Annotation of sys/dev/usb/uvisor.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: uvisor.c,v 1.35 2007/06/14 10:11:16 mbalmer Exp $ */
2: /* $NetBSD: uvisor.c,v 1.21 2003/08/03 21:59:26 nathanw Exp $ */
3:
4: /*
5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Lennart Augustsson (lennart@augustsson.net) at
10: * Carlstedt Research & Technology.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: /*
42: * Handspring Visor (Palmpilot compatible PDA) driver
43: */
44:
45: #include <sys/param.h>
46: #include <sys/systm.h>
47: #include <sys/kernel.h>
48: #include <sys/device.h>
49: #include <sys/conf.h>
50: #include <sys/tty.h>
51:
52: #include <dev/usb/usb.h>
53: #include <dev/usb/usbhid.h>
54:
55: #include <dev/usb/usbdi.h>
56: #include <dev/usb/usbdi_util.h>
57: #include <dev/usb/usbdevs.h>
58:
59: #include <dev/usb/ucomvar.h>
60:
61: #ifdef UVISOR_DEBUG
62: #define DPRINTF(x) if (uvisordebug) printf x
63: #define DPRINTFN(n,x) if (uvisordebug>(n)) printf x
64: int uvisordebug = 0;
65: #else
66: #define DPRINTF(x)
67: #define DPRINTFN(n,x)
68: #endif
69:
70: #define UVISOR_CONFIG_INDEX 0
71: #define UVISOR_IFACE_INDEX 0
72:
73: /* From the Linux driver */
74: /*
75: * UVISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
76: * are available to be transfered to the host for the specified endpoint.
77: * Currently this is not used, and always returns 0x0001
78: */
79: #define UVISOR_REQUEST_BYTES_AVAILABLE 0x01
80:
81: /*
82: * UVISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host
83: * is now closing the pipe. An empty packet is sent in response.
84: */
85: #define UVISOR_CLOSE_NOTIFICATION 0x02
86:
87: /*
88: * UVISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to
89: * get the endpoints used by the connection.
90: */
91: #define UVISOR_GET_CONNECTION_INFORMATION 0x03
92:
93:
94: /*
95: * UVISOR_GET_CONNECTION_INFORMATION returns data in the following format
96: */
97: #define UVISOR_MAX_CONN 8
98: struct uvisor_connection_info {
99: uWord num_ports;
100: struct {
101: uByte port_function_id;
102: uByte port;
103: } connections[UVISOR_MAX_CONN];
104: };
105: #define UVISOR_CONNECTION_INFO_SIZE 18
106:
107: /* struct uvisor_connection_info.connection[x].port_function_id defines: */
108: #define UVISOR_FUNCTION_GENERIC 0x00
109: #define UVISOR_FUNCTION_DEBUGGER 0x01
110: #define UVISOR_FUNCTION_HOTSYNC 0x02
111: #define UVISOR_FUNCTION_CONSOLE 0x03
112: #define UVISOR_FUNCTION_REMOTE_FILE_SYS 0x04
113:
114: /*
115: * Unknown PalmOS stuff.
116: */
117: #define UVISOR_GET_PALM_INFORMATION 0x04
118: #define UVISOR_GET_PALM_INFORMATION_LEN 0x44
119:
120: struct uvisor_palm_connection_info {
121: uByte num_ports;
122: uByte endpoint_numbers_different;
123: uWord reserved1;
124: struct {
125: uDWord port_function_id;
126: uByte port;
127: uByte end_point_info;
128: uWord reserved;
129: } connections[UVISOR_MAX_CONN];
130: };
131:
132: #define UVISORIBUFSIZE 64
133: #define UVISOROBUFSIZE 1024
134:
135: struct uvisor_softc {
136: struct device sc_dev; /* base device */
137: usbd_device_handle sc_udev; /* device */
138: usbd_interface_handle sc_iface; /* interface */
139: /*
140: * added sc_vendor for later interrogation in failed initialisations
141: */
142: int sc_vendor; /* USB device vendor */
143:
144: struct device *sc_subdevs[UVISOR_MAX_CONN];
145: int sc_numcon;
146:
147: u_int16_t sc_flags;
148:
149: u_char sc_dying;
150: };
151:
152: usbd_status uvisor_init(struct uvisor_softc *,
153: struct uvisor_connection_info *,
154: struct uvisor_palm_connection_info *);
155:
156: void uvisor_close(void *, int);
157:
158:
159: struct ucom_methods uvisor_methods = {
160: NULL,
161: NULL,
162: NULL,
163: NULL,
164: NULL,
165: uvisor_close,
166: NULL,
167: NULL,
168: };
169:
170: struct uvisor_type {
171: struct usb_devno uv_dev;
172: u_int16_t uv_flags;
173: #define PALM4 0x0001
174: #define VISOR 0x0002
175: #define NOFRE 0x0004
176: #define CLIE4 (VISOR|NOFRE)
177: };
178: static const struct uvisor_type uvisor_devs[] = {
179: {{ USB_VENDOR_ACEECA, USB_PRODUCT_ACEECA_MEZ1000 }, PALM4 },
180: {{ USB_VENDOR_HANDSPRING, USB_PRODUCT_HANDSPRING_VISOR }, VISOR },
181: {{ USB_VENDOR_HANDSPRING, USB_PRODUCT_HANDSPRING_TREO }, PALM4 },
182: {{ USB_VENDOR_HANDSPRING, USB_PRODUCT_HANDSPRING_TREO600 }, VISOR },
183: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M500 }, PALM4 },
184: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M505 }, PALM4 },
185: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M515 }, PALM4 },
186: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_I705 }, PALM4 },
187: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M125 }, PALM4 },
188: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_M130 }, PALM4 },
189: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_TUNGSTEN_Z }, PALM4 },
190: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_TUNGSTEN_T }, PALM4 },
191: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_ZIRE }, PALM4 },
192: {{ USB_VENDOR_PALM, USB_PRODUCT_PALM_ZIRE_31 }, PALM4 },
193: {{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_40 }, PALM4 },
194: {{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_41 }, PALM4 },
195: {{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_S360 }, PALM4 },
196: {{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_NX60 }, PALM4 },
197: {{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_TJ25 }, PALM4 },
198: /* {{ USB_VENDOR_SONY, USB_PRODUCT_SONY_CLIE_25 }, PALM4 },*/
199: {{ USB_VENDOR_GARMIN, USB_PRODUCT_GARMIN_IQUE3600 }, PALM4 },
200: {{ USB_VENDOR_TAPWAVE, USB_PRODUCT_TAPWAVE_ZODIAC }, PALM4 },
201: };
202: #define uvisor_lookup(v, p) ((struct uvisor_type *)usb_lookup(uvisor_devs, v, p))
203:
204: int uvisor_match(struct device *, void *, void *);
205: void uvisor_attach(struct device *, struct device *, void *);
206: int uvisor_detach(struct device *, int);
207: int uvisor_activate(struct device *, enum devact);
208:
209: struct cfdriver uvisor_cd = {
210: NULL, "uvisor", DV_DULL
211: };
212:
213: const struct cfattach uvisor_ca = {
214: sizeof(struct uvisor_softc),
215: uvisor_match,
216: uvisor_attach,
217: uvisor_detach,
218: uvisor_activate,
219: };
220:
221: int
222: uvisor_match(struct device *parent, void *match, void *aux)
223: {
224: struct usb_attach_arg *uaa = aux;
225:
226: if (uaa->iface != NULL)
227: return (UMATCH_NONE);
228:
229: DPRINTFN(20,("uvisor: vendor=0x%x, product=0x%x\n",
230: uaa->vendor, uaa->product));
231:
232: return (uvisor_lookup(uaa->vendor, uaa->product) != NULL ?
233: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
234: }
235:
236: void
237: uvisor_attach(struct device *parent, struct device *self, void *aux)
238: {
239: struct uvisor_softc *sc = (struct uvisor_softc *)self;
240: struct usb_attach_arg *uaa = aux;
241: usbd_device_handle dev = uaa->device;
242: usbd_interface_handle iface;
243: usb_interface_descriptor_t *id;
244: struct uvisor_connection_info coninfo;
245: struct uvisor_palm_connection_info palmconinfo;
246: usb_endpoint_descriptor_t *ed;
247: char *devinfop;
248: char *devname = sc->sc_dev.dv_xname;
249: int i, j, hasin, hasout, port;
250: usbd_status err;
251: struct ucom_attach_args uca;
252:
253: DPRINTFN(10,("\nuvisor_attach: sc=%p\n", sc));
254:
255: /* Move the device into the configured state. */
256: err = usbd_set_config_index(dev, UVISOR_CONFIG_INDEX, 1);
257: if (err) {
258: printf("\n%s: failed to set configuration, err=%s\n",
259: devname, usbd_errstr(err));
260: goto bad;
261: }
262:
263: err = usbd_device2interface_handle(dev, UVISOR_IFACE_INDEX, &iface);
264: if (err) {
265: printf("\n%s: failed to get interface, err=%s\n",
266: devname, usbd_errstr(err));
267: goto bad;
268: }
269:
270: devinfop = usbd_devinfo_alloc(dev, 0);
271: printf("\n%s: %s\n", devname, devinfop);
272: usbd_devinfo_free(devinfop);
273:
274: sc->sc_flags = uvisor_lookup(uaa->vendor, uaa->product)->uv_flags;
275: sc->sc_vendor = uaa->vendor;
276:
277: if ((sc->sc_flags & (VISOR | PALM4)) == 0) {
278: printf("%s: device is neither visor nor palm\n",
279: sc->sc_dev.dv_xname);
280: goto bad;
281: }
282:
283: id = usbd_get_interface_descriptor(iface);
284:
285: sc->sc_udev = dev;
286: sc->sc_iface = iface;
287:
288: uca.ibufsize = UVISORIBUFSIZE;
289: uca.obufsize = UVISOROBUFSIZE;
290: uca.ibufsizepad = UVISORIBUFSIZE;
291: uca.opkthdrlen = 0;
292: uca.device = dev;
293: uca.iface = iface;
294: uca.methods = &uvisor_methods;
295: uca.arg = sc;
296:
297: err = uvisor_init(sc, &coninfo, &palmconinfo);
298: if (err) {
299: printf("%s: init failed, %s\n", sc->sc_dev.dv_xname,
300: usbd_errstr(err));
301: goto bad;
302: }
303:
304: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
305: &sc->sc_dev);
306:
307: if (sc->sc_flags & VISOR) {
308: sc->sc_numcon = UGETW(coninfo.num_ports);
309: if (sc->sc_numcon > UVISOR_MAX_CONN)
310: sc->sc_numcon = UVISOR_MAX_CONN;
311:
312: /* Attach a ucom for each connection. */
313: for (i = 0; i < sc->sc_numcon; ++i) {
314: switch (coninfo.connections[i].port_function_id) {
315: case UVISOR_FUNCTION_GENERIC:
316: uca.info = "Generic";
317: break;
318: case UVISOR_FUNCTION_DEBUGGER:
319: uca.info = "Debugger";
320: break;
321: case UVISOR_FUNCTION_HOTSYNC:
322: uca.info = "HotSync";
323: break;
324: case UVISOR_FUNCTION_REMOTE_FILE_SYS:
325: uca.info = "Remote File System";
326: break;
327: default:
328: uca.info = "unknown";
329: break;
330: }
331: port = coninfo.connections[i].port;
332: uca.portno = port;
333: uca.bulkin = port | UE_DIR_IN;
334: uca.bulkout = port | UE_DIR_OUT;
335: /* Verify that endpoints exist. */
336: hasin = 0;
337: hasout = 0;
338: for (j = 0; j < id->bNumEndpoints; j++) {
339: ed = usbd_interface2endpoint_descriptor(iface, j);
340: if (ed == NULL)
341: break;
342: if (UE_GET_ADDR(ed->bEndpointAddress) == port &&
343: (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
344: if (UE_GET_DIR(ed->bEndpointAddress)
345: == UE_DIR_IN)
346: hasin++;
347: else
348: hasout++;
349: }
350: }
351: if (hasin == 1 && hasout == 1)
352: sc->sc_subdevs[i] = config_found_sm(self, &uca,
353: ucomprint, ucomsubmatch);
354: else
355: printf("%s: no proper endpoints for port %d (%d,%d)\n",
356: sc->sc_dev.dv_xname, port, hasin, hasout);
357: }
358: } else {
359: sc->sc_numcon = palmconinfo.num_ports;
360: if (sc->sc_numcon > UVISOR_MAX_CONN)
361: sc->sc_numcon = UVISOR_MAX_CONN;
362:
363: /* Attach a ucom for each connection. */
364: for (i = 0; i < sc->sc_numcon; ++i) {
365: /*
366: * XXX this should copy out 4-char string from the
367: * XXX port_function_id, but where would the string go?
368: * XXX uca.info is a const char *, not an array.
369: */
370: uca.info = "sync";
371: uca.portno = i;
372: if (palmconinfo.endpoint_numbers_different) {
373: port = palmconinfo.connections[i].end_point_info;
374: uca.bulkin = (port >> 4) | UE_DIR_IN;
375: uca.bulkout = (port & 0xf) | UE_DIR_OUT;
376: } else {
377: port = palmconinfo.connections[i].port;
378: uca.bulkin = port | UE_DIR_IN;
379: uca.bulkout = port | UE_DIR_OUT;
380: }
381: sc->sc_subdevs[i] = config_found_sm(self, &uca,
382: ucomprint, ucomsubmatch);
383: }
384: }
385:
386: return;
387:
388: bad:
389: DPRINTF(("uvisor_attach: ATTACH ERROR\n"));
390: sc->sc_dying = 1;
391: }
392:
393: int
394: uvisor_activate(struct device *self, enum devact act)
395: {
396: struct uvisor_softc *sc = (struct uvisor_softc *)self;
397: int rv = 0;
398: int i;
399:
400: switch (act) {
401: case DVACT_ACTIVATE:
402: break;
403:
404: case DVACT_DEACTIVATE:
405: for (i = 0; i < sc->sc_numcon; i++)
406: if (sc->sc_subdevs[i] != NULL)
407: rv = config_deactivate(sc->sc_subdevs[i]);
408: sc->sc_dying = 1;
409: break;
410: }
411: return (rv);
412: }
413:
414: int
415: uvisor_detach(struct device *self, int flags)
416: {
417: struct uvisor_softc *sc = (struct uvisor_softc *)self;
418: int rv = 0;
419: int i;
420:
421: DPRINTF(("uvisor_detach: sc=%p flags=%d\n", sc, flags));
422: sc->sc_dying = 1;
423: for (i = 0; i < sc->sc_numcon; i++) {
424: if (sc->sc_subdevs[i] != NULL) {
425: rv |= config_detach(sc->sc_subdevs[i], flags);
426: sc->sc_subdevs[i] = NULL;
427: }
428: }
429:
430: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
431: &sc->sc_dev);
432:
433: return (rv);
434: }
435:
436: usbd_status
437: uvisor_init(struct uvisor_softc *sc, struct uvisor_connection_info *ci,
438: struct uvisor_palm_connection_info *cpi)
439: {
440: usbd_status err;
441: usb_device_request_t req;
442: int actlen;
443: uWord avail;
444:
445: if (sc->sc_flags & PALM4) {
446: DPRINTF(("uvisor_init: getting Palm connection info\n"));
447: req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
448: req.bRequest = UVISOR_GET_PALM_INFORMATION;
449: USETW(req.wValue, 0);
450: USETW(req.wIndex, 0);
451: USETW(req.wLength, UVISOR_GET_PALM_INFORMATION_LEN);
452: err = usbd_do_request_flags(sc->sc_udev, &req, cpi,
453: USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT);
454: if (err == USBD_STALLED && sc->sc_vendor == USB_VENDOR_SONY) {
455: /* some sony clie devices stall on palm4 requests,
456: * switch them over to using visor. dont do free space
457: * checks on them since they dont like them either.
458: */
459: DPRINTF(("switching role for CLIE probe\n"));
460: sc->sc_flags = CLIE4;
461: err = 0;
462: }
463: if (err)
464: return (err);
465: }
466:
467: if (sc->sc_flags & VISOR) {
468: DPRINTF(("uvisor_init: getting Visor connection info\n"));
469: req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
470: req.bRequest = UVISOR_GET_CONNECTION_INFORMATION;
471: USETW(req.wValue, 0);
472: USETW(req.wIndex, 0);
473: USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE);
474: err = usbd_do_request_flags(sc->sc_udev, &req, ci,
475: USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT);
476: if (err)
477: return (err);
478: }
479:
480: if (sc->sc_flags & NOFRE)
481: return (err);
482:
483: DPRINTF(("uvisor_init: getting available bytes\n"));
484: req.bmRequestType = UT_READ_VENDOR_ENDPOINT;
485: req.bRequest = UVISOR_REQUEST_BYTES_AVAILABLE;
486: USETW(req.wValue, 0);
487: USETW(req.wIndex, 5);
488: USETW(req.wLength, sizeof avail);
489: err = usbd_do_request(sc->sc_udev, &req, &avail);
490: if (err)
491: return (err);
492: DPRINTF(("uvisor_init: avail=%d\n", UGETW(avail)));
493: DPRINTF(("uvisor_init: done\n"));
494: return (err);
495: }
496:
497: void
498: uvisor_close(void *addr, int portno)
499: {
500: struct uvisor_softc *sc = addr;
501: usb_device_request_t req;
502: struct uvisor_connection_info coninfo; /* XXX ? */
503: int actlen;
504:
505: if (sc->sc_dying)
506: return;
507:
508: req.bmRequestType = UT_READ_VENDOR_ENDPOINT; /* XXX read? */
509: req.bRequest = UVISOR_CLOSE_NOTIFICATION;
510: USETW(req.wValue, 0);
511: USETW(req.wIndex, 0);
512: USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE);
513: (void)usbd_do_request_flags(sc->sc_udev, &req, &coninfo,
514: USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT);
515: }
CVSweb