|
| 1 | +/* |
| 2 | + * Copyright (C) 2012 Canonical Ltd. |
| 3 | + * Author: Robert Ancell <robert.ancell@canonical.com> |
| 4 | + * |
| 5 | + * This program is free software: you can redistribute it and/or modify it under |
| 6 | + * the terms of the GNU General Public License as published by the Free Software |
| 7 | + * Foundation, either version 3 of the License, or (at your option) any later |
| 8 | + * version. See http://www.gnu.org/copyleft/gpl.html the full text of the |
| 9 | + * license. |
| 10 | + */ |
| 11 | + |
| 12 | +public enum RFKillDeviceType { |
| 13 | + ALL = 0, |
| 14 | + WLAN, |
| 15 | + BLUETOOTH, |
| 16 | + UWB, |
| 17 | + WIMAX, |
| 18 | + WMAN |
| 19 | +} |
| 20 | + |
| 21 | +public class RFKillDevice { |
| 22 | + public signal void changed (); |
| 23 | + |
| 24 | + public bool software_lock { |
| 25 | + get { return _software_lock; } |
| 26 | + set { |
| 27 | + var event = RFKillEvent (); |
| 28 | + event.idx = idx; |
| 29 | + event.op = RFKillOperation.CHANGE; |
| 30 | + event.soft = value ? 1 : 0; |
| 31 | + if (Posix.write (manager.fd, &event, 8) != 8) |
| 32 | + return; |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + public bool hardware_lock { get { return _hardware_lock; } } |
| 37 | + |
| 38 | + public RFKillDeviceType device_type { get { return _device_type; } } |
| 39 | + |
| 40 | + internal RFKillManager manager; |
| 41 | + internal uint32 idx; |
| 42 | + internal RFKillDeviceType _device_type; |
| 43 | + internal bool _software_lock; |
| 44 | + internal bool _hardware_lock; |
| 45 | + |
| 46 | + internal RFKillDevice (RFKillManager manager, uint32 idx, RFKillDeviceType device_type, bool software_lock, bool hardware_lock) { |
| 47 | + this.manager = manager; |
| 48 | + this.idx = idx; |
| 49 | + _device_type = device_type; |
| 50 | + _software_lock = software_lock; |
| 51 | + _hardware_lock = hardware_lock; |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +public class RFKillManager : Object { |
| 56 | + public signal void device_added (RFKillDevice device); |
| 57 | + public signal void device_changed (RFKillDevice device); |
| 58 | + public signal void device_deleted (RFKillDevice device); |
| 59 | + |
| 60 | + public RFKillManager () { |
| 61 | + _devices = new List<RFKillDevice> (); |
| 62 | + } |
| 63 | + |
| 64 | + public void open () { |
| 65 | + fd = Posix.open ("/dev/rfkill", Posix.O_RDWR); |
| 66 | + Posix.fcntl (fd, Posix.F_SETFL, Posix.O_NONBLOCK); |
| 67 | + |
| 68 | + /* Read initial state */ |
| 69 | + while (read_event ()); |
| 70 | + |
| 71 | + /* Monitor for events */ |
| 72 | + var channel = new IOChannel.unix_new (fd); |
| 73 | + channel.add_watch (IOCondition.IN | IOCondition.HUP | IOCondition.ERR, () => { return read_event (); }); |
| 74 | + } |
| 75 | + |
| 76 | + public List<RFKillDevice> get_devices () { |
| 77 | + var devices = new List<RFKillDevice> (); |
| 78 | + foreach (var device in _devices) |
| 79 | + devices.append (device); |
| 80 | + return devices; |
| 81 | + } |
| 82 | + |
| 83 | + public void set_software_lock (RFKillDeviceType type, bool lock_enabled) { |
| 84 | + var event = RFKillEvent (); |
| 85 | + event.type = type; |
| 86 | + event.op = RFKillOperation.CHANGE_ALL; |
| 87 | + event.soft = lock_enabled ? 1 : 0; |
| 88 | + if (Posix.write (fd, &event, 8) != 8) |
| 89 | + return; |
| 90 | + } |
| 91 | + |
| 92 | + internal int fd = -1; |
| 93 | + private List<RFKillDevice> _devices; |
| 94 | + |
| 95 | + private bool read_event () { |
| 96 | + var event = RFKillEvent (); |
| 97 | + if (Posix.read (fd, &event, 8) != 8) |
| 98 | + return false; |
| 99 | + |
| 100 | + switch (event.op) { |
| 101 | + case RFKillOperation.ADD: |
| 102 | + var device = new RFKillDevice (this, event.idx, (RFKillDeviceType) event.type, event.soft != 0, event.hard != 0); |
| 103 | + _devices.append (device); |
| 104 | + device_added (device); |
| 105 | + break; |
| 106 | + case RFKillOperation.DELETE: |
| 107 | + var device = get_device (event.idx); |
| 108 | + if (device != null) { |
| 109 | + _devices.remove (device); |
| 110 | + device_deleted (device); |
| 111 | + } |
| 112 | + break; |
| 113 | + case RFKillOperation.CHANGE: |
| 114 | + var device = get_device (event.idx); |
| 115 | + if (device != null) { |
| 116 | + device._software_lock = event.soft != 0; |
| 117 | + device._hardware_lock = event.hard != 0; |
| 118 | + device.changed (); |
| 119 | + device_changed (device); |
| 120 | + } |
| 121 | + break; |
| 122 | + } |
| 123 | + return true; |
| 124 | + } |
| 125 | + |
| 126 | + private RFKillDevice? get_device (uint32 idx) { |
| 127 | + foreach (var device in _devices) { |
| 128 | + if (device.idx == idx) |
| 129 | + return device; |
| 130 | + } |
| 131 | + |
| 132 | + return null; |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +private struct RFKillEvent { |
| 137 | + uint32 idx; |
| 138 | + uint8 type; |
| 139 | + uint8 op; |
| 140 | + uint8 soft; |
| 141 | + uint8 hard; |
| 142 | +} |
| 143 | + |
| 144 | +private enum RFKillOperation { |
| 145 | + ADD = 0, |
| 146 | + DELETE, |
| 147 | + CHANGE, |
| 148 | + CHANGE_ALL |
| 149 | +} |
0 commit comments