Annotation of sys/dev/usb/uipaq.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: uipaq.c,v 1.12 2007/06/14 10:11:16 mbalmer Exp $ */
2:
3: /*
4: * Copyright (c) 2000 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Lennart Augustsson (lennart@augustsson.net) at
9: * Carlstedt Research & Technology.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: * iPAQ driver
42: *
43: * 19 July 2003: Incorporated changes suggested by Sam Lawrance from
44: * the uppc module
45: *
46: *
47: * Contact isis@cs.umd.edu if you have any questions/comments about this driver
48: */
49:
50: #include <sys/param.h>
51: #include <sys/systm.h>
52: #include <sys/kernel.h>
53: #include <sys/device.h>
54: #include <sys/conf.h>
55: #include <sys/tty.h>
56:
57: #include <dev/usb/usb.h>
58: #include <dev/usb/usbhid.h>
59:
60: #include <dev/usb/usbcdc.h> /*UCDC_* stuff */
61:
62: #include <dev/usb/usbdi.h>
63: #include <dev/usb/usbdi_util.h>
64: #include <dev/usb/usbdevs.h>
65:
66: #include <dev/usb/ucomvar.h>
67:
68: #ifdef UIPAQ_DEBUG
69: #define DPRINTF(x) if (uipaqdebug) printf x
70: #define DPRINTFN(n,x) if (uipaqdebug>(n)) printf x
71: int uipaqdebug = 0;
72: #else
73: #define DPRINTF(x)
74: #define DPRINTFN(n,x)
75: #endif
76:
77: #define UIPAQ_CONFIG_NO 1
78: #define UIPAQ_IFACE_INDEX 0
79:
80: #define UIPAQIBUFSIZE 1024
81: #define UIPAQOBUFSIZE 1024
82:
83: struct uipaq_softc {
84: struct device sc_dev; /* base device */
85: usbd_device_handle sc_udev; /* device */
86: usbd_interface_handle sc_iface; /* interface */
87:
88: struct device *sc_subdev; /* ucom uses that */
89: u_int16_t sc_lcr; /* state for DTR/RTS */
90:
91: u_int16_t sc_flags;
92:
93: u_char sc_dying;
94: };
95:
96: /* Callback routines */
97: void uipaq_set(void *, int, int, int);
98:
99:
100: /* Support routines. */
101: /* based on uppc module by Sam Lawrance */
102: void uipaq_dtr(struct uipaq_softc *sc, int onoff);
103: void uipaq_rts(struct uipaq_softc *sc, int onoff);
104: void uipaq_break(struct uipaq_softc* sc, int onoff);
105:
106:
107: struct ucom_methods uipaq_methods = {
108: NULL,
109: uipaq_set,
110: NULL,
111: NULL,
112: NULL, /*open*/
113: NULL, /*close*/
114: NULL,
115: NULL
116: };
117:
118: struct uipaq_type {
119: struct usb_devno uv_dev;
120: u_int16_t uv_flags;
121: };
122:
123: static const struct uipaq_type uipaq_devs[] = {
124: {{ USB_VENDOR_HP, USB_PRODUCT_HP_2215 }, 0 },
125: {{ USB_VENDOR_HP, USB_PRODUCT_HP_568J }, 0},
126: {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQPOCKETPC} , 0},
127: {{ USB_VENDOR_CASIO, USB_PRODUCT_CASIO_BE300} , 0},
128: {{ USB_VENDOR_ASUS, USB_PRODUCT_ASUS_MYPAL_A730} , 0}
129: };
130:
131: #define uipaq_lookup(v, p) ((struct uipaq_type *)usb_lookup(uipaq_devs, v, p))
132:
133: int uipaq_match(struct device *, void *, void *);
134: void uipaq_attach(struct device *, struct device *, void *);
135: int uipaq_detach(struct device *, int);
136: int uipaq_activate(struct device *, enum devact);
137:
138: struct cfdriver uipaq_cd = {
139: NULL, "uipaq", DV_DULL
140: };
141:
142: const struct cfattach uipaq_ca = {
143: sizeof(struct uipaq_softc),
144: uipaq_match,
145: uipaq_attach,
146: uipaq_detach,
147: uipaq_activate,
148: };
149:
150: int
151: uipaq_match(struct device *parent, void *match, void *aux)
152: {
153: struct usb_attach_arg *uaa = aux;
154:
155: if (uaa->iface != NULL)
156: return (UMATCH_NONE);
157:
158: DPRINTFN(20,("uipaq: vendor=0x%x, product=0x%x\n",
159: uaa->vendor, uaa->product));
160:
161: return (uipaq_lookup(uaa->vendor, uaa->product) != NULL ?
162: UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
163: }
164:
165: void
166: uipaq_attach(struct device *parent, struct device *self, void *aux)
167: {
168: struct uipaq_softc *sc = (struct uipaq_softc *)self;
169: struct usb_attach_arg *uaa = aux;
170: usbd_device_handle dev = uaa->device;
171: usbd_interface_handle iface;
172: usb_interface_descriptor_t *id;
173: usb_endpoint_descriptor_t *ed;
174: char *devinfop;
175: char *devname = sc->sc_dev.dv_xname;
176: int i;
177: usbd_status err;
178: struct ucom_attach_args uca;
179:
180: DPRINTFN(10,("\nuipaq_attach: sc=%p\n", sc));
181:
182: /* Move the device into the configured state. */
183: err = usbd_set_config_no(dev, UIPAQ_CONFIG_NO, 1);
184: if (err) {
185: printf("\n%s: failed to set configuration, err=%s\n",
186: devname, usbd_errstr(err));
187: goto bad;
188: }
189:
190: err = usbd_device2interface_handle(dev, UIPAQ_IFACE_INDEX, &iface);
191: if (err) {
192: printf("\n%s: failed to get interface, err=%s\n",
193: devname, usbd_errstr(err));
194: goto bad;
195: }
196:
197: devinfop = usbd_devinfo_alloc(dev, 0);
198: printf("\n%s: %s\n", devname, devinfop);
199: usbd_devinfo_free(devinfop);
200:
201: sc->sc_flags = uipaq_lookup(uaa->vendor, uaa->product)->uv_flags;
202:
203: id = usbd_get_interface_descriptor(iface);
204:
205: sc->sc_udev = dev;
206: sc->sc_iface = iface;
207:
208: uca.ibufsize = UIPAQIBUFSIZE;
209: uca.obufsize = UIPAQOBUFSIZE;
210: uca.ibufsizepad = UIPAQIBUFSIZE;
211: uca.opkthdrlen = 0;
212: uca.device = dev;
213: uca.iface = iface;
214: uca.methods = &uipaq_methods;
215: uca.arg = sc;
216: uca.portno = UCOM_UNK_PORTNO;
217: uca.info = "Generic";
218:
219: /* err = uipaq_init(sc);
220: if (err) {
221: printf("%s: init failed, %s\n", sc->sc_dev.dv_xname,
222: usbd_errstr(err));
223: goto bad;
224: }*/
225:
226: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
227: &sc->sc_dev);
228:
229: uca.bulkin = uca.bulkout = -1;
230: for (i=0; i<id->bNumEndpoints; i++) {
231: ed = usbd_interface2endpoint_descriptor(iface, i);
232: if (ed == NULL) {
233: printf("%s: no endpoint descriptor for %d\n",
234: devname,i);
235: goto bad;
236: }
237: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
238: (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
239: uca.bulkin = ed->bEndpointAddress;
240: } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
241: (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
242: uca.bulkout = ed->bEndpointAddress;
243: }
244: }
245: if (uca.bulkin != -1 && uca.bulkout != -1)
246: sc->sc_subdev = config_found_sm(self, &uca,
247: ucomprint, ucomsubmatch);
248: else
249: printf("%s: no proper endpoints found (%d,%d) \n",
250: devname, uca.bulkin, uca.bulkout);
251:
252: return;
253:
254: bad:
255: DPRINTF(("uipaq_attach: ATTACH ERROR\n"));
256: sc->sc_dying = 1;
257: }
258:
259:
260: void
261: uipaq_dtr(struct uipaq_softc* sc, int onoff)
262: {
263: usb_device_request_t req;
264: usbd_status err;
265: int retries = 3;
266:
267: DPRINTF(("%s: uipaq_dtr: onoff=%x\n", sc->sc_dev.dv_xname, onoff));
268:
269: /* Avoid sending unnecessary requests */
270: if (onoff && (sc->sc_lcr & UCDC_LINE_DTR))
271: return;
272: if (!onoff && !(sc->sc_lcr & UCDC_LINE_DTR))
273: return;
274:
275: /* Other parameters depend on reg */
276: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
277: req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
278: sc->sc_lcr = onoff ? sc->sc_lcr | UCDC_LINE_DTR : sc->sc_lcr & ~UCDC_LINE_DTR;
279: USETW(req.wValue, sc->sc_lcr);
280: USETW(req.wIndex, 0x0);
281: USETW(req.wLength, 0);
282:
283: /* Fire off the request a few times if necessary */
284: while (retries) {
285: err = usbd_do_request(sc->sc_udev, &req, NULL);
286: if (!err)
287: break;
288: retries--;
289: }
290: }
291:
292:
293: void
294: uipaq_rts(struct uipaq_softc* sc, int onoff)
295: {
296: usb_device_request_t req;
297: usbd_status err;
298: int retries = 3;
299:
300: DPRINTF(("%s: uipaq_rts: onoff=%x\n", sc->sc_dev.dv_xname, onoff));
301:
302: /* Avoid sending unnecessary requests */
303: if (onoff && (sc->sc_lcr & UCDC_LINE_RTS)) return;
304: if (!onoff && !(sc->sc_lcr & UCDC_LINE_RTS)) return;
305:
306: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
307: req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
308: sc->sc_lcr = onoff ? sc->sc_lcr | UCDC_LINE_RTS : sc->sc_lcr & ~UCDC_LINE_RTS;
309: USETW(req.wValue, sc->sc_lcr);
310: USETW(req.wIndex, 0x0);
311: USETW(req.wLength, 0);
312:
313: while (retries) {
314: err = usbd_do_request(sc->sc_udev, &req, NULL);
315: if (!err)
316: break;
317: retries--;
318: }
319: }
320:
321:
322: void
323: uipaq_break(struct uipaq_softc* sc, int onoff)
324: {
325: usb_device_request_t req;
326: usbd_status err;
327: int retries = 3;
328:
329: DPRINTF(("%s: uipaq_break: onoff=%x\n", sc->sc_dev.dv_xname, onoff));
330:
331: req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
332: req.bRequest = UCDC_SEND_BREAK;
333:
334: USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
335: USETW(req.wIndex, 0x0);
336: USETW(req.wLength, 0);
337:
338: while (retries) {
339: err = usbd_do_request(sc->sc_udev, &req, NULL);
340: if (!err)
341: break;
342: retries--;
343: }
344: }
345:
346:
347: void
348: uipaq_set(void *addr, int portno, int reg, int onoff)
349: {
350: struct uipaq_softc* sc = addr;
351:
352: switch (reg) {
353: case UCOM_SET_DTR:
354: uipaq_dtr(addr, onoff);
355: break;
356: case UCOM_SET_RTS:
357: uipaq_rts(addr, onoff);
358: break;
359: case UCOM_SET_BREAK:
360: uipaq_break(addr, onoff);
361: break;
362: default:
363: printf("%s: unhandled set request: reg=%x onoff=%x\n",
364: sc->sc_dev.dv_xname, reg, onoff);
365: return;
366: }
367: }
368:
369:
370: int
371: uipaq_activate(struct device *self, enum devact act)
372: {
373: struct uipaq_softc *sc = (struct uipaq_softc *)self;
374: int rv = 0;
375:
376: switch (act) {
377: case DVACT_ACTIVATE:
378: break;
379:
380: case DVACT_DEACTIVATE:
381: if (sc->sc_subdev != NULL)
382: rv = config_deactivate(sc->sc_subdev);
383: sc->sc_dying = 1;
384: break;
385: }
386: return (rv);
387: }
388:
389: int
390: uipaq_detach(struct device *self, int flags)
391: {
392: struct uipaq_softc *sc = (struct uipaq_softc *)self;
393: int rv = 0;
394:
395: DPRINTF(("uipaq_detach: sc=%p flags=%d\n", sc, flags));
396: sc->sc_dying = 1;
397: if (sc->sc_subdev != NULL) {
398: rv |= config_detach(sc->sc_subdev, flags);
399: sc->sc_subdev = NULL;
400: }
401:
402: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
403: &sc->sc_dev);
404:
405: return (rv);
406: }
407:
CVSweb