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