summaryrefslogtreecommitdiff
path: root/sys/dev/usb/uhid.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/uhid.c')
-rw-r--r--sys/dev/usb/uhid.c546
1 files changed, 0 insertions, 546 deletions
diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c
deleted file mode 100644
index 26c0e5b5b20f..000000000000
--- a/sys/dev/usb/uhid.c
+++ /dev/null
@@ -1,546 +0,0 @@
-/* $NetBSD: uhid.c,v 1.14 1999/01/08 11:58:25 augustss Exp $ */
-/* $FreeBSD$ */
-
-/*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson (augustss@carlstedt.se) at
- * Carlstedt Research & Technology.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#if defined(__NetBSD__)
-#include <sys/device.h>
-#include <sys/ioctl.h>
-#elif defined(__FreeBSD__)
-#include <sys/ioccom.h>
-#include <sys/filio.h>
-#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/ioccom.h>
-#endif
-#include <sys/tty.h>
-#include <sys/file.h>
-#include <sys/select.h>
-#include <sys/proc.h>
-#include <sys/vnode.h>
-#include <sys/poll.h>
-
-#include <dev/usb/usb.h>
-#include <dev/usb/usbhid.h>
-
-#include <dev/usb/usbdi.h>
-#include <dev/usb/usbdi_util.h>
-#include <dev/usb/hid.h>
-#include <dev/usb/usb_quirks.h>
-
-#ifdef USB_DEBUG
-#define DPRINTF(x) if (uhiddebug) printf x
-#define DPRINTFN(n,x) if (uhiddebug>(n)) printf x
-int uhiddebug = 1;
-#else
-#define DPRINTF(x)
-#define DPRINTFN(n,x)
-#endif
-
-struct uhid_softc {
- bdevice sc_dev; /* base device */
- usbd_interface_handle sc_iface; /* interface */
- usbd_pipe_handle sc_intrpipe; /* interrupt pipe */
- int sc_ep_addr;
-
- int sc_isize;
- int sc_osize;
- int sc_fsize;
- u_int8_t sc_iid;
- u_int8_t sc_oid;
- u_int8_t sc_fid;
-
- char *sc_ibuf;
- char *sc_obuf;
-
- void *sc_repdesc;
- int sc_repdesc_size;
-
- struct clist sc_q;
- struct selinfo sc_rsel;
- u_char sc_state; /* driver state */
-#define UHID_OPEN 0x01 /* device is open */
-#define UHID_ASLP 0x02 /* waiting for device data */
-#define UHID_NEEDCLEAR 0x04 /* needs clearing endpoint stall */
-#define UHID_IMMED 0x08 /* return read data immediately */
- int sc_disconnected; /* device is gone */
-};
-
-#define UHIDUNIT(dev) (minor(dev))
-#define UHID_CHUNK 128 /* chunk size for read */
-#define UHID_BSIZE 1020 /* buffer size */
-
-int uhidopen __P((dev_t, int, int, struct proc *));
-int uhidclose __P((dev_t, int, int, struct proc *p));
-int uhidread __P((dev_t, struct uio *uio, int));
-int uhidwrite __P((dev_t, struct uio *uio, int));
-int uhidioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
-int uhidpoll __P((dev_t, int, struct proc *));
-void uhid_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
-void uhid_disco __P((void *));
-
-USB_DECLARE_DRIVER(uhid);
-
-USB_MATCH(uhid)
-{
- USB_MATCH_START(uhid, uaa);
- usb_interface_descriptor_t *id;
-
- if (!uaa->iface)
- return (UMATCH_NONE);
- id = usbd_get_interface_descriptor(uaa->iface);
- if (!id || id->bInterfaceClass != UCLASS_HID)
- return (UMATCH_NONE);
- return (UMATCH_IFACECLASS_GENERIC);
-}
-
-USB_ATTACH(uhid)
-{
- USB_ATTACH_START(uhid, sc, uaa);
- usbd_interface_handle iface = uaa->iface;
- usb_interface_descriptor_t *id;
- usb_endpoint_descriptor_t *ed;
- int size;
- void *desc;
- usbd_status r;
- char devinfo[1024];
-
- sc->sc_disconnected = 1;
- sc->sc_iface = iface;
- id = usbd_get_interface_descriptor(iface);
- usbd_devinfo(uaa->device, 0, devinfo);
- USB_ATTACH_SETUP;
- printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev),
- devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
-
- ed = usbd_interface2endpoint_descriptor(iface, 0);
- if (!ed) {
- printf("%s: could not read endpoint descriptor\n",
- USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
- }
-
- DPRINTFN(10,("uhid_attach: bLength=%d bDescriptorType=%d "
- "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
- " bInterval=%d\n",
- ed->bLength, ed->bDescriptorType,
- ed->bEndpointAddress & UE_ADDR,
- ed->bEndpointAddress & UE_IN ? "in" : "out",
- ed->bmAttributes & UE_XFERTYPE,
- UGETW(ed->wMaxPacketSize), ed->bInterval));
-
- if ((ed->bEndpointAddress & UE_IN) != UE_IN ||
- (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
- printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
- }
-
- sc->sc_ep_addr = ed->bEndpointAddress;
- sc->sc_disconnected = 0;
-
- r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_USB);
- if (r != USBD_NORMAL_COMPLETION) {
- printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev));
- USB_ATTACH_ERROR_RETURN;
- }
-
- (void)usbd_set_idle(iface, 0, 0);
-
- sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid);
- sc->sc_osize = hid_report_size(desc, size, hid_output, &sc->sc_oid);
- sc->sc_fsize = hid_report_size(desc, size, hid_feature, &sc->sc_fid);
-
- sc->sc_repdesc = desc;
- sc->sc_repdesc_size = size;
-
- USB_ATTACH_SUCCESS_RETURN;
-}
-
-#if defined(__FreeBSD__)
-static int
-uhid_detach(device_t self)
-{
- char *devinfo = (char *) device_get_desc(self);
-
- if (devinfo) {
- device_set_desc(self, NULL);
- free(devinfo, M_USB);
- }
- return 0;
-}
-#endif
-
-void
-uhid_disco(p)
- void *p;
-{
- struct uhid_softc *sc = p;
-
- DPRINTF(("ums_hid: sc=%p\n", sc));
- usbd_abort_pipe(sc->sc_intrpipe);
- sc->sc_disconnected = 1;
-}
-
-void
-uhid_intr(reqh, addr, status)
- usbd_request_handle reqh;
- usbd_private_handle addr;
- usbd_status status;
-{
- struct uhid_softc *sc = addr;
-
- DPRINTFN(5, ("uhid_intr: status=%d\n", status));
- DPRINTFN(5, ("uhid_intr: data = %02x %02x %02x\n",
- sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2]));
-
- if (status == USBD_CANCELLED)
- return;
-
- if (status != USBD_NORMAL_COMPLETION) {
- DPRINTF(("uhid_intr: status=%d\n", status));
- sc->sc_state |= UHID_NEEDCLEAR;
- return;
- }
-
- (void) b_to_q(sc->sc_ibuf, sc->sc_isize, &sc->sc_q);
-
- if (sc->sc_state & UHID_ASLP) {
- sc->sc_state &= ~UHID_ASLP;
- DPRINTFN(5, ("uhid_intr: waking %p\n", sc));
- wakeup((caddr_t)sc);
- }
- selwakeup(&sc->sc_rsel);
-}
-
-int
-uhidopen(dev, flag, mode, p)
- dev_t dev;
- int flag;
- int mode;
- struct proc *p;
-{
- usbd_status r;
- USB_GET_SC_OPEN(uhid, UHIDUNIT(dev), sc);
-
- if (!sc)
- return (ENXIO);
-
- DPRINTF(("uhidopen: sc=%p, disco=%d\n", sc, sc->sc_disconnected));
-
- if (sc->sc_disconnected)
- return (EIO);
-
- if (sc->sc_state & UHID_OPEN)
- return (EBUSY);
-
-#if defined(__NetBSD__)
- if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1)
- return (ENOMEM);
-#elif defined(__FreeBSD__)
- clist_alloc_cblocks(&sc->sc_q, UHID_BSIZE, 0);
-#endif
-
- sc->sc_state |= UHID_OPEN;
- sc->sc_state &= ~UHID_IMMED;
-
- sc->sc_ibuf = malloc(sc->sc_isize, M_USB, M_WAITOK);
- sc->sc_obuf = malloc(sc->sc_osize, M_USB, M_WAITOK);
-
- /* Set up interrupt pipe. */
- r = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr,
- USBD_SHORT_XFER_OK,
- &sc->sc_intrpipe, sc, sc->sc_ibuf,
- sc->sc_isize, uhid_intr);
- if (r != USBD_NORMAL_COMPLETION) {
- DPRINTF(("uhidopen: usbd_open_pipe_intr failed, "
- "error=%d\n",r));
- sc->sc_state &= ~UHID_OPEN;
- return (EIO);
- }
- usbd_set_disco(sc->sc_intrpipe, uhid_disco, sc);
-
- return (0);
-}
-
-int
-uhidclose(dev, flag, mode, p)
- dev_t dev;
- int flag;
- int mode;
- struct proc *p;
-{
- USB_GET_SC(uhid, UHIDUNIT(dev), sc);
-
- if (sc->sc_disconnected)
- return (EIO);
-
- DPRINTF(("uhidclose: sc=%p\n", sc));
-
- /* Disable interrupts. */
- usbd_abort_pipe(sc->sc_intrpipe);
- usbd_close_pipe(sc->sc_intrpipe);
-
- sc->sc_state &= ~UHID_OPEN;
-
-#if defined(__NetBSD__)
- clfree(&sc->sc_q);
-#elif defined(__FreeBSD__)
- clist_free_cblocks(&sc->sc_q);
-#endif
-
- free(sc->sc_ibuf, M_USB);
- free(sc->sc_obuf, M_USB);
-
- return (0);
-}
-
-int
-uhidread(dev, uio, flag)
- dev_t dev;
- struct uio *uio;
- int flag;
-{
- int s;
- int error = 0;
- size_t length;
- u_char buffer[UHID_CHUNK];
- usbd_status r;
- USB_GET_SC(uhid, UHIDUNIT(dev), sc);
-
- if (sc->sc_disconnected)
- return (EIO);
-
- DPRINTFN(1, ("uhidread\n"));
- if (sc->sc_state & UHID_IMMED) {
- DPRINTFN(1, ("uhidread immed\n"));
-
- r = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT,
- sc->sc_iid, sc->sc_ibuf, sc->sc_isize);
- if (r != USBD_NORMAL_COMPLETION)
- return (EIO);
- return (uiomove(buffer, sc->sc_isize, uio));
- }
-
- s = splusb();
- while (sc->sc_q.c_cc == 0) {
- if (flag & IO_NDELAY) {
- splx(s);
- return EWOULDBLOCK;
- }
- sc->sc_state |= UHID_ASLP;
- DPRINTFN(5, ("uhidread: sleep on %p\n", sc));
- error = tsleep((caddr_t)sc, PZERO | PCATCH, "uhidrea", 0);
- DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
- if (error) {
- sc->sc_state &= ~UHID_ASLP;
- splx(s);
- return (error);
- }
- if (sc->sc_state & UHID_NEEDCLEAR) {
- DPRINTFN(-1,("uhidread: clearing stall\n"));
- sc->sc_state &= ~UHID_NEEDCLEAR;
- usbd_clear_endpoint_stall(sc->sc_intrpipe);
- }
- }
- splx(s);
-
- /* Transfer as many chunks as possible. */
- while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) {
- length = min(sc->sc_q.c_cc, uio->uio_resid);
- if (length > sizeof(buffer))
- length = sizeof(buffer);
-
- /* Remove a small chunk from the input queue. */
- (void) q_to_b(&sc->sc_q, buffer, length);
- DPRINTFN(5, ("uhidread: got %d chars\n", length));
-
- /* Copy the data to the user process. */
- if ((error = uiomove(buffer, length, uio)) != 0)
- break;
- }
-
- return (error);
-}
-
-int
-uhidwrite(dev, uio, flag)
- dev_t dev;
- struct uio *uio;
- int flag;
-{
- int error;
- int size;
- usbd_status r;
- USB_GET_SC(uhid, UHIDUNIT(dev), sc);
-
- if (sc->sc_disconnected)
- return (EIO);
-
- DPRINTFN(1, ("uhidwrite\n"));
-
- size = sc->sc_osize;
- error = 0;
- while (uio->uio_resid > 0) {
- if (uio->uio_resid != size)
- return (0);
- if ((error = uiomove(sc->sc_obuf, size, uio)) != 0)
- break;
- if (sc->sc_oid)
- r = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT,
- sc->sc_obuf[0],
- sc->sc_obuf+1, size-1);
- else
- r = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT,
- 0, sc->sc_obuf, size);
- if (r != USBD_NORMAL_COMPLETION) {
- error = EIO;
- break;
- }
- }
- return (error);
-}
-
-int
-uhidioctl(dev, cmd, addr, flag, p)
- dev_t dev;
- u_long cmd;
- caddr_t addr;
- int flag;
- struct proc *p;
-{
- struct usb_ctl_report_desc *rd;
- struct usb_ctl_report *re;
- int size, id;
- usbd_status r;
- USB_GET_SC(uhid, UHIDUNIT(dev), sc);
-
- if (sc->sc_disconnected)
- return (EIO);
-
- DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
- switch (cmd) {
- case FIONBIO:
- /* All handled in the upper FS layer. */
- break;
-
- case USB_GET_REPORT_DESC:
- rd = (struct usb_ctl_report_desc *)addr;
- size = min(sc->sc_repdesc_size, sizeof rd->data);
- rd->size = size;
- memcpy(rd->data, sc->sc_repdesc, size);
- break;
-
- case USB_SET_IMMED:
- if (*(int *)addr) {
- /* XXX should read into ibuf, but does it matter */
- r = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT,
- sc->sc_iid, sc->sc_ibuf,
- sc->sc_isize);
- if (r != USBD_NORMAL_COMPLETION)
- return (EOPNOTSUPP);
-
- sc->sc_state |= UHID_IMMED;
- } else
- sc->sc_state &= ~UHID_IMMED;
- break;
-
- case USB_GET_REPORT:
- re = (struct usb_ctl_report *)addr;
- switch (re->report) {
- case UHID_INPUT_REPORT:
- size = sc->sc_isize;
- id = sc->sc_iid;
- break;
- case UHID_OUTPUT_REPORT:
- size = sc->sc_osize;
- id = sc->sc_oid;
- break;
- case UHID_FEATURE_REPORT:
- size = sc->sc_fsize;
- id = sc->sc_fid;
- break;
- default:
- return (EINVAL);
- }
- r = usbd_get_report(sc->sc_iface, re->report, id,
- re->data, size);
- if (r != USBD_NORMAL_COMPLETION)
- return (EIO);
- break;
-
- default:
- return (EINVAL);
- }
- return (0);
-}
-
-int
-uhidpoll(dev, events, p)
- dev_t dev;
- int events;
- struct proc *p;
-{
- int revents = 0;
- int s;
- USB_GET_SC(uhid, UHIDUNIT(dev), sc);
-
- if (sc->sc_disconnected)
- return (EIO);
-
- s = splusb();
- if (events & (POLLOUT | POLLWRNORM))
- revents |= events & (POLLOUT | POLLWRNORM);
- if (events & (POLLIN | POLLRDNORM)) {
- if (sc->sc_q.c_cc > 0)
- revents |= events & (POLLIN | POLLRDNORM);
- else
- selrecord(p, &sc->sc_rsel);
- }
-
- splx(s);
- return (revents);
-}
-
-#if defined(__FreeBSD__)
-DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, 0);
-#endif