1 /*	$NetBSD: urio.c,v 1.44 2016/07/07 06:55:42 msaitoh 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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * The inspiration and information for this driver comes from the
35  * FreeBSD driver written by Iwasa Kazmi.
36  */
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: urio.c,v 1.44 2016/07/07 06:55:42 msaitoh Exp $");
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/kmem.h>
45 #include <sys/device.h>
46 #include <sys/ioctl.h>
47 #include <sys/conf.h>
48 #include <sys/file.h>
49 #include <sys/select.h>
50 #include <sys/proc.h>
51 #include <sys/vnode.h>
52 #include <sys/poll.h>
53 
54 #include <dev/usb/usb.h>
55 #include <dev/usb/usbdi.h>
56 #include <dev/usb/usbdi_util.h>
57 
58 #include <dev/usb/usbdevs.h>
59 #include <dev/usb/urio.h>
60 
61 #ifdef URIO_DEBUG
62 #define DPRINTF(x)	if (uriodebug) printf x
63 #define DPRINTFN(n,x)	if (uriodebug>(n)) printf x
64 int	uriodebug = 0;
65 #else
66 #define DPRINTF(x)
67 #define DPRINTFN(n,x)
68 #endif
69 
70 
71 dev_type_open(urioopen);
72 dev_type_close(urioclose);
73 dev_type_read(urioread);
74 dev_type_write(uriowrite);
75 dev_type_ioctl(urioioctl);
76 
77 const struct cdevsw urio_cdevsw = {
78 	.d_open = urioopen,
79 	.d_close = urioclose,
80 	.d_read = urioread,
81 	.d_write = uriowrite,
82 	.d_ioctl = urioioctl,
83 	.d_stop = nostop,
84 	.d_tty = notty,
85 	.d_poll = nopoll,
86 	.d_mmap = nommap,
87 	.d_kqfilter = nokqfilter,
88 	.d_discard = nodiscard,
89 	.d_flag = D_OTHER
90 };
91 
92 #define URIO_CONFIG_NO		1
93 #define URIO_IFACE_IDX		0
94 
95 
96 #define	URIO_BSIZE	4096
97 
98 
99 struct urio_softc {
100  	device_t		sc_dev;
101 	struct usbd_device *	sc_udev;
102 	struct usbd_interface *	sc_iface;
103 
104 	int			sc_in_addr;
105 	struct usbd_pipe *	sc_in_pipe;
106 	int			sc_out_addr;
107 	struct usbd_pipe *	sc_out_pipe;
108 
109 	int			sc_refcnt;
110 	char			sc_dying;
111 };
112 
113 #define URIOUNIT(n) (minor(n))
114 
115 #define URIO_RW_TIMEOUT 4000	/* ms */
116 
117 static const struct usb_devno urio_devs[] = {
118 	{ USB_VENDOR_DIAMOND, USB_PRODUCT_DIAMOND_RIO500USB},
119 	{ USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO600USB},
120 	{ USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO800USB},
121 	{ USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_PSAPLAY120},
122 };
123 #define urio_lookup(v, p) usb_lookup(urio_devs, v, p)
124 
125 int	urio_match(device_t, cfdata_t, void *);
126 void	urio_attach(device_t, device_t, void *);
127 int	urio_detach(device_t, int);
128 int	urio_activate(device_t, enum devact);
129 extern struct cfdriver urio_cd;
130 CFATTACH_DECL_NEW(urio, sizeof(struct urio_softc), urio_match, urio_attach,
131     urio_detach, urio_activate);
132 
133 int
urio_match(device_t parent,cfdata_t match,void * aux)134 urio_match(device_t parent, cfdata_t match, void *aux)
135 {
136 	struct usb_attach_arg *uaa = aux;
137 
138 	DPRINTFN(50,("urio_match\n"));
139 
140 	return urio_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ?
141 		UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
142 }
143 
144 void
urio_attach(device_t parent,device_t self,void * aux)145 urio_attach(device_t parent, device_t self, void *aux)
146 {
147 	struct urio_softc *sc = device_private(self);
148 	struct usb_attach_arg *uaa = aux;
149 	struct usbd_device *	dev = uaa->uaa_device;
150 	struct usbd_interface *	iface;
151 	char			*devinfop;
152 	usbd_status		err;
153 	usb_endpoint_descriptor_t *ed;
154 	uint8_t			epcount;
155 	int			i;
156 
157 	DPRINTFN(10,("urio_attach: sc=%p\n", sc));
158 
159 	sc->sc_dev = self;
160 
161 	aprint_naive("\n");
162 	aprint_normal("\n");
163 
164 	devinfop = usbd_devinfo_alloc(dev, 0);
165 	aprint_normal_dev(self, "%s\n", devinfop);
166 	usbd_devinfo_free(devinfop);
167 
168 	err = usbd_set_config_no(dev, URIO_CONFIG_NO, 1);
169 	if (err) {
170 		aprint_error_dev(self, "failed to set configuration"
171 		    ", err=%s\n", usbd_errstr(err));
172 		return;
173 	}
174 
175 	err = usbd_device2interface_handle(dev, URIO_IFACE_IDX, &iface);
176 	if (err) {
177 		aprint_error_dev(self, "getting interface handle failed\n");
178 		return;
179 	}
180 
181 	sc->sc_udev = dev;
182 	sc->sc_iface = iface;
183 
184 	epcount = 0;
185 	(void)usbd_endpoint_count(iface, &epcount);
186 
187 	sc->sc_in_addr = -1;
188 	sc->sc_out_addr = -1;
189 	for (i = 0; i < epcount; i++) {
190 		ed = usbd_interface2endpoint_descriptor(iface, i);
191 		if (ed == NULL) {
192 			aprint_error_dev(self, "couldn't get ep %d\n", i);
193 			return;
194 		}
195 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
196 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
197 			sc->sc_in_addr = ed->bEndpointAddress;
198 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
199 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
200 			sc->sc_out_addr = ed->bEndpointAddress;
201 		}
202 	}
203 	if (sc->sc_in_addr == -1 || sc->sc_out_addr == -1) {
204 		aprint_error_dev(self, "missing endpoint\n");
205 		return;
206 	}
207 
208 	DPRINTFN(10, ("urio_attach: %p\n", sc->sc_udev));
209 
210 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
211 
212 	return;
213 }
214 
215 int
urio_detach(device_t self,int flags)216 urio_detach(device_t self, int flags)
217 {
218 	struct urio_softc *sc = device_private(self);
219 	int s;
220 	int maj, mn;
221 
222 	DPRINTF(("urio_detach: sc=%p flags=%d\n", sc, flags));
223 
224 	sc->sc_dying = 1;
225 	/* Abort all pipes.  Causes processes waiting for transfer to wake. */
226 	if (sc->sc_in_pipe != NULL) {
227 		usbd_abort_pipe(sc->sc_in_pipe);
228 		usbd_close_pipe(sc->sc_in_pipe);
229 		sc->sc_in_pipe = NULL;
230 	}
231 	if (sc->sc_out_pipe != NULL) {
232 		usbd_abort_pipe(sc->sc_out_pipe);
233 		usbd_close_pipe(sc->sc_out_pipe);
234 		sc->sc_out_pipe = NULL;
235 	}
236 
237 	s = splusb();
238 	if (--sc->sc_refcnt >= 0) {
239 		/* Wait for processes to go away. */
240 		usb_detach_waitold(sc->sc_dev);
241 	}
242 	splx(s);
243 
244 	/* locate the major number */
245 	maj = cdevsw_lookup_major(&urio_cdevsw);
246 
247 	/* Nuke the vnodes for any open instances (calls close). */
248 	mn = device_unit(self);
249 	vdevgone(maj, mn, mn, VCHR);
250 
251 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
252 
253 	return 0;
254 }
255 
256 int
urio_activate(device_t self,enum devact act)257 urio_activate(device_t self, enum devact act)
258 {
259 	struct urio_softc *sc = device_private(self);
260 
261 	switch (act) {
262 	case DVACT_DEACTIVATE:
263 		sc->sc_dying = 1;
264 		return 0;
265 	default:
266 		return EOPNOTSUPP;
267 	}
268 }
269 
270 int
urioopen(dev_t dev,int flag,int mode,struct lwp * l)271 urioopen(dev_t dev, int flag, int mode, struct lwp *l)
272 {
273 	struct urio_softc *sc;
274 	usbd_status err;
275 
276 	sc = device_lookup_private(&urio_cd, URIOUNIT(dev));
277 	if (sc == NULL)
278 		return ENXIO;
279 
280 	DPRINTFN(5, ("urioopen: flag=%d, mode=%d, unit=%d\n",
281 		     flag, mode, URIOUNIT(dev)));
282 
283 	if (sc->sc_dying)
284 		return EIO;
285 
286 	if (sc->sc_in_pipe != NULL)
287 		return EBUSY;
288 
289 	if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
290 		return EACCES;
291 
292 	err = usbd_open_pipe(sc->sc_iface, sc->sc_in_addr, 0, &sc->sc_in_pipe);
293 	if (err)
294 		return EIO;
295 	err = usbd_open_pipe(sc->sc_iface, sc->sc_out_addr,0,&sc->sc_out_pipe);
296 	if (err) {
297 		usbd_close_pipe(sc->sc_in_pipe);
298 		sc->sc_in_pipe = NULL;
299 		return EIO;
300 	}
301 
302 	return 0;
303 }
304 
305 int
urioclose(dev_t dev,int flag,int mode,struct lwp * l)306 urioclose(dev_t dev, int flag, int mode,
307     struct lwp *l)
308 {
309 	struct urio_softc *sc;
310 	sc = device_lookup_private(&urio_cd, URIOUNIT(dev));
311 
312 	DPRINTFN(5, ("urioclose: flag=%d, mode=%d, unit=%d\n",
313 		     flag, mode, URIOUNIT(dev)));
314 
315 	if (sc->sc_in_pipe != NULL) {
316 		usbd_abort_pipe(sc->sc_in_pipe);
317 		usbd_close_pipe(sc->sc_in_pipe);
318 		sc->sc_in_pipe = NULL;
319 	}
320 	if (sc->sc_out_pipe != NULL) {
321 		usbd_abort_pipe(sc->sc_out_pipe);
322 		usbd_close_pipe(sc->sc_out_pipe);
323 		sc->sc_out_pipe = NULL;
324 	}
325 
326 	return 0;
327 }
328 
329 int
urioread(dev_t dev,struct uio * uio,int flag)330 urioread(dev_t dev, struct uio *uio, int flag)
331 {
332 	struct urio_softc *sc;
333 	struct usbd_xfer *xfer;
334 	usbd_status err;
335 	void *bufp;
336 	uint32_t n, tn;
337 	int error = 0;
338 
339 	sc = device_lookup_private(&urio_cd, URIOUNIT(dev));
340 
341 	DPRINTFN(5, ("urioread: %d\n", URIOUNIT(dev)));
342 
343 	if (sc->sc_dying)
344 		return EIO;
345 
346 	error = usbd_create_xfer(sc->sc_in_pipe, URIO_BSIZE, 0, 0, &xfer);
347 	if (error) {
348 		return error;
349 	}
350 	bufp = usbd_get_buffer(xfer);
351 
352 	sc->sc_refcnt++;
353 
354 	while ((n = min(URIO_BSIZE, uio->uio_resid)) != 0) {
355 		DPRINTFN(1, ("urioread: start transfer %d bytes\n", n));
356 		tn = n;
357 		err = usbd_bulk_transfer(xfer, sc->sc_in_pipe, 0,
358 			  URIO_RW_TIMEOUT, bufp, &tn);
359 		if (err) {
360 			if (err == USBD_INTERRUPTED)
361 				error = EINTR;
362 			else if (err == USBD_TIMEOUT)
363 				error = ETIMEDOUT;
364 			else
365 				error = EIO;
366 			break;
367 		}
368 
369 		DPRINTFN(1, ("urioread: got %d bytes\n", tn));
370 
371 		error = uiomove(bufp, tn, uio);
372 		if (error || tn < n)
373 			break;
374 	}
375 	usbd_destroy_xfer(xfer);
376 
377 	if (--sc->sc_refcnt < 0)
378 		usb_detach_wakeupold(sc->sc_dev);
379 
380 	return error;
381 }
382 
383 int
uriowrite(dev_t dev,struct uio * uio,int flag)384 uriowrite(dev_t dev, struct uio *uio, int flag)
385 {
386 	struct urio_softc *sc;
387 	struct usbd_xfer *xfer;
388 	usbd_status err;
389 	void *bufp;
390 	uint32_t n;
391 	int error = 0;
392 
393 	sc = device_lookup_private(&urio_cd, URIOUNIT(dev));
394 
395 	DPRINTFN(5, ("uriowrite: unit=%d, len=%ld\n", URIOUNIT(dev),
396 		     (long)uio->uio_resid));
397 
398 	if (sc->sc_dying)
399 		return EIO;
400 
401 	error = usbd_create_xfer(sc->sc_out_pipe, URIO_BSIZE, 0, 0, &xfer);
402 	if (error) {
403 		return error;
404 	}
405 	bufp = usbd_get_buffer(xfer);
406 	sc->sc_refcnt++;
407 
408 	while ((n = min(URIO_BSIZE, uio->uio_resid)) != 0) {
409 		error = uiomove(bufp, n, uio);
410 		if (error)
411 			break;
412 
413 		DPRINTFN(1, ("uriowrite: transfer %d bytes\n", n));
414 
415 		err = usbd_bulk_transfer(xfer, sc->sc_out_pipe, 0,
416 			  URIO_RW_TIMEOUT, bufp, &n);
417 		DPRINTFN(2, ("uriowrite: err=%d\n", err));
418 		if (err) {
419 			if (err == USBD_INTERRUPTED)
420 				error = EINTR;
421 			else if (err == USBD_TIMEOUT)
422 				error = ETIMEDOUT;
423 			else
424 				error = EIO;
425 			break;
426 		}
427 	}
428 
429 	usbd_destroy_xfer(xfer);
430 
431 	if (--sc->sc_refcnt < 0)
432 		usb_detach_wakeupold(sc->sc_dev);
433 
434 	DPRINTFN(5, ("uriowrite: done unit=%d, error=%d\n", URIOUNIT(dev),
435 		     error));
436 
437 	return error;
438 }
439 
440 
441 int
urioioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)442 urioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
443 {
444 	struct urio_softc * sc;
445 	int unit = URIOUNIT(dev);
446 	struct urio_command *rcmd;
447 	int requesttype, len;
448 	struct iovec iov;
449 	struct uio uio;
450 	usb_device_request_t req;
451 	usbd_status err;
452 	int req_flags = 0;
453 	uint32_t req_actlen = 0;
454 	void *ptr = NULL;
455 	int error = 0;
456 
457 	sc = device_lookup_private(&urio_cd, unit);
458 
459 	if (sc->sc_dying)
460 		return EIO;
461 
462 	rcmd = (struct urio_command *)addr;
463 
464 	switch (cmd) {
465 	case URIO_RECV_COMMAND:
466 		requesttype = rcmd->requesttype | UT_READ_VENDOR_DEVICE;
467 		break;
468 
469 	case URIO_SEND_COMMAND:
470 		requesttype = rcmd->requesttype | UT_WRITE_VENDOR_DEVICE;
471 		break;
472 
473 	default:
474 		return EINVAL;
475 		break;
476 	}
477 
478 	if (!(flag & FWRITE))
479 		return EPERM;
480 	len = rcmd->length;
481 
482 	DPRINTFN(1,("urio_ioctl: cmd=0x%08lx reqtype=0x%0x req=0x%0x "
483 		    "value=0x%0x index=0x%0x len=0x%0x\n",
484 		    cmd, requesttype, rcmd->request, rcmd->value,
485 		    rcmd->index, len));
486 
487 	/* Send rio control message */
488 	req.bmRequestType = requesttype;
489 	req.bRequest = rcmd->request;
490 	USETW(req.wValue, rcmd->value);
491 	USETW(req.wIndex, rcmd->index);
492 	USETW(req.wLength, len);
493 
494 	if (len < 0 || len > 32767)
495 		return EINVAL;
496 	if (len != 0) {
497 		iov.iov_base = (void *)rcmd->buffer;
498 		iov.iov_len = len;
499 		uio.uio_iov = &iov;
500 		uio.uio_iovcnt = 1;
501 		uio.uio_resid = len;
502 		uio.uio_offset = 0;
503 		uio.uio_rw = req.bmRequestType & UT_READ ?
504 			     UIO_READ : UIO_WRITE;
505 		uio.uio_vmspace = l->l_proc->p_vmspace;
506 		ptr = kmem_alloc(len, KM_SLEEP);
507 		if (uio.uio_rw == UIO_WRITE) {
508 			error = uiomove(ptr, len, &uio);
509 			if (error)
510 				goto ret;
511 		}
512 	}
513 
514 	sc->sc_refcnt++;
515 
516 	err = usbd_do_request_flags(sc->sc_udev, &req, ptr, req_flags,
517 		  &req_actlen, USBD_DEFAULT_TIMEOUT);
518 
519 	if (--sc->sc_refcnt < 0)
520 		usb_detach_wakeupold(sc->sc_dev);
521 
522 	if (err) {
523 		error = EIO;
524 	} else {
525 		if (len != 0 && uio.uio_rw == UIO_READ)
526 			error = uiomove(ptr, len, &uio);
527 	}
528 
529 ret:
530 	if (ptr != NULL)
531 		kmem_free(ptr, len);
532 	return error;
533 }
534