1 /* $OpenBSD: upd.c,v 1.5 2014/03/20 13:07:01 andre Exp $ */ 2 3 /* 4 * Copyright (c) 2014 Andre de Oliveira <andre@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* Driver for USB Power Devices sensors */ 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/kernel.h> 24 #include <sys/malloc.h> 25 #include <sys/device.h> 26 #include <sys/sensors.h> 27 28 #include <dev/usb/hid.h> 29 #include <dev/usb/usb.h> 30 #include <dev/usb/usbdi.h> 31 #include <dev/usb/usbdevs.h> 32 #include <dev/usb/usbhid.h> 33 #include <dev/usb/uhidev.h> 34 #include <dev/usb/usbdi_util.h> 35 36 #ifdef UPD_DEBUG 37 #define DPRINTF(x) do { printf x; } while (0) 38 #else 39 #define DPRINTF(x) 40 #endif 41 42 enum upd_sensor_id { 43 UPD_SENSOR_UNKNOWN, 44 UPD_SENSOR_RELCHARGE, 45 UPD_SENSOR_ABSCHARGE, 46 UPD_SENSOR_REMCAPACI, 47 UPD_SENSOR_FULLCHARG, 48 UPD_SENSOR_CHARGING, 49 UPD_SENSOR_DISCHARG, 50 UPD_SENSOR_BATTPRESENT, 51 UPD_SENSOR_SHUTIMMINENT, 52 UPD_SENSOR_ACPRESENT, 53 UPD_SENSOR_TIMETOFULL, 54 UPD_SENSOR_NUM 55 /* 56 * TODO 57 * - atratetimetofull 58 * - atratetimetoempty 59 * - cyclecount 60 */ 61 }; 62 63 struct upd_usage_entry { 64 enum upd_sensor_id upd_sid; 65 uint8_t usage_pg; 66 uint8_t usage_id; 67 enum sensor_type senstype; 68 char *usage_name; /* sensor string */ 69 }; 70 71 static struct upd_usage_entry upd_usage_table[UPD_SENSOR_NUM] = { 72 { UPD_SENSOR_UNKNOWN, HUP_UNDEFINED,HUP_UNDEFINED, 73 -1, "unknown" }, 74 { UPD_SENSOR_RELCHARGE, HUP_BATTERY, HUB_REL_STATEOF_CHARGE, 75 SENSOR_PERCENT, "RelativeStateOfCharge" }, 76 { UPD_SENSOR_ABSCHARGE, HUP_BATTERY, HUB_ABS_STATEOF_CHARGE, 77 SENSOR_PERCENT, "AbsoluteStateOfCharge" }, 78 { UPD_SENSOR_REMCAPACI, HUP_BATTERY, HUB_REM_CAPACITY, 79 SENSOR_PERCENT, "RemainingCapacity" }, 80 { UPD_SENSOR_FULLCHARG, HUP_BATTERY, HUB_FULLCHARGE_CAPACITY, 81 SENSOR_PERCENT, "FullChargeCapacity" }, 82 { UPD_SENSOR_CHARGING, HUP_BATTERY, HUB_CHARGING, 83 SENSOR_INDICATOR, "Charging" }, 84 { UPD_SENSOR_DISCHARG, HUP_BATTERY, HUB_DISCHARGING, 85 SENSOR_INDICATOR, "Discharging" }, 86 { UPD_SENSOR_BATTPRESENT, HUP_BATTERY, HUB_BATTERY_PRESENT, 87 SENSOR_INDICATOR, "BatteryPresent" }, 88 { UPD_SENSOR_SHUTIMMINENT,HUP_POWER, HUP_SHUTDOWN_IMMINENT, 89 SENSOR_INDICATOR, "ShutdownImminent" }, 90 { UPD_SENSOR_ACPRESENT, HUP_BATTERY, HUB_AC_PRESENT, 91 SENSOR_INDICATOR, "ACPresent" }, 92 { UPD_SENSOR_TIMETOFULL, HUP_BATTERY, HUB_ATRATE_TIMETOFULL, 93 SENSOR_TIMEDELTA, "AtRateTimeToFull" } 94 }; 95 96 struct upd_sensor { 97 int attached; 98 struct ksensor sensor; 99 struct hid_item item; 100 size_t flen; 101 }; 102 103 struct upd_softc { 104 struct uhidev sc_hdev; 105 int sc_num_sensors; 106 107 /* sensor framework */ 108 struct upd_sensor sc_sensors[UPD_SENSOR_NUM]; 109 struct ksensordev sc_sensordev; 110 struct sensor_task *sc_sensortask; 111 }; 112 113 static const struct usb_devno upd_devs[] = { 114 { USB_VENDOR_APC, USB_PRODUCT_APC_UPS }, 115 { USB_VENDOR_APC, USB_PRODUCT_APC_UPS5G }, 116 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C100 }, 117 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C1100 }, 118 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C120 }, 119 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C1250EITWRK }, 120 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C1500EITWRK }, 121 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C550AVR }, 122 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C800 }, 123 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6C900 }, 124 { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F6H375 }, 125 { USB_VENDOR_CYBERPOWER, USB_PRODUCT_CYBERPOWER_1500 }, 126 { USB_VENDOR_CYBERPOWER, USB_PRODUCT_CYBERPOWER_OR2200 }, 127 { USB_VENDOR_CYBERPOWER, USB_PRODUCT_CYBERPOWER_UPS }, 128 { USB_VENDOR_DELL2, USB_PRODUCT_DELL2_UPS }, 129 { USB_VENDOR_HP, USB_PRODUCT_HP_R1500G2 }, 130 { USB_VENDOR_HP, USB_PRODUCT_HP_RT2200 }, 131 { USB_VENDOR_HP, USB_PRODUCT_HP_T1000 }, 132 { USB_VENDOR_HP, USB_PRODUCT_HP_T1500 }, 133 { USB_VENDOR_HP, USB_PRODUCT_HP_T750 }, 134 { USB_VENDOR_HP, USB_PRODUCT_HP_T750G2 }, 135 { USB_VENDOR_IDOWELL, USB_PRODUCT_IDOWELL_IDOWELL }, 136 { USB_VENDOR_LIEBERT, USB_PRODUCT_LIEBERT_UPS }, 137 { USB_VENDOR_LIEBERT2, USB_PRODUCT_LIEBERT2_PSA }, 138 { USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS1 }, 139 { USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS2 }, 140 { USB_VENDOR_OMRON, USB_PRODUCT_OMRON_BX35F }, 141 { USB_VENDOR_OMRON, USB_PRODUCT_OMRON_BX50F }, 142 { USB_VENDOR_OMRON, USB_PRODUCT_OMRON_BY35S } 143 }; 144 #define upd_lookup(v, p) usb_lookup(upd_devs, v, p) 145 146 int upd_match(struct device *, void *, void *); 147 void upd_attach(struct device *, struct device *, void *); 148 int upd_detach(struct device *, int); 149 150 void upd_add_sensor(struct upd_softc *, const struct hid_item *, void *, int); 151 void upd_refresh(void *); 152 void upd_intr(struct uhidev *, void *, uint); 153 154 struct cfdriver upd_cd = { 155 NULL, "upd", DV_DULL 156 }; 157 158 const struct cfattach upd_ca = { 159 sizeof(struct upd_softc), 160 upd_match, 161 upd_attach, 162 upd_detach 163 }; 164 165 int 166 upd_match(struct device *parent, void *match, void *aux) 167 { 168 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 169 170 if (uha->reportid != UHIDEV_CLAIM_ALLREPORTID) 171 return (UMATCH_NONE); 172 173 if (upd_lookup(uha->uaa->vendor, uha->uaa->product) == NULL) 174 return (UMATCH_NONE); 175 176 DPRINTF(("upd: vendor=0x%x, product=0x%x\n", uha->uaa->vendor, 177 uha->uaa->product)); 178 179 return (UMATCH_VENDOR_PRODUCT); 180 } 181 182 void 183 upd_attach(struct device *parent, struct device *self, void *aux) 184 { 185 struct upd_softc *sc = (struct upd_softc *)self; 186 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 187 struct hid_item item; 188 struct hid_data *hdata; 189 int size; 190 void *desc; 191 192 sc->sc_hdev.sc_intr = upd_intr; 193 sc->sc_hdev.sc_parent = uha->parent; 194 sc->sc_num_sensors = 0; 195 196 strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname, 197 sizeof(sc->sc_sensordev.xname)); 198 199 DPRINTF(("upd: devname=%s sc_nrepid=%d\n", sc->sc_hdev.sc_dev.dv_xname, 200 uha->parent->sc_nrepid)); 201 202 uhidev_get_report_desc(uha->parent, &desc, &size); 203 hdata = hid_start_parse(desc, size, hid_feature); 204 /* lookup for item in our sensors list */ 205 while (hid_get_item(hdata, &item)) 206 upd_add_sensor(sc, &item, desc, size); 207 208 hid_end_parse(hdata); 209 DPRINTF(("upd: sc_num_sensors=%d\n", sc->sc_num_sensors)); 210 211 if (sc->sc_num_sensors > 0) { 212 sc->sc_sensortask = sensor_task_register(sc, upd_refresh, 6); 213 if (sc->sc_sensortask == NULL) { 214 printf(", unable to register update task\n"); 215 return; 216 } 217 sensordev_install(&sc->sc_sensordev); 218 } 219 220 printf("\n"); 221 222 DPRINTF(("upd_attach: complete\n")); 223 } 224 225 int 226 upd_detach(struct device *self, int flags) 227 { 228 struct upd_softc *sc = (struct upd_softc *)self; 229 struct upd_sensor *sensor; 230 int i; 231 232 if (sc->sc_num_sensors <= 0) 233 goto finish; 234 235 if (sc->sc_sensortask != NULL) { 236 wakeup(&sc->sc_sensortask); 237 sensor_task_unregister(sc->sc_sensortask); 238 } 239 240 sensordev_deinstall(&sc->sc_sensordev); 241 242 for (i = 0; i < UPD_SENSOR_NUM; i++) { 243 sensor = &sc->sc_sensors[i]; 244 if (!sensor->attached) 245 continue; 246 247 sensor_detach(&sc->sc_sensordev, &sensor->sensor); 248 DPRINTF(("upd_detach: %s\n", sensor->sensor.desc)); 249 } 250 251 finish: 252 DPRINTF(("upd_detach: complete\n")); 253 return (0); 254 } 255 256 void 257 upd_refresh(void *arg) 258 { 259 struct upd_softc *sc = (struct upd_softc *)arg; 260 struct hid_location *loc; 261 struct upd_sensor *sensor; 262 ulong hdata; 263 ulong adjust; 264 uint8_t buf[256]; 265 int i, err; 266 267 for (i = 0; i < UPD_SENSOR_NUM; i++) { 268 sensor = &sc->sc_sensors[i]; 269 if (sensor && !sensor->attached) 270 continue; 271 272 switch (i) { 273 case UPD_SENSOR_RELCHARGE: 274 case UPD_SENSOR_ABSCHARGE: 275 case UPD_SENSOR_REMCAPACI: 276 case UPD_SENSOR_FULLCHARG: 277 adjust = 1000; /* scale adjust */ 278 /* FALLTHROUGH */ 279 case UPD_SENSOR_CHARGING: 280 case UPD_SENSOR_DISCHARG: 281 case UPD_SENSOR_TIMETOFULL: 282 /* 283 * don't query nor show battery dependent sensors if no 284 * battery 285 */ 286 if (sc->sc_sensors[UPD_SENSOR_BATTPRESENT].sensor.value 287 <= 0) { 288 sensor->sensor.flags |= SENSOR_FINVALID; 289 continue; 290 } 291 break; 292 default: 293 adjust = 1; /* no scale adjust */ 294 } 295 296 loc = &sensor->item.loc; 297 sc->sc_hdev.sc_report_id = sensor->item.report_ID; 298 memset(buf, 0x0, sizeof(buf)); 299 err = uhidev_get_report(&sc->sc_hdev, UHID_FEATURE_REPORT, buf, 300 sensor->flen); 301 if (err) { 302 DPRINTF(("read failure: sens=%02x reportid=%02x " 303 "err=%d\n", i, sc->sc_hdev.sc_report_id, err)); 304 continue; 305 } 306 307 hdata = hid_get_data(buf + 1, loc); 308 309 sensor->sensor.flags &= ~SENSOR_FINVALID; 310 sensor->sensor.value = hdata * adjust; 311 DPRINTF(("%s: %s: hidget data: %d\n", sc->sc_sensordev.xname, 312 upd_usage_table[i].usage_name, hdata)); 313 } 314 } 315 316 void 317 upd_add_sensor(struct upd_softc *sc, const struct hid_item *item, void *desc, 318 int dsiz) 319 { 320 struct upd_usage_entry *entry = NULL; 321 struct upd_sensor *sensor = NULL; 322 int i; 323 324 for (i = 0; i < UPD_SENSOR_NUM; i++) { 325 entry = &upd_usage_table[i]; 326 if (entry->upd_sid == UPD_SENSOR_UNKNOWN || 327 entry->usage_pg != HID_GET_USAGE_PAGE(item->usage) || 328 entry->usage_id != HID_GET_USAGE(item->usage)) 329 continue; 330 331 sensor = &sc->sc_sensors[i]; 332 if (sensor && sensor->attached) 333 continue; 334 335 /* keep our copy of hid_item */ 336 memset(&sensor->item, 0x0, sizeof(struct hid_item)); 337 memcpy(&sensor->item, item, sizeof(struct hid_item)); 338 sensor->flen = hid_report_size(desc, dsiz, hid_feature, 339 item->report_ID) + 1; 340 strlcpy(sensor->sensor.desc, entry->usage_name, 341 sizeof(sensor->sensor.desc)); 342 sensor->sensor.type = entry->senstype; 343 sensor->sensor.flags |= SENSOR_FINVALID; 344 sensor->sensor.value = 0; 345 sensor_attach(&sc->sc_sensordev, &sensor->sensor); 346 sensor->attached = 1; 347 sc->sc_num_sensors++; 348 } 349 } 350 351 void 352 upd_intr(struct uhidev *uh, void *p, uint len) 353 { 354 /* noop */ 355 } 356