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