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