]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/usb/uipaq.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / usb / uipaq.c
1 /*      $NetBSD: uipaq.c,v 1.4 2006/11/16 01:33:27 christos Exp $       */
2 /*      $OpenBSD: uipaq.c,v 1.1 2005/06/17 23:50:33 deraadt Exp $       */
3
4 /*
5  * Copyright (c) 2000-2005 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  * iPAQ driver
43  * 
44  * 19 July 2003:        Incorporated changes suggested by Sam Lawrance from
45  *                      the uppc module
46  *
47  *
48  * Contact isis@cs.umd.edu if you have any questions/comments about this driver
49  */
50
51 #include <sys/cdefs.h>
52 __FBSDID("$FreeBSD$");
53
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/kernel.h>
57 #include <sys/bus.h>
58 #include <sys/conf.h>
59 #include <sys/tty.h>
60 #include <sys/module.h>
61
62 #include <dev/usb/usb.h>
63 #include <dev/usb/usbhid.h>
64
65 #include <dev/usb/usbcdc.h>     /*UCDC_* stuff */
66
67 #include <dev/usb/usbdi.h>
68 #include <dev/usb/usbdi_util.h>
69 #include "usbdevs.h"
70
71 #include <dev/usb/ucomvar.h>
72
73 #ifdef UIPAQ_DEBUG
74 #define DPRINTF(x)      if (uipaqdebug) printf x
75 #define DPRINTFN(n,x)   if (uipaqdebug>(n)) printf x
76 int uipaqdebug = 0;
77 #else
78 #define DPRINTF(x)
79 #define DPRINTFN(n,x)
80 #endif
81
82 #define UIPAQ_CONFIG_NO         1
83 #define UIPAQ_IFACE_INDEX       0
84
85 #define UIPAQIBUFSIZE 1024
86 #define UIPAQOBUFSIZE 1024
87
88 struct uipaq_softc {
89         struct ucom_softc       sc_ucom;
90         u_int16_t               sc_lcr;         /* state for DTR/RTS */
91         u_int16_t               sc_flags;
92
93 };
94
95 /* Callback routines */
96 static void     uipaq_set(void *, int, int, int);
97
98 /* Support routines. */
99 /* based on uppc module by Sam Lawrance */
100 static void     uipaq_dtr(struct uipaq_softc *sc, int onoff);
101 static void     uipaq_rts(struct uipaq_softc *sc, int onoff);
102 static void     uipaq_break(struct uipaq_softc* sc, int onoff);
103
104 int uipaq_detach(device_t self);
105
106 struct ucom_callback uipaq_callback = {
107         NULL,
108         uipaq_set,
109         NULL,
110         NULL,
111         NULL,   /*open*/
112         NULL,   /*close*/
113         NULL,
114         NULL
115 };
116
117 struct uipaq_type {
118         struct usb_devno        uv_dev;
119         u_int16_t               uv_flags;
120 };
121
122 static const struct uipaq_type uipaq_devs[] = {
123         {{ USB_VENDOR_HP, USB_PRODUCT_HP_2215 }, 0 },
124         {{ USB_VENDOR_HP, USB_PRODUCT_HP_568J }, 0},
125         {{ USB_VENDOR_HTC, USB_PRODUCT_HTC_WINMOBILE }, 0},
126         {{ USB_VENDOR_HTC, USB_PRODUCT_HTC_PPC6700MODEM }, 0},
127         {{ USB_VENDOR_HTC, USB_PRODUCT_HTC_SMARTPHONE }, 0},
128         {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQPOCKETPC } , 0},
129         {{ USB_VENDOR_CASIO, USB_PRODUCT_CASIO_BE300 } , 0},
130         {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_WZERO3ES }, 0},
131         {{ USB_VENDOR_ASUS, USB_PRODUCT_ASUS_P535 }, 0},
132 };
133
134 #define uipaq_lookup(v, p) ((const struct uipaq_type *)usb_lookup(uipaq_devs, v, p))
135
136 static int
137 uipaq_match(device_t self)
138 {
139         struct usb_attach_arg *uaa = device_get_ivars(self);
140
141         if (uaa->iface != NULL)
142                 return (UMATCH_NONE);
143
144         DPRINTFN(20,("uipaq: vendor=0x%x, product=0x%x\n",
145             uaa->vendor, uaa->product));
146
147         return (uipaq_lookup(uaa->vendor, uaa->product) != NULL ?
148             UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
149 }
150
151 static int
152 uipaq_attach(device_t self)
153 {
154         struct uipaq_softc *sc = device_get_softc(self);
155         struct usb_attach_arg *uaa = device_get_ivars(self);
156         usbd_device_handle dev = uaa->device;
157         usbd_interface_handle iface;
158         usb_interface_descriptor_t *id;
159         usb_endpoint_descriptor_t *ed;
160         int i;
161         usbd_status err;
162         struct ucom_softc *ucom = &sc->sc_ucom;
163
164         ucom->sc_dev = self;
165         ucom->sc_udev = dev;
166
167         DPRINTFN(10,("\nuipaq_attach: sc=%p\n", sc));
168
169         /* Move the device into the configured state. */
170         err = usbd_set_config_no(dev, UIPAQ_CONFIG_NO, 1);
171         if (err) {
172                 device_printf(ucom->sc_dev,
173                     "failed to set configuration: %s\n", usbd_errstr(err));
174                 goto bad;
175         }
176
177         err = usbd_device2interface_handle(dev, UIPAQ_IFACE_INDEX, &iface);
178         if (err) {
179                 device_printf(ucom->sc_dev, "failed to get interface: %s\n",
180                     usbd_errstr(err));
181                 goto bad;
182         }
183
184         sc->sc_flags = uipaq_lookup(uaa->vendor, uaa->product)->uv_flags;
185         id = usbd_get_interface_descriptor(iface);
186         ucom->sc_iface = iface;
187         ucom->sc_ibufsize = UIPAQIBUFSIZE;
188         ucom->sc_obufsize = UIPAQOBUFSIZE;
189         ucom->sc_ibufsizepad = UIPAQIBUFSIZE;
190         ucom->sc_opkthdrlen = 0;
191         ucom->sc_callback = &uipaq_callback;
192         ucom->sc_parent = sc;
193         ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
194         for (i=0; i<id->bNumEndpoints; i++) {
195                 ed = usbd_interface2endpoint_descriptor(iface, i);
196                 if (ed == NULL) {
197                         device_printf(ucom->sc_dev, 
198                             "no endpoint descriptor for %d\n", i);
199                         goto bad;
200                 }
201                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
202                     (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
203                        ucom->sc_bulkin_no = ed->bEndpointAddress;
204                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
205                     (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
206                        ucom->sc_bulkout_no = ed->bEndpointAddress;
207                 }
208         }
209         if (ucom->sc_bulkin_no == -1 || ucom->sc_bulkout_no == -1) {
210                 device_printf(ucom->sc_dev,
211                     "no proper endpoints found (%d,%d)\n",
212                     ucom->sc_bulkin_no, ucom->sc_bulkout_no);
213                 return (ENXIO);
214         }
215         
216         ucom_attach(&sc->sc_ucom);
217         return (0);
218 bad:
219         DPRINTF(("uipaq_attach: ATTACH ERROR\n"));
220         ucom->sc_dying = 1;
221         return (ENXIO);
222 }
223
224 void
225 uipaq_dtr(struct uipaq_softc* sc, int onoff)
226 {
227         usb_device_request_t req;
228         struct ucom_softc *ucom = &sc->sc_ucom;
229         usbd_status err;
230         int retries = 3;
231
232         DPRINTF(("%s: uipaq_dtr: onoff=%x\n", device_get_nameunit(ucom->sc_dev), onoff));
233
234         /* Avoid sending unnecessary requests */
235         if (onoff && (sc->sc_lcr & UCDC_LINE_DTR))
236                 return;
237         if (!onoff && !(sc->sc_lcr & UCDC_LINE_DTR))
238                 return;
239
240         /* Other parameters depend on reg */
241         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
242         req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
243         sc->sc_lcr = onoff ? sc->sc_lcr | UCDC_LINE_DTR : sc->sc_lcr & ~UCDC_LINE_DTR;
244         USETW(req.wValue, sc->sc_lcr);
245         USETW(req.wIndex, 0x0);
246         USETW(req.wLength, 0);
247
248         /* Fire off the request a few times if necessary */
249         while (retries) {
250                 err = usbd_do_request(ucom->sc_udev, &req, NULL);
251                 if (!err)
252                         break;
253                 retries--;
254         }
255 }
256
257 void
258 uipaq_rts(struct uipaq_softc* sc, int onoff)
259 {
260         usb_device_request_t req;
261         struct ucom_softc *ucom = &sc->sc_ucom;
262         usbd_status err;
263         int retries = 3;
264
265         DPRINTF(("%s: uipaq_rts: onoff=%x\n", device_get_nameunit(ucom->sc_dev), onoff));
266
267         /* Avoid sending unnecessary requests */
268         if (onoff && (sc->sc_lcr & UCDC_LINE_RTS)) return;
269         if (!onoff && !(sc->sc_lcr & UCDC_LINE_RTS)) return;
270
271         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
272         req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
273         sc->sc_lcr = onoff ? sc->sc_lcr | UCDC_LINE_RTS : sc->sc_lcr & ~UCDC_LINE_RTS;
274         USETW(req.wValue, sc->sc_lcr);
275         USETW(req.wIndex, 0x0);
276         USETW(req.wLength, 0);
277
278         while (retries) {
279                 err = usbd_do_request(ucom->sc_udev, &req, NULL);
280                 if (!err)
281                         break;
282                 retries--;
283         }
284 }
285
286 void
287 uipaq_break(struct uipaq_softc* sc, int onoff)
288 {
289         usb_device_request_t req;
290         struct ucom_softc *ucom = &sc->sc_ucom;
291         usbd_status err;
292         int retries = 3;
293
294         DPRINTF(("%s: uipaq_break: onoff=%x\n", device_get_nameunit(ucom->sc_dev), onoff));
295
296         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
297         req.bRequest = UCDC_SEND_BREAK;
298
299         USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
300         USETW(req.wIndex, 0x0);
301         USETW(req.wLength, 0);
302
303         while (retries) {
304                 err = usbd_do_request(ucom->sc_udev, &req, NULL);
305                 if (!err)
306                         break;
307                 retries--;
308         }
309 }
310
311 void
312 uipaq_set(void *addr, int portno, int reg, int onoff)
313 {
314         struct uipaq_softc* sc = addr;
315         struct ucom_softc *ucom = &sc->sc_ucom;
316
317         switch (reg) {
318         case UCOM_SET_DTR:
319                 uipaq_dtr(addr, onoff);
320                 break;
321         case UCOM_SET_RTS:
322                 uipaq_rts(addr, onoff);
323                 break;
324         case UCOM_SET_BREAK:
325                 uipaq_break(addr, onoff);
326                 break;
327         default:
328                 printf("%s: unhandled set request: reg=%x onoff=%x\n",
329                   device_get_nameunit(ucom->sc_dev), reg, onoff);
330                 return;
331         }
332 }
333
334 int
335 uipaq_detach(device_t self)
336 {
337         struct uipaq_softc *sc = device_get_softc(self);
338         struct ucom_softc *ucom = &sc->sc_ucom;
339         int rv = 0;
340
341         DPRINTF(("uipaq_detach: sc=%p flags=%d\n", sc, flags));
342         ucom->sc_dying = 1;
343
344         rv = ucom_detach(ucom);
345
346         return (rv);
347 }
348
349 static device_method_t uipaq_methods[] = {
350         /* Device interface */
351         DEVMETHOD(device_probe, uipaq_match),
352         DEVMETHOD(device_attach, uipaq_attach),
353         DEVMETHOD(device_detach, uipaq_detach),
354
355         { 0, 0 }
356 };
357 static driver_t uipaq_driver = {
358         "ucom",
359         uipaq_methods,
360         sizeof (struct uipaq_softc)
361 };
362
363 DRIVER_MODULE(uipaq, uhub, uipaq_driver, ucom_devclass, usbd_driver_load, 0);
364 MODULE_DEPEND(uipaq, usb, 1, 1, 1);
365 MODULE_DEPEND(uipaq, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);