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