1 /* $OpenBSD: urio.c,v 1.18 2004/07/08 22:18:44 deraadt Exp $ */
2 /* $NetBSD: urio.c,v 1.15 2002/10/23 09:14:02 jdolecek 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 * The inspiration and information for this driver comes from the
43 * FreeBSD driver written by Iwasa Kazmi.
44 */
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #if defined(__NetBSD__) || defined(__OpenBSD__)
51 #include <sys/device.h>
52 #include <sys/ioctl.h>
53 #elif defined(__FreeBSD__)
54 #include <sys/module.h>
55 #include <sys/bus.h>
56 #include <sys/ioccom.h>
57 #include <sys/conf.h>
58 #include <sys/fcntl.h>
59 #include <sys/filio.h>
60 #endif
61 #include <sys/conf.h>
62 #include <sys/file.h>
63 #include <sys/select.h>
64 #include <sys/proc.h>
65 #include <sys/vnode.h>
66 #include <sys/poll.h>
67
68 #include <dev/usb/usb.h>
69 #include <dev/usb/usbdi.h>
70 #include <dev/usb/usbdi_util.h>
71
72 #include <dev/usb/usbdevs.h>
73 #include <dev/usb/urio.h>
74
75 #ifdef URIO_DEBUG
76 #define DPRINTF(x) do { if (uriodebug) logprintf x; } while (0)
77 #define DPRINTFN(n,x) do { if (uriodebug>(n)) logprintf x; } while (0)
78 int uriodebug = 0;
79 #else
80 #define DPRINTF(x)
81 #define DPRINTFN(n,x)
82 #endif
83
84
85 #if defined(__NetBSD__)
86 dev_type_open(urioopen);
87 dev_type_close(urioclose);
88 dev_type_read(urioread);
89 dev_type_write(uriowrite);
90 dev_type_ioctl(urioioctl);
91
92 const struct cdevsw urio_cdevsw = {
93 urioopen, urioclose, urioread, uriowrite, urioioctl,
94 nostop, notty, nopoll, nommap, nokqfilter,
95 };
96 #elif defined(__FreeBSD__)
97 d_open_t urioopen;
98 d_close_t urioclose;
99 d_read_t urioread;
100 d_write_t uriowrite;
101 d_ioctl_t urioioctl;
102
103 #define URIO_CDEV_MAJOR 143
104
105 static struct cdevsw urio_cdevsw = {
106 urioopen, urioclose, urioread, uriowrite,
107 urioioctl, nopoll, nommap, nostrategy,
108 "urio", URIO_CDEV_MAJOR,nodump, nopsize,
109 0, -1
110 };
111 #endif /* defined(__FreeBSD__) */
112
113 #define URIO_CONFIG_NO 1
114 #define URIO_IFACE_IDX 0
115
116
117 #define URIO_BSIZE 4096
118
119
120 struct urio_softc {
121 USBBASEDEVICE sc_dev;
122 usbd_device_handle sc_udev;
123 usbd_interface_handle sc_iface;
124
125 int sc_in_addr;
126 usbd_pipe_handle sc_in_pipe;
127 int sc_out_addr;
128 usbd_pipe_handle sc_out_pipe;
129
130 int sc_refcnt;
131 char sc_dying;
132 };
133
134 #define URIOUNIT(n) (minor(n))
135
136 #define URIO_RW_TIMEOUT 4000 /* ms */
137
138 static const struct usb_devno urio_devs[] = {
139 { USB_VENDOR_DIAMOND, USB_PRODUCT_DIAMOND_RIO500USB},
140 { USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO600USB},
141 { USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO800USB},
142 { USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_PSAPLAY120},
143 };
144 #define urio_lookup(v, p) usb_lookup(urio_devs, v, p)
145
146 USB_DECLARE_DRIVER(urio);
147
USB_MATCH(urio)148 USB_MATCH(urio)
149 {
150 USB_MATCH_START(urio, uaa);
151
152 DPRINTFN(50,("urio_match\n"));
153
154 if (uaa->iface != NULL)
155 return (UMATCH_NONE);
156
157 return (urio_lookup(uaa->vendor, uaa->product) != NULL ?
158 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
159 }
160
USB_ATTACH(urio)161 USB_ATTACH(urio)
162 {
163 USB_ATTACH_START(urio, sc, uaa);
164 usbd_device_handle dev = uaa->device;
165 usbd_interface_handle iface;
166 char devinfo[1024];
167 usbd_status err;
168 usb_endpoint_descriptor_t *ed;
169 u_int8_t epcount;
170 int i;
171
172 DPRINTFN(10,("urio_attach: sc=%p\n", sc));
173
174 usbd_devinfo(dev, 0, devinfo, sizeof devinfo);
175 USB_ATTACH_SETUP;
176 printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
177
178 err = usbd_set_config_no(dev, URIO_CONFIG_NO, 1);
179 if (err) {
180 printf("%s: setting config no failed\n",
181 USBDEVNAME(sc->sc_dev));
182 USB_ATTACH_ERROR_RETURN;
183 }
184
185 err = usbd_device2interface_handle(dev, URIO_IFACE_IDX, &iface);
186 if (err) {
187 printf("%s: getting interface handle failed\n",
188 USBDEVNAME(sc->sc_dev));
189 USB_ATTACH_ERROR_RETURN;
190 }
191
192 sc->sc_udev = dev;
193 sc->sc_iface = iface;
194
195 epcount = 0;
196 (void)usbd_endpoint_count(iface, &epcount);
197
198 sc->sc_in_addr = -1;
199 sc->sc_out_addr = -1;
200 for (i = 0; i < epcount; i++) {
201 ed = usbd_interface2endpoint_descriptor(iface, i);
202 if (ed == NULL) {
203 printf("%s: couldn't get ep %d\n",
204 USBDEVNAME(sc->sc_dev), i);
205 USB_ATTACH_ERROR_RETURN;
206 }
207 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
208 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
209 sc->sc_in_addr = ed->bEndpointAddress;
210 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
211 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
212 sc->sc_out_addr = ed->bEndpointAddress;
213 }
214 }
215 if (sc->sc_in_addr == -1 || sc->sc_out_addr == -1) {
216 printf("%s: missing endpoint\n", USBDEVNAME(sc->sc_dev));
217 USB_ATTACH_ERROR_RETURN;
218 }
219
220 #if defined(__FreeBSD__)
221 /* XXX no error trapping, no storing of dev_t */
222 (void)make_dev(&urio_cdevsw, device_get_unit(self),
223 UID_ROOT, GID_OPERATOR,
224 0644, "urio%d", device_get_unit(self));
225 #endif /* defined(__FreeBSD__) */
226
227 DPRINTFN(10, ("urio_attach: %p\n", sc->sc_udev));
228
229 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
230 USBDEV(sc->sc_dev));
231
232 USB_ATTACH_SUCCESS_RETURN;
233 }
234
USB_DETACH(urio)235 USB_DETACH(urio)
236 {
237 USB_DETACH_START(urio, sc);
238 int s;
239 #if defined(__NetBSD__) || defined(__OpenBSD__)
240 int maj, mn;
241
242 DPRINTF(("urio_detach: sc=%p flags=%d\n", sc, flags));
243 #elif defined(__FreeBSD__)
244 DPRINTF(("urio_detach: sc=%p\n", sc));
245 #endif
246
247 sc->sc_dying = 1;
248 /* Abort all pipes. Causes processes waiting for transfer to wake. */
249 if (sc->sc_in_pipe != NULL) {
250 usbd_abort_pipe(sc->sc_in_pipe);
251 usbd_close_pipe(sc->sc_in_pipe);
252 sc->sc_in_pipe = NULL;
253 }
254 if (sc->sc_out_pipe != NULL) {
255 usbd_abort_pipe(sc->sc_out_pipe);
256 usbd_close_pipe(sc->sc_out_pipe);
257 sc->sc_out_pipe = NULL;
258 }
259
260 s = splusb();
261 if (--sc->sc_refcnt >= 0) {
262 /* Wait for processes to go away. */
263 usb_detach_wait(USBDEV(sc->sc_dev));
264 }
265 splx(s);
266
267 #if defined(__NetBSD__) || defined(__OpenBSD__)
268 /* locate the major number */
269 #if defined(__NetBSD__)
270 maj = cdevsw_lookup_major(&urio_cdevsw);
271 #elif defined(__OpenBSD__)
272 for (maj = 0; maj < nchrdev; maj++)
273 if (cdevsw[maj].d_open == urioopen)
274 break;
275 #endif
276
277 /* Nuke the vnodes for any open instances (calls close). */
278 mn = self->dv_unit;
279 vdevgone(maj, mn, mn, VCHR);
280 #elif defined(__FreeBSD__)
281 /* XXX not implemented yet */
282 #endif
283
284 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
285 USBDEV(sc->sc_dev));
286
287 return (0);
288 }
289
290 #if defined(__NetBSD__) || defined(__OpenBSD__)
291 int
urio_activate(device_ptr_t self,enum devact act)292 urio_activate(device_ptr_t self, enum devact act)
293 {
294 struct urio_softc *sc = (struct urio_softc *)self;
295
296 switch (act) {
297 case DVACT_ACTIVATE:
298 return (EOPNOTSUPP);
299 break;
300
301 case DVACT_DEACTIVATE:
302 sc->sc_dying = 1;
303 break;
304 }
305 return (0);
306 }
307 #endif
308
309 int
urioopen(dev_t dev,int flag,int mode,usb_proc_ptr p)310 urioopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
311 {
312 struct urio_softc *sc;
313 usbd_status err;
314
315 USB_GET_SC_OPEN(urio, URIOUNIT(dev), sc);
316
317 DPRINTFN(5, ("urioopen: flag=%d, mode=%d, unit=%d\n",
318 flag, mode, URIOUNIT(dev)));
319
320 if (sc->sc_dying)
321 return (EIO);
322
323 if (sc->sc_in_pipe != NULL)
324 return (EBUSY);
325
326 if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
327 return (EACCES);
328
329 err = usbd_open_pipe(sc->sc_iface, sc->sc_in_addr, 0, &sc->sc_in_pipe);
330 if (err)
331 return (EIO);
332 err = usbd_open_pipe(sc->sc_iface, sc->sc_out_addr,0,&sc->sc_out_pipe);
333 if (err) {
334 usbd_close_pipe(sc->sc_in_pipe);
335 sc->sc_in_pipe = NULL;
336 return (EIO);
337 }
338
339 return (0);
340 }
341
342 int
urioclose(dev_t dev,int flag,int mode,usb_proc_ptr p)343 urioclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
344 {
345 struct urio_softc *sc;
346 USB_GET_SC(urio, URIOUNIT(dev), sc);
347
348 DPRINTFN(5, ("urioclose: flag=%d, mode=%d, unit=%d\n",
349 flag, mode, URIOUNIT(dev)));
350
351 if (sc->sc_in_pipe != NULL) {
352 usbd_abort_pipe(sc->sc_in_pipe);
353 usbd_close_pipe(sc->sc_in_pipe);
354 sc->sc_in_pipe = NULL;
355 }
356 if (sc->sc_out_pipe != NULL) {
357 usbd_abort_pipe(sc->sc_out_pipe);
358 usbd_close_pipe(sc->sc_out_pipe);
359 sc->sc_out_pipe = NULL;
360 }
361
362 return (0);
363 }
364
365 int
urioread(dev_t dev,struct uio * uio,int flag)366 urioread(dev_t dev, struct uio *uio, int flag)
367 {
368 struct urio_softc *sc;
369 usbd_xfer_handle xfer;
370 usbd_status err;
371 void *bufp;
372 u_int32_t n, tn;
373 int error = 0;
374
375 USB_GET_SC(urio, URIOUNIT(dev), sc);
376
377 DPRINTFN(5, ("urioread: %d\n", URIOUNIT(dev)));
378
379 if (sc->sc_dying)
380 return (EIO);
381
382 xfer = usbd_alloc_xfer(sc->sc_udev);
383 if (xfer == NULL)
384 return (ENOMEM);
385 bufp = usbd_alloc_buffer(xfer, URIO_BSIZE);
386 if (bufp == NULL) {
387 usbd_free_xfer(xfer);
388 return (ENOMEM);
389 }
390
391 sc->sc_refcnt++;
392
393 while ((n = min(URIO_BSIZE, uio->uio_resid)) != 0) {
394 DPRINTFN(1, ("urioread: start transfer %d bytes\n", n));
395 tn = n;
396 err = usbd_bulk_transfer(xfer, sc->sc_in_pipe, USBD_NO_COPY,
397 URIO_RW_TIMEOUT, bufp, &tn, "uriors");
398 if (err) {
399 if (err == USBD_INTERRUPTED)
400 error = EINTR;
401 else if (err == USBD_TIMEOUT)
402 error = ETIMEDOUT;
403 else
404 error = EIO;
405 break;
406 }
407
408 DPRINTFN(1, ("urioread: got %d bytes\n", tn));
409
410 error = uiomove(bufp, tn, uio);
411 if (error || tn < n)
412 break;
413 }
414 usbd_free_xfer(xfer);
415
416 if (--sc->sc_refcnt < 0)
417 usb_detach_wakeup(USBDEV(sc->sc_dev));
418
419 return (error);
420 }
421
422 int
uriowrite(dev_t dev,struct uio * uio,int flag)423 uriowrite(dev_t dev, struct uio *uio, int flag)
424 {
425 struct urio_softc *sc;
426 usbd_xfer_handle xfer;
427 usbd_status err;
428 void *bufp;
429 u_int32_t n;
430 int error = 0;
431
432 USB_GET_SC(urio, URIOUNIT(dev), sc);
433
434 DPRINTFN(5, ("uriowrite: unit=%d, len=%ld\n", URIOUNIT(dev),
435 (long)uio->uio_resid));
436
437 if (sc->sc_dying)
438 return (EIO);
439
440 xfer = usbd_alloc_xfer(sc->sc_udev);
441 if (xfer == NULL)
442 return (ENOMEM);
443 bufp = usbd_alloc_buffer(xfer, URIO_BSIZE);
444 if (bufp == NULL) {
445 usbd_free_xfer(xfer);
446 return (ENOMEM);
447 }
448
449 sc->sc_refcnt++;
450
451 while ((n = min(URIO_BSIZE, uio->uio_resid)) != 0) {
452 error = uiomove(bufp, n, uio);
453 if (error)
454 break;
455
456 DPRINTFN(1, ("uriowrite: transfer %d bytes\n", n));
457
458 err = usbd_bulk_transfer(xfer, sc->sc_out_pipe, USBD_NO_COPY,
459 URIO_RW_TIMEOUT, bufp, &n, "uriowr");
460 DPRINTFN(2, ("uriowrite: err=%d\n", err));
461 if (err) {
462 if (err == USBD_INTERRUPTED)
463 error = EINTR;
464 else if (err == USBD_TIMEOUT)
465 error = ETIMEDOUT;
466 else
467 error = EIO;
468 break;
469 }
470 }
471
472 usbd_free_xfer(xfer);
473
474 if (--sc->sc_refcnt < 0)
475 usb_detach_wakeup(USBDEV(sc->sc_dev));
476
477 DPRINTFN(5, ("uriowrite: done unit=%d, error=%d\n", URIOUNIT(dev),
478 error));
479
480 return (error);
481 }
482
483
484 int
urioioctl(dev_t dev,u_long cmd,caddr_t addr,int flag,usb_proc_ptr p)485 urioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
486 {
487 struct urio_softc * sc;
488 int unit = URIOUNIT(dev);
489 struct urio_command *rcmd;
490 int requesttype, len;
491 struct iovec iov;
492 struct uio uio;
493 usb_device_request_t req;
494 usbd_status err;
495 int req_flags = 0;
496 u_int32_t req_actlen = 0;
497 void *ptr = NULL;
498 int error = 0;
499
500 USB_GET_SC(urio, unit, sc);
501
502 if (sc->sc_dying)
503 return (EIO);
504
505 rcmd = (struct urio_command *)addr;
506
507 switch (cmd) {
508 case URIO_RECV_COMMAND:
509 requesttype = rcmd->requesttype | UT_READ_VENDOR_DEVICE;
510 break;
511
512 case URIO_SEND_COMMAND:
513 requesttype = rcmd->requesttype | UT_WRITE_VENDOR_DEVICE;
514 break;
515
516 default:
517 return (EINVAL);
518 break;
519 }
520
521 if (!(flag & FWRITE))
522 return (EPERM);
523 len = rcmd->length;
524
525 DPRINTFN(1,("urio_ioctl: cmd=0x%08lx reqtype=0x%0x req=0x%0x "
526 "value=0x%0x index=0x%0x len=0x%0x\n",
527 cmd, requesttype, rcmd->request, rcmd->value,
528 rcmd->index, len));
529
530 /* Send rio control message */
531 req.bmRequestType = requesttype;
532 req.bRequest = rcmd->request;
533 USETW(req.wValue, rcmd->value);
534 USETW(req.wIndex, rcmd->index);
535 USETW(req.wLength, len);
536
537 if (len < 0 || len > 32767)
538 return (EINVAL);
539 if (len != 0) {
540 iov.iov_base = (caddr_t)rcmd->buffer;
541 iov.iov_len = len;
542 uio.uio_iov = &iov;
543 uio.uio_iovcnt = 1;
544 uio.uio_resid = len;
545 uio.uio_offset = 0;
546 uio.uio_segflg = UIO_USERSPACE;
547 uio.uio_rw = req.bmRequestType & UT_READ ?
548 UIO_READ : UIO_WRITE;
549 uio.uio_procp = p;
550 ptr = malloc(len, M_TEMP, M_WAITOK);
551 if (uio.uio_rw == UIO_WRITE) {
552 error = uiomove(ptr, len, &uio);
553 if (error)
554 goto ret;
555 }
556 }
557
558 sc->sc_refcnt++;
559
560 err = usbd_do_request_flags(sc->sc_udev, &req, ptr, req_flags,
561 &req_actlen, USBD_DEFAULT_TIMEOUT);
562
563 if (--sc->sc_refcnt < 0)
564 usb_detach_wakeup(USBDEV(sc->sc_dev));
565
566 if (err) {
567 error = EIO;
568 } else {
569 if (len != 0 && uio.uio_rw == UIO_READ)
570 error = uiomove(ptr, len, &uio);
571 }
572
573 ret:
574 if (ptr != NULL)
575 free(ptr, M_TEMP);
576 return (error);
577 }
578
579 int
uriopoll(dev_t dev,int events,usb_proc_ptr p)580 uriopoll(dev_t dev, int events, usb_proc_ptr p)
581 {
582 return (0);
583 }
584
585 #if defined(__FreeBSD__)
586 DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, usbd_driver_load, 0);
587 #endif /* defined(__FreeBSD__) */
588