DEVFS - remove dev_ops_add(), dev_ops_get(), and get_dev()
[dragonfly.git] / sys / dev / usbmisc / urio / urio.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 2000 Iwasa Kazmi
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions, and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * This code is based on ugen.c and ulpt.c developed by Lennart Augustsson.
27 * This code includes software developed by the NetBSD Foundation, Inc. and
28 * its contributors.
29 */
30
1550dfd9
MD
31/*
32 * $FreeBSD: src/sys/dev/usb/urio.c,v 1.28 2003/08/25 22:01:06 joe Exp $
74781d8f 33 * $DragonFly: src/sys/dev/usbmisc/urio/urio.c,v 1.27 2008/08/14 20:55:54 hasso Exp $
1550dfd9 34 */
984263bc
MD
35
36/*
37 * 2000/3/24 added NetBSD/OpenBSD support (from Alex Nemirovsky)
38 * 2000/3/07 use two bulk-pipe handles for read and write (Dirk)
39 * 2000/3/06 change major number(143), and copyright header
40 * some fix for 4.0 (Dirk)
41 * 2000/3/05 codes for FreeBSD 4.x - CURRENT (Thanks to Dirk-Willem van Gulik)
42 * 2000/3/01 remove retry code from urioioctl()
43 * change method of bulk transfer (no interrupt)
44 * 2000/2/28 small fixes for new rio_usb.h
45 * 2000/2/24 first version.
46 */
47
48#include <sys/param.h>
49#include <sys/systm.h>
50#include <sys/kernel.h>
51#include <sys/malloc.h>
984263bc
MD
52#include <sys/module.h>
53#include <sys/bus.h>
984263bc
MD
54#include <sys/fcntl.h>
55#include <sys/filio.h>
56#include <sys/conf.h>
57#include <sys/uio.h>
58#include <sys/tty.h>
59#include <sys/file.h>
984263bc 60#include <sys/select.h>
984263bc
MD
61#include <sys/poll.h>
62#include <sys/sysctl.h>
41c20dac 63#include <sys/proc.h>
4e01b467 64#include <sys/thread2.h>
984263bc 65
1f2de5d4
MD
66#include <bus/usb/usb.h>
67#include <bus/usb/usbdi.h>
68#include <bus/usb/usbdi_util.h>
984263bc 69
1f2de5d4 70#include <bus/usb/rio500_usb.h>
984263bc
MD
71
72#ifdef USB_DEBUG
fc1ef497
HT
73#define DPRINTF(x) if (uriodebug) kprintf x
74#define DPRINTFN(n,x) if (uriodebug>(n)) kprintf x
984263bc
MD
75int uriodebug = 0;
76SYSCTL_NODE(_hw_usb, OID_AUTO, urio, CTLFLAG_RW, 0, "USB urio");
77SYSCTL_INT(_hw_usb_urio, OID_AUTO, debug, CTLFLAG_RW,
78 &uriodebug, 0, "urio debug level");
79#else
80#define DPRINTF(x)
81#define DPRINTFN(n,x)
82#endif
83
84/* difference of usbd interface */
1550dfd9 85#define USBDI 1
984263bc
MD
86
87#define RIO_OUT 0
88#define RIO_IN 1
89#define RIO_NODIR 2
90
984263bc
MD
91d_open_t urioopen;
92d_close_t urioclose;
93d_read_t urioread;
94d_write_t uriowrite;
95d_ioctl_t urioioctl;
96
97#define URIO_CDEV_MAJOR 143
98
6ed427ca 99static struct dev_ops urio_ops = {
fef8985e
MD
100 { "urio", URIO_CDEV_MAJOR, 0 },
101 .d_open = urioopen,
102 .d_close = urioclose,
103 .d_read = urioread,
104 .d_write = uriowrite,
105 .d_ioctl = urioioctl,
984263bc
MD
106};
107#define RIO_UE_GET_DIR(p) ((UE_GET_DIR(p) == UE_DIR_IN) ? RIO_IN :\
108 ((UE_GET_DIR(p) == UE_DIR_OUT) ? RIO_OUT :\
109 RIO_NODIR))
984263bc
MD
110
111#define URIO_BBSIZE 1024
112
113struct urio_softc {
6ed427ca 114 device_t sc_dev;
984263bc
MD
115 usbd_device_handle sc_udev;
116 usbd_interface_handle sc_iface;
117
118 int sc_opened;
119 usbd_pipe_handle sc_pipeh_in;
120 usbd_pipe_handle sc_pipeh_out;
121 int sc_epaddr[2];
122
123 int sc_refcnt;
984263bc
MD
124};
125
126#define URIOUNIT(n) (minor(n))
127
128#define RIO_RW_TIMEOUT 4000 /* ms */
129
61b69189
HT
130static device_probe_t urio_match;
131static device_attach_t urio_attach;
132static device_detach_t urio_detach;
133
134static devclass_t urio_devclass;
135
136static kobj_method_t urio_methods[] = {
137 DEVMETHOD(device_probe, urio_match),
138 DEVMETHOD(device_attach, urio_attach),
139 DEVMETHOD(device_detach, urio_detach),
140 {0,0}
141};
142
143static driver_t urio_driver = {
144 "urio",
145 urio_methods,
146 sizeof(struct urio_softc)
147};
148
3f56796e
HT
149static const struct usb_devno urio_devs[] = {
150 { USB_DEVICE(0x045a, 0x5001) }, /* Diamond Multimedia Rio 600 */
151 { USB_DEVICE(0x045a, 0x5002) }, /* Diamond Multimedia Rio 800 */
152 { USB_DEVICE(0x0841, 0x0001) }, /* Diamond Multimedia Rio 500 */
153};
154
61b69189 155MODULE_DEPEND(urio, usb, 1, 1, 1);
984263bc 156
e785a5d9
HT
157static int
158urio_match(device_t self)
984263bc 159{
e785a5d9 160 struct usb_attach_arg *uaa = device_get_ivars(self);
984263bc
MD
161
162 DPRINTFN(10,("urio_match\n"));
3f56796e
HT
163 if (uaa->iface == NULL)
164 return (UMATCH_NONE);
165
166 return (usb_lookup(urio_devs, uaa->vendor, uaa->product) != NULL ?
167 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
984263bc
MD
168}
169
e785a5d9
HT
170static int
171urio_attach(device_t self)
984263bc 172{
e785a5d9
HT
173 struct urio_softc *sc = device_get_softc(self);
174 struct usb_attach_arg *uaa = device_get_ivars(self);
984263bc
MD
175 usbd_interface_handle iface;
176 u_int8_t epcount;
984263bc
MD
177 usbd_status r;
178 char * ermsg = "<none>";
179 int i;
180
1550dfd9 181 DPRINTFN(10,("urio_attach: sc=%p\n", sc));
e785a5d9 182 sc->sc_dev = self;
74781d8f 183 sc->sc_udev = uaa->device;
984263bc 184
984263bc
MD
185 if ((!uaa->device) || (!uaa->iface)) {
186 ermsg = "device or iface";
187 goto nobulk;
188 }
189 sc->sc_iface = iface = uaa->iface;
984263bc
MD
190 sc->sc_opened = 0;
191 sc->sc_pipeh_in = 0;
192 sc->sc_pipeh_out = 0;
193 sc->sc_refcnt = 0;
194
195 r = usbd_endpoint_count(iface, &epcount);
1550dfd9 196 if (r != USBD_NORMAL_COMPLETION) {
984263bc
MD
197 ermsg = "endpoints";
198 goto nobulk;
199 }
200
201 sc->sc_epaddr[RIO_OUT] = 0xff;
202 sc->sc_epaddr[RIO_IN] = 0x00;
203
204 for (i = 0; i < epcount; i++) {
1550dfd9 205 usb_endpoint_descriptor_t *edesc =
984263bc
MD
206 usbd_interface2endpoint_descriptor(iface, i);
207 int d;
208
209 if (!edesc) {
210 ermsg = "interface endpoint";
211 goto nobulk;
212 }
1550dfd9 213
984263bc
MD
214 d = RIO_UE_GET_DIR(edesc->bEndpointAddress);
215 if (d != RIO_NODIR)
216 sc->sc_epaddr[d] = edesc->bEndpointAddress;
217 }
218 if ( sc->sc_epaddr[RIO_OUT] == 0xff ||
219 sc->sc_epaddr[RIO_IN] == 0x00) {
220 ermsg = "Rio I&O";
221 goto nobulk;
222 }
223
fef8985e 224 make_dev(&urio_ops, device_get_unit(self),
3e82b46c
MD
225 UID_ROOT, GID_OPERATOR,
226 0644, "urio%d", device_get_unit(self));
984263bc
MD
227
228 DPRINTFN(10, ("urio_attach: %p\n", sc->sc_udev));
229
e785a5d9 230 return 0;
984263bc
MD
231
232 nobulk:
6ed427ca 233 kprintf("%s: could not find %s\n", device_get_nameunit(sc->sc_dev),ermsg);
e785a5d9 234 return ENXIO;
984263bc
MD
235}
236
237
238int
fef8985e 239urioopen(struct dev_open_args *ap)
984263bc 240{
b13267a5 241 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
242#if (USBDI >= 1)
243 struct urio_softc * sc;
244#endif
245 int unit = URIOUNIT(dev);
1e089e7e
HT
246 sc = devclass_get_softc(urio_devclass, unit);
247 if (sc == NULL)
248 return (ENXIO);
984263bc 249
1550dfd9 250 DPRINTFN(5, ("urioopen: flag=%d, mode=%d, unit=%d\n",
fef8985e 251 ap->a_oflags, ap->a_devtype, unit));
984263bc
MD
252
253 if (sc->sc_opened)
254 return EBUSY;
255
fef8985e 256 if ((ap->a_oflags & (FWRITE|FREAD)) != (FWRITE|FREAD))
984263bc
MD
257 return EACCES;
258
259 sc->sc_opened = 1;
260 sc->sc_pipeh_in = 0;
261 sc->sc_pipeh_out = 0;
1550dfd9
MD
262 if (usbd_open_pipe(sc->sc_iface,
263 sc->sc_epaddr[RIO_IN], 0, &sc->sc_pipeh_in)
984263bc
MD
264 != USBD_NORMAL_COMPLETION)
265 {
266 sc->sc_pipeh_in = 0;
267 return EIO;
268 };
1550dfd9
MD
269 if (usbd_open_pipe(sc->sc_iface,
270 sc->sc_epaddr[RIO_OUT], 0, &sc->sc_pipeh_out)
984263bc
MD
271 != USBD_NORMAL_COMPLETION)
272 {
1550dfd9 273 usbd_close_pipe(sc->sc_pipeh_in);
984263bc
MD
274 sc->sc_pipeh_in = 0;
275 sc->sc_pipeh_out = 0;
276 return EIO;
277 };
278 return 0;
279}
280
281int
fef8985e 282urioclose(struct dev_close_args *ap)
984263bc 283{
b13267a5 284 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
285#if (USBDI >= 1)
286 struct urio_softc * sc;
287#endif
288 int unit = URIOUNIT(dev);
1e089e7e 289 sc = devclass_get_softc(urio_devclass, unit);
984263bc 290
fef8985e
MD
291 DPRINTFN(5, ("urioclose: flag=%d, mode=%d, unit=%d\n",
292 ap->a_fflag, ap->a_devtype, unit));
1550dfd9
MD
293 if (sc->sc_pipeh_in)
294 usbd_close_pipe(sc->sc_pipeh_in);
984263bc 295
1550dfd9
MD
296 if (sc->sc_pipeh_out)
297 usbd_close_pipe(sc->sc_pipeh_out);
984263bc
MD
298
299 sc->sc_pipeh_in = 0;
300 sc->sc_pipeh_out = 0;
301 sc->sc_opened = 0;
302 sc->sc_refcnt = 0;
1550dfd9 303 return 0;
984263bc
MD
304}
305
306int
fef8985e 307urioread(struct dev_read_args *ap)
984263bc 308{
b13267a5 309 cdev_t dev = ap->a_head.a_dev;
fef8985e 310 struct uio *uio = ap->a_uio;
984263bc
MD
311#if (USBDI >= 1)
312 struct urio_softc * sc;
313 usbd_xfer_handle reqh;
314#else
315 usbd_request_handle reqh;
316 usbd_private_handle r_priv;
317 void *r_buff;
318 usbd_status r_status;
319#endif
320 int unit = URIOUNIT(dev);
321 usbd_status r;
322 char buf[URIO_BBSIZE];
323 u_int32_t n, tn;
324 int error = 0;
325
1e089e7e 326 sc = devclass_get_softc(urio_devclass, unit);
984263bc
MD
327
328 DPRINTFN(5, ("urioread: %d\n", unit));
329 if (!sc->sc_opened)
330 return EIO;
331
332#if (USBDI >= 1)
333 sc->sc_refcnt++;
334 reqh = usbd_alloc_xfer(sc->sc_udev);
335#else
336 reqh = usbd_alloc_request();
337#endif
338 if (reqh == 0)
339 return ENOMEM;
340 while ((n = min(URIO_BBSIZE, uio->uio_resid)) != 0) {
341 DPRINTFN(1, ("urioread: start transfer %d bytes\n", n));
342 tn = n;
343#if (USBDI >= 1)
344 usbd_setup_xfer(reqh, sc->sc_pipeh_in, 0, buf, tn,
345 0, RIO_RW_TIMEOUT, 0);
346#else
347 r = usbd_setup_request(reqh, sc->sc_pipeh_in, 0, buf, tn,
348 0, RIO_RW_TIMEOUT, 0);
349 if (r != USBD_NORMAL_COMPLETION) {
350 error = EIO;
351 break;
352 }
353#endif
354 r = usbd_sync_transfer(reqh);
355 if (r != USBD_NORMAL_COMPLETION) {
356 DPRINTFN(1, ("urioread: error=%d\n", r));
357 usbd_clear_endpoint_stall(sc->sc_pipeh_in);
358 tn = 0;
359 error = EIO;
360 break;
361 }
362#if (USBDI >= 1)
363 usbd_get_xfer_status(reqh, 0, 0, &tn, 0);
364#else
365 usbd_get_request_status(reqh, &r_priv, &r_buff, &tn, &r_status);
366#endif
367
368 DPRINTFN(1, ("urioread: got %d bytes\n", tn));
369 error = uiomove(buf, tn, uio);
370 if (error || tn < n)
371 break;
372 }
373#if (USBDI >= 1)
374 usbd_free_xfer(reqh);
375#else
376 usbd_free_request(reqh);
377#endif
378
379 return error;
380}
381
382int
fef8985e 383uriowrite(struct dev_write_args *ap)
984263bc 384{
b13267a5 385 cdev_t dev = ap->a_head.a_dev;
fef8985e 386 struct uio *uio = ap->a_uio;
984263bc
MD
387#if (USBDI >= 1)
388 struct urio_softc * sc;
389 usbd_xfer_handle reqh;
390#else
391 usbd_request_handle reqh;
392#endif
393 int unit = URIOUNIT(dev);
394 usbd_status r;
395 char buf[URIO_BBSIZE];
396 u_int32_t n;
397 int error = 0;
398
1e089e7e 399 sc = devclass_get_softc(urio_devclass, unit);
984263bc
MD
400
401 DPRINTFN(5, ("uriowrite: %d\n", unit));
402 if (!sc->sc_opened)
403 return EIO;
404
405#if (USBDI >= 1)
406 sc->sc_refcnt++;
407 reqh = usbd_alloc_xfer(sc->sc_udev);
408#else
409 reqh = usbd_alloc_request();
410#endif
411 if (reqh == 0)
412 return EIO;
413 while ((n = min(URIO_BBSIZE, uio->uio_resid)) != 0) {
414 error = uiomove(buf, n, uio);
415 if (error)
416 break;
417 DPRINTFN(1, ("uriowrite: transfer %d bytes\n", n));
418#if (USBDI >= 1)
419 usbd_setup_xfer(reqh, sc->sc_pipeh_out, 0, buf, n,
420 0, RIO_RW_TIMEOUT, 0);
421#else
422 r = usbd_setup_request(reqh, sc->sc_pipeh_out, 0, buf, n,
423 0, RIO_RW_TIMEOUT, 0);
424 if (r != USBD_NORMAL_COMPLETION) {
425 error = EIO;
426 break;
427 }
428#endif
429 r = usbd_sync_transfer(reqh);
430 if (r != USBD_NORMAL_COMPLETION) {
431 DPRINTFN(1, ("uriowrite: error=%d\n", r));
432 usbd_clear_endpoint_stall(sc->sc_pipeh_out);
433 error = EIO;
434 break;
435 }
436#if (USBDI >= 1)
437 usbd_get_xfer_status(reqh, 0, 0, 0, 0);
438#endif
439 }
440
441#if (USBDI >= 1)
442 usbd_free_xfer(reqh);
443#else
444 usbd_free_request(reqh);
445#endif
446
447 return error;
448}
449
450
451int
fef8985e 452urioioctl(struct dev_ioctl_args *ap)
984263bc 453{
b13267a5 454 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
455#if (USBDI >= 1)
456 struct urio_softc * sc;
457#endif
458 int unit = URIOUNIT(dev);
459 struct RioCommand *rio_cmd;
460 int requesttype, len;
461 struct iovec iov;
462 struct uio uio;
463 usb_device_request_t req;
464 int req_flags = 0, req_actlen = 0;
465 void *ptr = 0;
466 int error = 0;
467 usbd_status r;
468
1e089e7e 469 sc = devclass_get_softc(urio_devclass, unit);
984263bc 470
fef8985e 471 switch (ap->a_cmd) {
984263bc 472 case RIO_RECV_COMMAND:
fef8985e 473 if (!(ap->a_fflag & FWRITE))
984263bc 474 return EPERM;
fef8985e 475 rio_cmd = (struct RioCommand *)ap->a_data;
984263bc
MD
476 if (rio_cmd == NULL)
477 return EINVAL;
478 len = rio_cmd->length;
479
480 requesttype = rio_cmd->requesttype | UT_READ_VENDOR_DEVICE;
1550dfd9 481 DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
984263bc
MD
482 requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len));
483 break;
484
485 case RIO_SEND_COMMAND:
fef8985e 486 if (!(ap->a_fflag & FWRITE))
984263bc 487 return EPERM;
fef8985e 488 rio_cmd = (struct RioCommand *)ap->a_data;
984263bc
MD
489 if (rio_cmd == NULL)
490 return EINVAL;
491 len = rio_cmd->length;
492
493 requesttype = rio_cmd->requesttype | UT_WRITE_VENDOR_DEVICE;
1550dfd9 494 DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
984263bc
MD
495 requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len));
496 break;
497
498 default:
499 return EINVAL;
500 break;
501 }
502
503 /* Send rio control message */
504 req.bmRequestType = requesttype;
505 req.bRequest = rio_cmd->request;
506 USETW(req.wValue, rio_cmd->value);
507 USETW(req.wIndex, rio_cmd->index);
508 USETW(req.wLength, len);
509
510 if (len < 0 || len > 32767)
511 return EINVAL;
512 if (len != 0) {
513 iov.iov_base = (caddr_t)rio_cmd->buffer;
514 iov.iov_len = len;
515 uio.uio_iov = &iov;
516 uio.uio_iovcnt = 1;
517 uio.uio_resid = len;
518 uio.uio_offset = 0;
519 uio.uio_segflg = UIO_USERSPACE;
520 uio.uio_rw =
1550dfd9 521 req.bmRequestType & UT_READ ?
984263bc 522 UIO_READ : UIO_WRITE;
fef8985e 523 uio.uio_td = curthread;
efda3bd0 524 ptr = kmalloc(len, M_TEMP, M_WAITOK);
984263bc
MD
525 if (uio.uio_rw == UIO_WRITE) {
526 error = uiomove(ptr, len, &uio);
527 if (error)
528 goto ret;
529 }
530 }
531
1550dfd9
MD
532 r = usbd_do_request_flags(sc->sc_udev, &req,
533 ptr, req_flags, &req_actlen,
534 USBD_DEFAULT_TIMEOUT);
984263bc
MD
535 if (r == USBD_NORMAL_COMPLETION) {
536 error = 0;
537 if (len != 0) {
538 if (uio.uio_rw == UIO_READ) {
539 error = uiomove(ptr, len, &uio);
540 }
541 }
542 } else {
543 error = EIO;
544 }
545
546ret:
547 if (ptr)
efda3bd0 548 kfree(ptr, M_TEMP);
984263bc
MD
549 return error;
550}
551
6ed427ca 552static int
984263bc 553urio_detach(device_t self)
1550dfd9 554{
6ed427ca 555 DPRINTF(("%s: disconnected\n", device_get_nameunit(self)));
cd29885a 556 dev_ops_remove_minor(&urio_ops, /*-1, */device_get_unit(self));
1550dfd9 557 /* XXX not implemented yet */
984263bc
MD
558 device_set_desc(self, NULL);
559 return 0;
560}
561
984263bc 562DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, usbd_driver_load, 0);
7c070ee7 563