1 /* $OpenBSD: uow.c,v 1.33 2013/04/15 09:23:02 mglocker Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Alexander Yurchenko <grange@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 DISCLAIMS 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 /* 20 * Maxim/Dallas DS2490 USB 1-Wire adapter driver. 21 */ 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/device.h> 26 #include <sys/kernel.h> 27 28 #include <dev/onewire/onewirereg.h> 29 #include <dev/onewire/onewirevar.h> 30 31 #include <dev/usb/usb.h> 32 #include <dev/usb/usbdevs.h> 33 #include <dev/usb/usbdi.h> 34 #include <dev/usb/usbdi_util.h> 35 36 #include <dev/usb/uowreg.h> 37 38 #define UOW_TIMEOUT 1000 /* ms */ 39 40 struct uow_softc { 41 struct device sc_dev; 42 43 struct onewire_bus sc_ow_bus; 44 struct device *sc_ow_dev; 45 46 struct usbd_device *sc_udev; 47 struct usbd_interface *sc_iface; 48 struct usbd_pipe *sc_ph_ibulk; 49 struct usbd_pipe *sc_ph_obulk; 50 struct usbd_pipe *sc_ph_intr; 51 u_int8_t sc_regs[DS2490_NREGS]; 52 struct usbd_xfer *sc_xfer; 53 u_int8_t sc_fifo[DS2490_DATAFIFOSIZE]; 54 }; 55 56 int uow_match(struct device *, void *, void *); 57 void uow_attach(struct device *, struct device *, void *); 58 int uow_detach(struct device *, int); 59 int uow_activate(struct device *, int); 60 61 struct cfdriver uow_cd = { 62 NULL, "uow", DV_DULL 63 }; 64 65 const struct cfattach uow_ca = { 66 sizeof(struct uow_softc), 67 uow_match, 68 uow_attach, 69 uow_detach, 70 uow_activate, 71 }; 72 73 /* List of supported devices */ 74 static const struct usb_devno uow_devs[] = { 75 { USB_VENDOR_DALLAS, USB_PRODUCT_DALLAS_USB_FOB_IBUTTON } 76 }; 77 78 int uow_ow_reset(void *); 79 int uow_ow_bit(void *, int); 80 int uow_ow_read_byte(void *); 81 void uow_ow_write_byte(void *, int); 82 void uow_ow_read_block(void *, void *, int); 83 void uow_ow_write_block(void *, const void *, int); 84 void uow_ow_matchrom(void *, u_int64_t); 85 int uow_ow_search(void *, u_int64_t *, int, u_int64_t); 86 87 int uow_cmd(struct uow_softc *, int, int, int); 88 #define uow_ctlcmd(s, c, p) uow_cmd((s), DS2490_CONTROL_CMD, (c), (p)) 89 #define uow_commcmd(s, c, p) uow_cmd((s), DS2490_COMM_CMD, (c), (p)) 90 #define uow_modecmd(s, c, p) uow_cmd((s), DS2490_MODE_CMD, (c), (p)) 91 92 void uow_intr(struct usbd_xfer *, void *, usbd_status); 93 int uow_read(struct uow_softc *, void *, int); 94 int uow_write(struct uow_softc *, const void *, int); 95 int uow_reset(struct uow_softc *); 96 97 int 98 uow_match(struct device *parent, void *match, void *aux) 99 { 100 struct usb_attach_arg *uaa = aux; 101 102 if (uaa->iface != NULL) 103 return (UMATCH_NONE); 104 105 return ((usb_lookup(uow_devs, uaa->vendor, uaa->product) != NULL) ? 106 UMATCH_VENDOR_PRODUCT : UMATCH_NONE); 107 } 108 109 void 110 uow_attach(struct device *parent, struct device *self, void *aux) 111 { 112 struct uow_softc *sc = (struct uow_softc *)self; 113 struct usb_attach_arg *uaa = aux; 114 usb_interface_descriptor_t *id; 115 usb_endpoint_descriptor_t *ed; 116 int ep_ibulk = -1, ep_obulk = -1, ep_intr = -1; 117 struct onewirebus_attach_args oba; 118 usbd_status error; 119 int i; 120 121 sc->sc_udev = uaa->device; 122 123 /* Set USB configuration */ 124 if ((error = usbd_set_config_no(sc->sc_udev, 125 DS2490_USB_CONFIG, 0)) != 0) { 126 printf("%s: failed to set config %d: %s\n", 127 sc->sc_dev.dv_xname, DS2490_USB_CONFIG, 128 usbd_errstr(error)); 129 return; 130 } 131 132 /* Get interface handle */ 133 if ((error = usbd_device2interface_handle(sc->sc_udev, 134 DS2490_USB_IFACE, &sc->sc_iface)) != 0) { 135 printf("%s: failed to get iface %d: %s\n", 136 sc->sc_dev.dv_xname, DS2490_USB_IFACE, 137 usbd_errstr(error)); 138 return; 139 } 140 141 /* Find endpoints */ 142 id = usbd_get_interface_descriptor(sc->sc_iface); 143 for (i = 0; i < id->bNumEndpoints; i++) { 144 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); 145 if (ed == NULL) { 146 printf("%s: failed to get endpoint %d descriptor\n", 147 sc->sc_dev.dv_xname, i); 148 return; 149 } 150 151 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 152 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 153 ep_ibulk = ed->bEndpointAddress; 154 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 155 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) 156 ep_obulk = ed->bEndpointAddress; 157 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 158 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) 159 ep_intr = ed->bEndpointAddress; 160 } 161 if (ep_ibulk == -1 || ep_obulk == -1 || ep_intr == -1) { 162 printf("%s: missing endpoint: ibulk %d, obulk %d, intr %d\n", 163 sc->sc_dev.dv_xname, ep_ibulk, ep_obulk, ep_intr); 164 return; 165 } 166 167 /* Open pipes */ 168 if ((error = usbd_open_pipe(sc->sc_iface, ep_ibulk, USBD_EXCLUSIVE_USE, 169 &sc->sc_ph_ibulk)) != 0) { 170 printf("%s: failed to open bulk-in pipe: %s\n", 171 sc->sc_dev.dv_xname, usbd_errstr(error)); 172 return; 173 } 174 if ((error = usbd_open_pipe(sc->sc_iface, ep_obulk, USBD_EXCLUSIVE_USE, 175 &sc->sc_ph_obulk)) != 0) { 176 printf("%s: failed to open bulk-out pipe: %s\n", 177 sc->sc_dev.dv_xname, usbd_errstr(error)); 178 goto fail; 179 } 180 if ((error = usbd_open_pipe_intr(sc->sc_iface, ep_intr, 181 USBD_SHORT_XFER_OK, &sc->sc_ph_intr, sc, 182 sc->sc_regs, sizeof(sc->sc_regs), uow_intr, 183 USBD_DEFAULT_INTERVAL)) != 0) { 184 printf("%s: failed to open intr pipe: %s\n", 185 sc->sc_dev.dv_xname, usbd_errstr(error)); 186 goto fail; 187 } 188 189 #if 0 190 /* Allocate xfer for bulk transfers */ 191 if ((sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) { 192 printf("%s: failed to alloc bulk xfer\n", 193 sc->sc_dev.dv_xname); 194 goto fail; 195 } 196 #endif 197 198 memset(sc->sc_fifo, 0xff, sizeof(sc->sc_fifo)); 199 200 /* Reset device */ 201 uow_reset(sc); 202 203 /* Attach 1-Wire bus */ 204 sc->sc_ow_bus.bus_cookie = sc; 205 sc->sc_ow_bus.bus_reset = uow_ow_reset; 206 sc->sc_ow_bus.bus_bit = uow_ow_bit; 207 sc->sc_ow_bus.bus_read_byte = uow_ow_read_byte; 208 sc->sc_ow_bus.bus_write_byte = uow_ow_write_byte; 209 sc->sc_ow_bus.bus_read_block = uow_ow_read_block; 210 sc->sc_ow_bus.bus_write_block = uow_ow_write_block; 211 sc->sc_ow_bus.bus_matchrom = uow_ow_matchrom; 212 #if 0 213 sc->sc_ow_bus.bus_search = uow_ow_search; 214 #endif 215 216 bzero(&oba, sizeof(oba)); 217 oba.oba_bus = &sc->sc_ow_bus; 218 sc->sc_ow_dev = config_found(self, &oba, onewirebus_print); 219 220 return; 221 222 fail: 223 if (sc->sc_ph_ibulk != NULL) 224 usbd_close_pipe(sc->sc_ph_ibulk); 225 if (sc->sc_ph_obulk != NULL) 226 usbd_close_pipe(sc->sc_ph_obulk); 227 if (sc->sc_ph_intr != NULL) 228 usbd_close_pipe(sc->sc_ph_intr); 229 if (sc->sc_xfer != NULL) 230 usbd_free_xfer(sc->sc_xfer); 231 } 232 233 int 234 uow_detach(struct device *self, int flags) 235 { 236 struct uow_softc *sc = (struct uow_softc *)self; 237 int rv = 0, s; 238 239 s = splusb(); 240 241 if (sc->sc_ph_ibulk != NULL) { 242 usbd_abort_pipe(sc->sc_ph_ibulk); 243 usbd_close_pipe(sc->sc_ph_ibulk); 244 } 245 if (sc->sc_ph_obulk != NULL) { 246 usbd_abort_pipe(sc->sc_ph_obulk); 247 usbd_close_pipe(sc->sc_ph_obulk); 248 } 249 if (sc->sc_ph_intr != NULL) { 250 usbd_abort_pipe(sc->sc_ph_intr); 251 usbd_close_pipe(sc->sc_ph_intr); 252 } 253 254 if (sc->sc_xfer != NULL) 255 usbd_free_xfer(sc->sc_xfer); 256 257 if (sc->sc_ow_dev != NULL) 258 rv = config_detach(sc->sc_ow_dev, flags); 259 260 splx(s); 261 262 return (rv); 263 } 264 265 int 266 uow_activate(struct device *self, int act) 267 { 268 struct uow_softc *sc = (struct uow_softc *)self; 269 int rv = 0; 270 271 switch (act) { 272 case DVACT_DEACTIVATE: 273 if (sc->sc_ow_dev != NULL) 274 rv = config_deactivate(sc->sc_ow_dev); 275 usbd_deactivate(sc->sc_udev); 276 break; 277 } 278 279 return (rv); 280 } 281 282 int 283 uow_ow_reset(void *arg) 284 { 285 struct uow_softc *sc = arg; 286 287 if (uow_commcmd(sc, DS2490_COMM_1WIRE_RESET | DS2490_BIT_IM, 0) != 0) 288 return (1); 289 290 /* XXX: check presence pulse */ 291 return (0); 292 } 293 294 int 295 uow_ow_bit(void *arg, int value) 296 { 297 struct uow_softc *sc = arg; 298 u_int8_t data; 299 300 if (uow_commcmd(sc, DS2490_COMM_BIT_IO | DS2490_BIT_IM | 301 (value ? DS2490_BIT_D : 0), 0) != 0) 302 return (1); 303 if (uow_read(sc, &data, 1) != 1) 304 return (1); 305 306 return (data); 307 } 308 309 int 310 uow_ow_read_byte(void *arg) 311 { 312 struct uow_softc *sc = arg; 313 u_int8_t data; 314 315 if (uow_commcmd(sc, DS2490_COMM_BYTE_IO | DS2490_BIT_IM, 0xff) != 0) 316 return (-1); 317 if (uow_read(sc, &data, 1) != 1) 318 return (-1); 319 320 return (data); 321 } 322 323 void 324 uow_ow_write_byte(void *arg, int value) 325 { 326 struct uow_softc *sc = arg; 327 u_int8_t data; 328 329 if (uow_commcmd(sc, DS2490_COMM_BYTE_IO | DS2490_BIT_IM, value) != 0) 330 return; 331 uow_read(sc, &data, sizeof(data)); 332 } 333 334 void 335 uow_ow_read_block(void *arg, void *buf, int len) 336 { 337 struct uow_softc *sc = arg; 338 339 if (uow_write(sc, sc->sc_fifo, len) != 0) 340 return; 341 if (uow_commcmd(sc, DS2490_COMM_BLOCK_IO | DS2490_BIT_IM, len) != 0) 342 return; 343 uow_read(sc, buf, len); 344 } 345 346 void 347 uow_ow_write_block(void *arg, const void *buf, int len) 348 { 349 struct uow_softc *sc = arg; 350 351 if (uow_write(sc, buf, len) != 0) 352 return; 353 if (uow_commcmd(sc, DS2490_COMM_BLOCK_IO | DS2490_BIT_IM, len) != 0) 354 return; 355 } 356 357 void 358 uow_ow_matchrom(void *arg, u_int64_t rom) 359 { 360 struct uow_softc *sc = arg; 361 u_int8_t data[8]; 362 int i; 363 364 for (i = 0; i < 8; i++) 365 data[i] = (rom >> (i * 8)) & 0xff; 366 367 if (uow_write(sc, data, 8) != 0) 368 return; 369 if (uow_commcmd(sc, DS2490_COMM_MATCH_ACCESS | DS2490_BIT_IM, 370 ONEWIRE_CMD_MATCH_ROM) != 0) 371 return; 372 } 373 374 int 375 uow_ow_search(void *arg, u_int64_t *buf, int size, u_int64_t startrom) 376 { 377 struct uow_softc *sc = arg; 378 u_int8_t data[8]; 379 int i, rv; 380 381 for (i = 0; i < 8; i++) 382 data[i] = (startrom >> (i * 8)) & 0xff; 383 384 if (uow_write(sc, data, 8) != 0) 385 return (-1); 386 if (uow_commcmd(sc, DS2490_COMM_SEARCH_ACCESS | DS2490_BIT_IM | 387 DS2490_BIT_SM | DS2490_BIT_RST | DS2490_BIT_F, size << 8 | 388 ONEWIRE_CMD_SEARCH_ROM) != 0) 389 return (-1); 390 391 if ((rv = uow_read(sc, buf, size * 8)) == -1) 392 return (-1); 393 394 return (rv / 8); 395 } 396 397 int 398 uow_cmd(struct uow_softc *sc, int type, int cmd, int param) 399 { 400 usb_device_request_t req; 401 usbd_status error; 402 403 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 404 req.bRequest = type; 405 USETW(req.wValue, cmd); 406 USETW(req.wIndex, param); 407 USETW(req.wLength, 0); 408 if ((error = usbd_do_request(sc->sc_udev, &req, NULL)) != 0) { 409 printf("%s: cmd failed, type 0x%02x, cmd 0x%04x, " 410 "param 0x%04x: %s\n", sc->sc_dev.dv_xname, type, cmd, 411 param, usbd_errstr(error)); 412 if (cmd != DS2490_CTL_RESET_DEVICE) 413 uow_reset(sc); 414 return (1); 415 } 416 417 again: 418 if (tsleep(sc->sc_regs, PRIBIO, "uowcmd", 419 (UOW_TIMEOUT * hz) / 1000) != 0) { 420 printf("%s: cmd timeout, type 0x%02x, cmd 0x%04x, " 421 "param 0x%04x\n", sc->sc_dev.dv_xname, type, cmd, 422 param); 423 return (1); 424 } 425 if ((sc->sc_regs[DS2490_ST_STFL] & DS2490_ST_STFL_IDLE) == 0) 426 goto again; 427 428 return (0); 429 } 430 431 void 432 uow_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 433 { 434 struct uow_softc *sc = priv; 435 436 if (status != USBD_NORMAL_COMPLETION) { 437 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 438 return; 439 if (status == USBD_STALLED) 440 usbd_clear_endpoint_stall_async(sc->sc_ph_intr); 441 return; 442 } 443 444 wakeup(sc->sc_regs); 445 } 446 447 int 448 uow_read(struct uow_softc *sc, void *buf, int len) 449 { 450 usbd_status error; 451 int count; 452 453 /* XXX: implement FIFO status monitoring */ 454 if (len > DS2490_DATAFIFOSIZE) { 455 printf("%s: read %d bytes, xfer too big\n", 456 sc->sc_dev.dv_xname, len); 457 return (-1); 458 } 459 460 if ((sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) { 461 printf("%s: failed to alloc xfer\n", sc->sc_dev.dv_xname); 462 return (-1); 463 } 464 usbd_setup_xfer(sc->sc_xfer, sc->sc_ph_ibulk, sc, buf, len, 465 USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS, UOW_TIMEOUT, NULL); 466 error = usbd_transfer(sc->sc_xfer); 467 usbd_free_xfer(sc->sc_xfer); 468 if (error != 0) { 469 printf("%s: read failed, len %d: %s\n", 470 sc->sc_dev.dv_xname, len, usbd_errstr(error)); 471 uow_reset(sc); 472 return (-1); 473 } 474 475 usbd_get_xfer_status(sc->sc_xfer, NULL, NULL, &count, &error); 476 return (count); 477 } 478 479 int 480 uow_write(struct uow_softc *sc, const void *buf, int len) 481 { 482 usbd_status error; 483 484 /* XXX: implement FIFO status monitoring */ 485 if (len > DS2490_DATAFIFOSIZE) { 486 printf("%s: write %d bytes, xfer too big\n", 487 sc->sc_dev.dv_xname, len); 488 return (1); 489 } 490 491 if ((sc->sc_xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL) { 492 printf("%s: failed to alloc xfer\n", sc->sc_dev.dv_xname); 493 return (-1); 494 } 495 usbd_setup_xfer(sc->sc_xfer, sc->sc_ph_obulk, sc, (void *)buf, len, 496 USBD_SYNCHRONOUS, UOW_TIMEOUT, NULL); 497 error = usbd_transfer(sc->sc_xfer); 498 usbd_free_xfer(sc->sc_xfer); 499 if (error != 0) { 500 printf("%s: write failed, len %d: %s\n", 501 sc->sc_dev.dv_xname, len, usbd_errstr(error)); 502 uow_reset(sc); 503 return (1); 504 } 505 506 return (0); 507 } 508 509 int 510 uow_reset(struct uow_softc *sc) 511 { 512 return (uow_ctlcmd(sc, DS2490_CTL_RESET_DEVICE, 0)); 513 } 514