ums.c revision 1.16
11.16Saugustss/* $NetBSD: ums.c,v 1.16 1998/12/26 12:53:03 augustss Exp $ */ 21.1Saugustss 31.1Saugustss/* 41.1Saugustss * Copyright (c) 1998 The NetBSD Foundation, Inc. 51.1Saugustss * All rights reserved. 61.1Saugustss * 71.11Saugustss * This code is derived from software contributed to The NetBSD Foundation 81.11Saugustss * by Lennart Augustsson (augustss@carlstedt.se) at 91.11Saugustss * Carlstedt Research & Technology. 101.1Saugustss * 111.1Saugustss * Redistribution and use in source and binary forms, with or without 121.1Saugustss * modification, are permitted provided that the following conditions 131.1Saugustss * are met: 141.1Saugustss * 1. Redistributions of source code must retain the above copyright 151.1Saugustss * notice, this list of conditions and the following disclaimer. 161.1Saugustss * 2. Redistributions in binary form must reproduce the above copyright 171.1Saugustss * notice, this list of conditions and the following disclaimer in the 181.1Saugustss * documentation and/or other materials provided with the distribution. 191.1Saugustss * 3. All advertising materials mentioning features or use of this software 201.1Saugustss * must display the following acknowledgement: 211.1Saugustss * This product includes software developed by the NetBSD 221.1Saugustss * Foundation, Inc. and its contributors. 231.1Saugustss * 4. Neither the name of The NetBSD Foundation nor the names of its 241.1Saugustss * contributors may be used to endorse or promote products derived 251.1Saugustss * from this software without specific prior written permission. 261.1Saugustss * 271.1Saugustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 281.1Saugustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 291.1Saugustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 301.1Saugustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 311.1Saugustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 321.1Saugustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 331.1Saugustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 341.1Saugustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 351.1Saugustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 361.1Saugustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 371.1Saugustss * POSSIBILITY OF SUCH DAMAGE. 381.1Saugustss */ 391.1Saugustss 401.1Saugustss#include <sys/param.h> 411.1Saugustss#include <sys/systm.h> 421.1Saugustss#include <sys/kernel.h> 431.1Saugustss#include <sys/malloc.h> 441.16Saugustss#if defined(__NetBSD__) 451.1Saugustss#include <sys/device.h> 461.1Saugustss#include <sys/ioctl.h> 471.16Saugustss#elif defined(__FreeBSD__) 481.16Saugustss#include <sys/module.h> 491.16Saugustss#include <sys/bus.h> 501.16Saugustss#include <sys/ioccom.h> 511.16Saugustss#include <sys/conf.h> 521.16Saugustss#endif 531.1Saugustss#include <sys/tty.h> 541.1Saugustss#include <sys/file.h> 551.1Saugustss#include <sys/select.h> 561.1Saugustss#include <sys/proc.h> 571.1Saugustss#include <sys/vnode.h> 581.1Saugustss#include <sys/poll.h> 591.1Saugustss 601.1Saugustss#include <dev/usb/usb.h> 611.1Saugustss#include <dev/usb/usbhid.h> 621.1Saugustss 631.1Saugustss#include <dev/usb/usbdi.h> 641.16Saugustss#include <dev/usb/usbdivar.h> 651.1Saugustss#include <dev/usb/usbdi_util.h> 661.1Saugustss#include <dev/usb/usbdevs.h> 671.1Saugustss#include <dev/usb/usb_quirks.h> 681.1Saugustss#include <dev/usb/hid.h> 691.1Saugustss 701.16Saugustss#if defined(__NetBSD__) 711.3Saugustss#include <dev/wscons/wsconsio.h> 721.3Saugustss#include <dev/wscons/wsmousevar.h> 731.16Saugustss#elif defined(__FreeBSD__) 741.16Saugustss#include <machine/mouse.h> 751.16Saugustss#endif 761.3Saugustss 771.1Saugustss#ifdef USB_DEBUG 781.1Saugustss#define DPRINTF(x) if (umsdebug) printf x 791.1Saugustss#define DPRINTFN(n,x) if (umsdebug>(n)) printf x 801.1Saugustssint umsdebug = 0; 811.1Saugustss#else 821.1Saugustss#define DPRINTF(x) 831.1Saugustss#define DPRINTFN(n,x) 841.1Saugustss#endif 851.1Saugustss 861.16Saugustss#define UMSUNIT(s) (minor(s)&0x1f) 871.16Saugustss 881.16Saugustss#define PS2LBUTMASK x01 891.16Saugustss#define PS2RBUTMASK x02 901.16Saugustss#define PS2MBUTMASK x04 911.1Saugustss#define PS2BUTMASK 0x0f 921.1Saugustss 931.16Saugustss#define QUEUE_BUFSIZE 240 /* MUST be divisible by 3 _and_ 4 */ 941.16Saugustss 951.1Saugustssstruct ums_softc { 961.16Saugustss bdevice sc_dev; /* base device */ 971.1Saugustss usbd_interface_handle sc_iface; /* interface */ 981.1Saugustss usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ 991.1Saugustss int sc_ep_addr; 1001.1Saugustss 1011.1Saugustss u_char *sc_ibuf; 1021.1Saugustss u_int8_t sc_iid; 1031.1Saugustss int sc_isize; 1041.16Saugustss struct hid_location sc_loc_x, sc_loc_y, sc_loc_z; 1051.16Saugustss struct hid_location *sc_loc_btn; 1061.1Saugustss 1071.16Saugustss int sc_enabled; 1081.1Saugustss int sc_disconnected; /* device is gone */ 1091.3Saugustss 1101.16Saugustss int flags; /* device configuration */ 1111.16Saugustss#define UMS_Z 0x01 /* z direction available */ 1121.16Saugustss int nbuttons; 1131.16Saugustss 1141.16Saugustss#if defined(__NetBSD__) 1151.16Saugustss u_char sc_buttons; /* mouse button status */ 1161.3Saugustss struct device *sc_wsmousedev; 1171.16Saugustss#elif defined(__FreeBSD__) 1181.16Saugustss u_char qbuf[QUEUE_BUFSIZE]; 1191.16Saugustss u_char dummy[100]; /* just for safety and for now */ 1201.16Saugustss int qcount, qhead, qtail; 1211.16Saugustss mousehw_t hw; 1221.16Saugustss mousemode_t mode; 1231.16Saugustss mousestatus_t status; 1241.16Saugustss 1251.16Saugustss int state; 1261.16Saugustss# define UMS_ASLEEP 0x01 /* readFromDevice is waiting */ 1271.16Saugustss# define UMS_SELECT 0x02 /* select is waiting */ 1281.16Saugustss struct selinfo rsel; /* process waiting in select */ 1291.16Saugustss#endif 1301.1Saugustss}; 1311.1Saugustss 1321.2Saugustss#define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE) 1331.2Saugustss#define MOUSE_FLAGS (HIO_RELATIVE) 1341.2Saugustss 1351.1Saugustssvoid ums_intr __P((usbd_request_handle, usbd_private_handle, usbd_status)); 1361.1Saugustssvoid ums_disco __P((void *)); 1371.1Saugustss 1381.16Saugustssstatic int ums_enable __P((void *)); 1391.16Saugustssstatic void ums_disable __P((void *)); 1401.16Saugustss 1411.16Saugustss#if defined(__NetBSD__) 1421.16Saugustssstatic int ums_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 1431.3Saugustss 1441.3Saugustssconst struct wsmouse_accessops ums_accessops = { 1451.3Saugustss ums_enable, 1461.3Saugustss ums_ioctl, 1471.3Saugustss ums_disable, 1481.3Saugustss}; 1491.3Saugustss 1501.16Saugustss#elif defined(__FreeBSD__) 1511.16Saugustssstatic d_open_t ums_open; 1521.16Saugustssstatic d_close_t ums_close; 1531.16Saugustssstatic d_read_t ums_read; 1541.16Saugustssstatic d_ioctl_t ums_ioctl; 1551.16Saugustssstatic d_poll_t ums_poll; 1561.16Saugustss 1571.16Saugustss#define UMS_CDEV_MAJOR 138 /* XXX NWH should be requested */ 1581.16Saugustss 1591.16Saugustssstatic struct cdevsw ums_cdevsw = { 1601.16Saugustss ums_open, ums_close, ums_read, nowrite, 1611.16Saugustss ums_ioctl, nostop, nullreset, nodevtotty, 1621.16Saugustss ums_poll, nommap, 1631.16Saugustss NULL, "ums_", NULL, -1 1641.16Saugustss}; 1651.16Saugustss#endif 1661.1Saugustss 1671.16SaugustssUSB_DECLARE_DRIVER(ums); 1681.1Saugustss 1691.16SaugustssUSB_MATCH(ums) 1701.1Saugustss{ 1711.16Saugustss USB_MATCH_START(ums, uaa); 1721.1Saugustss usb_interface_descriptor_t *id; 1731.1Saugustss int size, ret; 1741.1Saugustss void *desc; 1751.1Saugustss usbd_status r; 1761.1Saugustss 1771.1Saugustss if (!uaa->iface) 1781.1Saugustss return (UMATCH_NONE); 1791.1Saugustss id = usbd_get_interface_descriptor(uaa->iface); 1801.14Saugustss if (!id || id->bInterfaceClass != UCLASS_HID) 1811.1Saugustss return (UMATCH_NONE); 1821.1Saugustss 1831.1Saugustss r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP); 1841.1Saugustss if (r != USBD_NORMAL_COMPLETION) 1851.1Saugustss return (UMATCH_NONE); 1861.1Saugustss 1871.1Saugustss if (hid_is_collection(desc, size, 1881.1Saugustss HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) 1891.1Saugustss ret = UMATCH_IFACECLASS; 1901.1Saugustss else 1911.1Saugustss ret = UMATCH_NONE; 1921.1Saugustss 1931.1Saugustss free(desc, M_TEMP); 1941.1Saugustss return (ret); 1951.1Saugustss} 1961.1Saugustss 1971.16SaugustssUSB_ATTACH(ums) 1981.1Saugustss{ 1991.16Saugustss USB_ATTACH_START(ums, sc, uaa); 2001.1Saugustss usbd_interface_handle iface = uaa->iface; 2011.1Saugustss usb_interface_descriptor_t *id; 2021.1Saugustss usb_endpoint_descriptor_t *ed; 2031.3Saugustss struct wsmousedev_attach_args a; 2041.1Saugustss int size; 2051.1Saugustss void *desc; 2061.1Saugustss usbd_status r; 2071.1Saugustss char devinfo[1024]; 2081.2Saugustss u_int32_t flags; 2091.16Saugustss int i; 2101.16Saugustss struct hid_location loc_btn; 2111.1Saugustss 2121.1Saugustss sc->sc_disconnected = 1; 2131.1Saugustss sc->sc_iface = iface; 2141.1Saugustss id = usbd_get_interface_descriptor(iface); 2151.1Saugustss usbd_devinfo(uaa->device, 0, devinfo); 2161.16Saugustss USB_ATTACH_SETUP; 2171.16Saugustss printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), 2181.12Saugustss devinfo, id->bInterfaceClass, id->bInterfaceSubClass); 2191.1Saugustss ed = usbd_interface2endpoint_descriptor(iface, 0); 2201.1Saugustss if (!ed) { 2211.1Saugustss printf("%s: could not read endpoint descriptor\n", 2221.16Saugustss USBDEVNAME(sc->sc_dev)); 2231.16Saugustss USB_ATTACH_ERROR_RETURN; 2241.1Saugustss } 2251.1Saugustss 2261.15Saugustss DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d " 2271.15Saugustss "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" 2281.15Saugustss " bInterval=%d\n", 2291.15Saugustss ed->bLength, ed->bDescriptorType, 2301.15Saugustss ed->bEndpointAddress & UE_ADDR, 2311.15Saugustss ed->bEndpointAddress & UE_IN ? "in" : "out", 2321.15Saugustss ed->bmAttributes & UE_XFERTYPE, 2331.15Saugustss UGETW(ed->wMaxPacketSize), ed->bInterval)); 2341.1Saugustss 2351.1Saugustss if ((ed->bEndpointAddress & UE_IN) != UE_IN || 2361.1Saugustss (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { 2371.1Saugustss printf("%s: unexpected endpoint\n", 2381.16Saugustss USBDEVNAME(sc->sc_dev)); 2391.16Saugustss USB_ATTACH_ERROR_RETURN; 2401.1Saugustss } 2411.1Saugustss 2421.1Saugustss r = usbd_alloc_report_desc(uaa->iface, &desc, &size, M_TEMP); 2431.1Saugustss if (r != USBD_NORMAL_COMPLETION) 2441.16Saugustss USB_ATTACH_ERROR_RETURN; 2451.16Saugustss 2461.2Saugustss if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), 2471.2Saugustss hid_input, &sc->sc_loc_x, &flags)) { 2481.16Saugustss printf("%s: mouse has no X report\n", USBDEVNAME(sc->sc_dev)); 2491.16Saugustss USB_ATTACH_ERROR_RETURN; 2501.16Saugustss } 2511.16Saugustss if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { 2521.16Saugustss printf("%s: X report 0x%04x not supported\n", 2531.16Saugustss USBDEVNAME(sc->sc_dev), flags); 2541.16Saugustss USB_ATTACH_ERROR_RETURN; 2551.1Saugustss } 2561.10Saugustss 2571.2Saugustss if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), 2581.2Saugustss hid_input, &sc->sc_loc_y, &flags)) { 2591.16Saugustss printf("%s: mouse has no Y report\n", USBDEVNAME(sc->sc_dev)); 2601.16Saugustss USB_ATTACH_ERROR_RETURN; 2611.16Saugustss } 2621.16Saugustss if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { 2631.16Saugustss printf("%s: Y report 0x%04x not supported\n", 2641.16Saugustss USBDEVNAME(sc->sc_dev), flags); 2651.16Saugustss USB_ATTACH_ERROR_RETURN; 2661.1Saugustss } 2671.10Saugustss 2681.16Saugustss /* try to guess the Z activator: first check Z, then WHEEL */ 2691.6Saugustss if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), 2701.6Saugustss hid_input, &sc->sc_loc_z, &flags) || 2711.6Saugustss hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), 2721.6Saugustss hid_input, &sc->sc_loc_z, &flags)) { 2731.16Saugustss if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { 2741.16Saugustss sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */ 2751.16Saugustss } else { 2761.16Saugustss sc->flags |= UMS_Z; 2771.16Saugustss } 2781.6Saugustss } 2791.6Saugustss 2801.16Saugustss /* figure out the number of buttons, 7 is an arbitrary limit */ 2811.16Saugustss for (i = 1; i <= 7; i++) 2821.16Saugustss if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), 2831.16Saugustss hid_input, &loc_btn, 0)) 2841.16Saugustss break; 2851.16Saugustss sc->nbuttons = i - 1; 2861.16Saugustss sc->sc_loc_btn = malloc(sizeof(struct hid_location)*sc->nbuttons, 2871.16Saugustss M_USBDEV, M_NOWAIT); 2881.16Saugustss if (!sc->sc_loc_btn) 2891.16Saugustss USB_ATTACH_ERROR_RETURN; 2901.16Saugustss 2911.16Saugustss printf("%s: %d buttons%s\n", USBDEVNAME(sc->sc_dev), 2921.16Saugustss sc->nbuttons, (sc->flags & UMS_Z? " and Z dir." : "")); 2931.16Saugustss 2941.16Saugustss for (i = 1; i <= sc->nbuttons; i++) 2951.16Saugustss hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), 2961.16Saugustss hid_input, &sc->sc_loc_btn[i-1], 0); 2971.1Saugustss 2981.1Saugustss sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid); 2991.1Saugustss sc->sc_ibuf = malloc(sc->sc_isize, M_USB, M_NOWAIT); 3001.16Saugustss if (!sc->sc_ibuf) { 3011.16Saugustss free(sc->sc_loc_btn, M_USB); 3021.16Saugustss USB_ATTACH_ERROR_RETURN; 3031.16Saugustss } 3041.1Saugustss 3051.1Saugustss sc->sc_ep_addr = ed->bEndpointAddress; 3061.1Saugustss sc->sc_disconnected = 0; 3071.1Saugustss free(desc, M_TEMP); 3081.3Saugustss 3091.16Saugustss#ifdef USB_DEBUG 3101.16Saugustss DPRINTF(("ums_attach: sc=%p\n", sc)); 3111.16Saugustss DPRINTF(("ums_attach: X\t%d/%d\n", 3121.16Saugustss sc->sc_loc_x.pos, sc->sc_loc_x.size)); 3131.16Saugustss DPRINTF(("ums_attach: Y\t%d/%d\n", 3141.16Saugustss sc->sc_loc_x.pos, sc->sc_loc_x.size)); 3151.16Saugustss if (sc->flags & UMS_Z) 3161.16Saugustss DPRINTF(("ums_attach: Z\t%d/%d\n", 3171.16Saugustss sc->sc_loc_z.pos, sc->sc_loc_z.size)); 3181.16Saugustss for (i = 1; i <= sc->nbuttons; i++) { 3191.16Saugustss DPRINTF(("ums_attach: B%d\t%d/%d\n", 3201.16Saugustss i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size)); 3211.16Saugustss } 3221.16Saugustss DPRINTF(("ums_attach: size=%d, id=%d\n", sc->sc_isize, sc->sc_iid)); 3231.16Saugustss#endif 3241.16Saugustss 3251.16Saugustss#if defined(__NetBSD__) 3261.3Saugustss a.accessops = &ums_accessops; 3271.3Saugustss a.accesscookie = sc; 3281.3Saugustss 3291.3Saugustss sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 3301.16Saugustss#elif defined(__FreeBSD__) 3311.16Saugustss sc->hw.buttons = 2; /* XXX hw&mode values are bogus */ 3321.16Saugustss sc->hw.iftype = MOUSE_IF_PS2; 3331.16Saugustss sc->hw.type = MOUSE_MOUSE; 3341.16Saugustss if (sc->flags & UMS_Z) 3351.16Saugustss sc->hw.model = MOUSE_MODEL_INTELLI; 3361.16Saugustss else 3371.16Saugustss sc->hw.model = MOUSE_MODEL_GENERIC; 3381.16Saugustss sc->hw.hwid = 0; 3391.16Saugustss sc->mode.protocol = MOUSE_PROTO_PS2; 3401.16Saugustss sc->mode.rate = -1; 3411.16Saugustss sc->mode.resolution = MOUSE_RES_DEFAULT; 3421.16Saugustss sc->mode.accelfactor = 1; 3431.16Saugustss sc->mode.level = 0; 3441.16Saugustss if (sc->flags & UMS_Z) { 3451.16Saugustss sc->mode.packetsize = MOUSE_INTELLI_PACKETSIZE; 3461.16Saugustss sc->mode.syncmask[0] = 0xc8; 3471.16Saugustss } else { 3481.16Saugustss sc->mode.packetsize = MOUSE_PS2_PACKETSIZE; 3491.16Saugustss sc->mode.syncmask[0] = 0xc0; 3501.16Saugustss } 3511.16Saugustss sc->mode.syncmask[1] = 0; 3521.16Saugustss 3531.16Saugustss sc->status.flags = 0; 3541.16Saugustss sc->status.button = sc->status.obutton = 0; 3551.16Saugustss sc->status.dx = sc->status.dy = sc->status.dz = 0; 3561.16Saugustss 3571.16Saugustss sc->rsel.si_flags = 0; 3581.16Saugustss sc->rsel.si_pid = 0; 3591.16Saugustss#endif 3601.16Saugustss 3611.16Saugustss USB_ATTACH_SUCCESS_RETURN; 3621.16Saugustss} 3631.16Saugustss 3641.16Saugustss 3651.16Saugustss#if defined(__FreeBSD__) 3661.16Saugustssstatic int 3671.16Saugustssums_detach(device_t self) 3681.16Saugustss{ 3691.16Saugustss struct ums_softc *sc = device_get_softc(self); 3701.16Saugustss char *devinfo = (char *) device_get_desc(self); 3711.16Saugustss 3721.16Saugustss if (devinfo) { 3731.16Saugustss device_set_desc(self, NULL); 3741.16Saugustss free(devinfo, M_USB); 3751.16Saugustss } 3761.16Saugustss free(sc->sc_loc_btn, M_USB); 3771.16Saugustss free(sc->sc_ibuf, M_USB); 3781.16Saugustss 3791.16Saugustss return 0; 3801.1Saugustss} 3811.16Saugustss#endif 3821.1Saugustss 3831.1Saugustssvoid 3841.1Saugustssums_disco(p) 3851.1Saugustss void *p; 3861.1Saugustss{ 3871.1Saugustss struct ums_softc *sc = p; 3881.8Saugustss 3891.8Saugustss DPRINTF(("ums_disco: sc=%p\n", sc)); 3901.8Saugustss usbd_abort_pipe(sc->sc_intrpipe); 3911.1Saugustss sc->sc_disconnected = 1; 3921.1Saugustss} 3931.1Saugustss 3941.1Saugustssvoid 3951.1Saugustssums_intr(reqh, addr, status) 3961.1Saugustss usbd_request_handle reqh; 3971.1Saugustss usbd_private_handle addr; 3981.1Saugustss usbd_status status; 3991.1Saugustss{ 4001.1Saugustss struct ums_softc *sc = addr; 4011.1Saugustss u_char *ibuf; 4021.6Saugustss int dx, dy, dz; 4031.16Saugustss u_char buttons = 0; 4041.16Saugustss int i; 4051.16Saugustss#if defined(__NetBSD__) 4061.16Saugustss#define UMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i) 4071.16Saugustss#elif defined(__FreeBSD__) 4081.16Saugustss#define UMS_BUT(i) (i) 4091.16Saugustss#endif 4101.1Saugustss 4111.1Saugustss DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status)); 4121.1Saugustss DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n", 4131.1Saugustss sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2])); 4141.1Saugustss 4151.1Saugustss if (status == USBD_CANCELLED) 4161.1Saugustss return; 4171.1Saugustss 4181.1Saugustss if (status != USBD_NORMAL_COMPLETION) { 4191.1Saugustss DPRINTF(("ums_intr: status=%d\n", status)); 4201.7Saugustss usbd_clear_endpoint_stall_async(sc->sc_intrpipe); 4211.1Saugustss return; 4221.1Saugustss } 4231.1Saugustss 4241.1Saugustss ibuf = sc->sc_ibuf; 4251.1Saugustss if (sc->sc_iid) { 4261.1Saugustss if (*ibuf++ != sc->sc_iid) 4271.1Saugustss return; 4281.1Saugustss } 4291.1Saugustss dx = hid_get_data(ibuf, &sc->sc_loc_x); 4301.1Saugustss dy = -hid_get_data(ibuf, &sc->sc_loc_y); 4311.6Saugustss dz = hid_get_data(ibuf, &sc->sc_loc_z); 4321.16Saugustss /* NWH Why are you modifying the button assignments here? 4331.16Saugustss * That's the purpose of a high level mouse driver 4341.16Saugustss */ 4351.16Saugustss for (i = 0; i < sc->nbuttons; i++) 4361.16Saugustss if (hid_get_data(ibuf, &sc->sc_loc_btn[i])) 4371.16Saugustss buttons |= (1 << UMS_BUT(i)); 4381.4Saugustss 4391.16Saugustss#if defined(__NetBSD__) 4401.4Saugustss if (dx || dy || buttons != sc->sc_buttons) { 4411.16Saugustss DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n", 4421.16Saugustss dx, dy, dz, buttons)); 4431.4Saugustss sc->sc_buttons = buttons; 4441.4Saugustss if (sc->sc_wsmousedev) 4451.6Saugustss wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, dz); 4461.16Saugustss#elif defined(__FreeBSD__) 4471.16Saugustss if (dx || dy || buttons != sc->status.button) { 4481.16Saugustss DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n", 4491.16Saugustss dx, dy, dz, buttons)); 4501.16Saugustss 4511.16Saugustss sc->status.button = buttons; 4521.16Saugustss sc->status.dx += dx; 4531.16Saugustss sc->status.dy += dy; 4541.16Saugustss sc->status.dz += dz; 4551.16Saugustss 4561.16Saugustss /* Discard data in case of full buffer */ 4571.16Saugustss if (sc->qcount == sizeof(sc->qbuf)) { 4581.16Saugustss DPRINTF(("Buffer full, discarded packet")); 4591.16Saugustss return; 4601.16Saugustss } 4611.16Saugustss 4621.16Saugustss sc->qbuf[sc->qhead] = MOUSE_PS2_SYNC; 4631.16Saugustss if (dx < 0) 4641.16Saugustss sc->qbuf[sc->qhead] |= MOUSE_PS2_XNEG; 4651.16Saugustss if (dx > 255 || dx < -255) 4661.16Saugustss sc->qbuf[sc->qhead] |= MOUSE_PS2_XOVERFLOW; 4671.16Saugustss if (dy < 0) 4681.16Saugustss sc->qbuf[sc->qhead] |= MOUSE_PS2_YNEG; 4691.16Saugustss if (dy > 255 || dy < -255) 4701.16Saugustss sc->qbuf[sc->qhead] |= MOUSE_PS2_YOVERFLOW; 4711.16Saugustss sc->qbuf[sc->qhead++] |= buttons; 4721.16Saugustss sc->qbuf[sc->qhead++] = dx; 4731.16Saugustss sc->qbuf[sc->qhead++] = dy; 4741.16Saugustss sc->qcount += 3; 4751.16Saugustss if (sc->flags & UMS_Z) { 4761.16Saugustss sc->qbuf[sc->qhead++] = dz; 4771.16Saugustss sc->qcount++; 4781.16Saugustss } 4791.16Saugustss#ifdef USB_DEBUG 4801.16Saugustss if (sc->qhead > sizeof(sc->qbuf)) 4811.16Saugustss DPRINTF(("Buffer overrun! %d %d\n", 4821.16Saugustss sc->qhead, sizeof(sc->qbuf))); 4831.16Saugustss#endif 4841.16Saugustss /* wrap round at end of buffer */ 4851.16Saugustss if (sc->qhead >= sizeof(sc->qbuf)) 4861.16Saugustss sc->qhead = 0; 4871.16Saugustss 4881.16Saugustss /* someone waiting for data */ 4891.16Saugustss if (sc->state & UMS_ASLEEP) 4901.16Saugustss wakeup(sc); 4911.16Saugustss /* wake up any pending selects */ 4921.16Saugustss selwakeup(&sc->rsel); 4931.16Saugustss sc->state &= ~UMS_SELECT; 4941.16Saugustss#endif 4951.1Saugustss } 4961.1Saugustss} 4971.3Saugustss 4981.16Saugustss 4991.16Saugustssstatic int 5001.3Saugustssums_enable(v) 5011.3Saugustss void *v; 5021.3Saugustss{ 5031.3Saugustss struct ums_softc *sc = v; 5041.16Saugustss 5051.3Saugustss usbd_status r; 5061.3Saugustss 5071.3Saugustss if (sc->sc_enabled) 5081.3Saugustss return EBUSY; 5091.3Saugustss 5101.3Saugustss sc->sc_enabled = 1; 5111.16Saugustss#if defined(__NetBSD__) 5121.4Saugustss sc->sc_buttons = 0; 5131.16Saugustss#elif defined(__FreeBSD__) 5141.16Saugustss sc->qcount = 0; 5151.16Saugustss sc->qhead = sc->qtail = 0; 5161.16Saugustss#ifdef USB_DEBUG 5171.16Saugustss if (sizeof(sc->qbuf) % 4 || sizeof(sc->qbuf) % 3) { 5181.16Saugustss DPRINTF(("Buffer size not divisible by 3 or 4\n")); 5191.16Saugustss return ENXIO; 5201.16Saugustss } 5211.16Saugustss#endif 5221.16Saugustss sc->status.flags = 0; 5231.16Saugustss sc->status.button = sc->status.obutton = 0; 5241.16Saugustss sc->status.dx = sc->status.dy = sc->status.dz = 0; 5251.16Saugustss#endif 5261.3Saugustss 5271.3Saugustss /* Set up interrupt pipe. */ 5281.3Saugustss r = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, 5291.3Saugustss USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, 5301.3Saugustss sc->sc_ibuf, sc->sc_isize, ums_intr); 5311.3Saugustss if (r != USBD_NORMAL_COMPLETION) { 5321.3Saugustss DPRINTF(("ums_enable: usbd_open_pipe_intr failed, error=%d\n", 5331.3Saugustss r)); 5341.3Saugustss sc->sc_enabled = 0; 5351.3Saugustss return (EIO); 5361.3Saugustss } 5371.3Saugustss usbd_set_disco(sc->sc_intrpipe, ums_disco, sc); 5381.3Saugustss return (0); 5391.3Saugustss} 5401.3Saugustss 5411.16Saugustssstatic void 5421.3Saugustssums_disable(v) 5431.3Saugustss void *v; 5441.3Saugustss{ 5451.3Saugustss struct ums_softc *sc = v; 5461.3Saugustss 5471.3Saugustss /* Disable interrupts. */ 5481.3Saugustss usbd_abort_pipe(sc->sc_intrpipe); 5491.3Saugustss usbd_close_pipe(sc->sc_intrpipe); 5501.3Saugustss 5511.3Saugustss sc->sc_enabled = 0; 5521.16Saugustss 5531.16Saugustss#if defined(USBVERBOSE) && defined(__FreeBSD__) 5541.16Saugustss if (sc->qcount != 0) 5551.16Saugustss DPRINTF(("Discarded %d bytes in queue\n", sc->qcount)); 5561.16Saugustss#endif 5571.3Saugustss} 5581.3Saugustss 5591.16Saugustss#if defined(__NetBSD__) 5601.16Saugustssstatic int 5611.3Saugustssums_ioctl(v, cmd, data, flag, p) 5621.3Saugustss void *v; 5631.3Saugustss u_long cmd; 5641.3Saugustss caddr_t data; 5651.3Saugustss int flag; 5661.3Saugustss struct proc *p; 5671.16Saugustss 5681.3Saugustss{ 5691.3Saugustss switch (cmd) { 5701.3Saugustss case WSMOUSEIO_GTYPE: 5711.3Saugustss *(u_int *)data = WSMOUSE_TYPE_PS2; 5721.3Saugustss return (0); 5731.3Saugustss } 5741.16Saugustss 5751.3Saugustss return (-1); 5761.3Saugustss} 5771.16Saugustss 5781.16Saugustss#elif defined(__FreeBSD__) 5791.16Saugustssstatic int 5801.16Saugustssums_open(dev_t dev, int flag, int fmt, struct proc *p) 5811.16Saugustss{ 5821.16Saugustss struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev)); 5831.16Saugustss 5841.16Saugustss if (!sc) { 5851.16Saugustss DPRINTF(("sc not found at open")); 5861.16Saugustss return EINVAL; 5871.16Saugustss } 5881.16Saugustss 5891.16Saugustss return ums_enable(sc); 5901.16Saugustss} 5911.16Saugustss 5921.16Saugustssstatic int 5931.16Saugustssums_close(dev_t dev, int flag, int fmt, struct proc *p) 5941.16Saugustss{ 5951.16Saugustss struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev)); 5961.16Saugustss 5971.16Saugustss if (!sc) { 5981.16Saugustss DPRINTF(("sc not found at close")); 5991.16Saugustss return EINVAL; 6001.16Saugustss } 6011.16Saugustss 6021.16Saugustss if (sc->sc_enabled) 6031.16Saugustss ums_disable(sc); 6041.16Saugustss return 0; 6051.16Saugustss} 6061.16Saugustss 6071.16Saugustssstatic int 6081.16Saugustssums_read(dev_t dev, struct uio *uio, int flag) 6091.16Saugustss{ 6101.16Saugustss struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev)); 6111.16Saugustss int s; 6121.16Saugustss char buf[sizeof(sc->qbuf)]; 6131.16Saugustss int l = 0; 6141.16Saugustss int error; 6151.16Saugustss 6161.16Saugustss if (!sc || !sc->sc_enabled) { 6171.16Saugustss DPRINTF(("sc not found at read")); 6181.16Saugustss return EINVAL; 6191.16Saugustss } 6201.16Saugustss 6211.16Saugustss s = splusb(); 6221.16Saugustss while (sc->qcount == 0 ) { 6231.16Saugustss /* NWH XXX non blocking I/O ?? 6241.16Saugustss if (non blocking I/O ) { 6251.16Saugustss splx(s); 6261.16Saugustss return EWOULDBLOCK; 6271.16Saugustss } else { 6281.16Saugustss */ 6291.16Saugustss sc->state |= UMS_ASLEEP; 6301.16Saugustss error = tsleep(sc, PZERO | PCATCH, "umsrea", 0); 6311.16Saugustss sc->state &= ~UMS_ASLEEP; 6321.16Saugustss if (error) { 6331.16Saugustss splx(s); 6341.16Saugustss return error; 6351.16Saugustss } 6361.16Saugustss } 6371.16Saugustss 6381.16Saugustss while ((sc->qcount > 0) && (uio->uio_resid > 0)) { 6391.16Saugustss l = (sc->qcount < uio->uio_resid? sc->qcount:uio->uio_resid); 6401.16Saugustss if (l > sizeof(buf)) 6411.16Saugustss l = sizeof(buf); 6421.16Saugustss if (l > sizeof(sc->qbuf) - sc->qtail) /* transfer till end of buf */ 6431.16Saugustss l = sizeof(sc->qbuf) - sc->qtail; 6441.16Saugustss 6451.16Saugustss splx(s); 6461.16Saugustss uiomove(&sc->qbuf[sc->qtail], l, uio); 6471.16Saugustss s = splusb(); 6481.16Saugustss 6491.16Saugustss if ( sc->qcount - l < 0 ) { 6501.16Saugustss DPRINTF(("qcount below 0, count=%d l=%d\n", sc->qcount, l)); 6511.16Saugustss sc->qcount = l; 6521.16Saugustss } 6531.16Saugustss sc->qcount -= l; /* remove the bytes from the buffer */ 6541.16Saugustss sc->qtail = (sc->qtail + l) % sizeof(sc->qbuf); 6551.16Saugustss } 6561.16Saugustss splx(s); 6571.16Saugustss 6581.16Saugustss return 0; 6591.16Saugustss} 6601.16Saugustss 6611.16Saugustssstatic int 6621.16Saugustssums_poll(dev_t dev, int events, struct proc *p) 6631.16Saugustss{ 6641.16Saugustss struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev)); 6651.16Saugustss int revents = 0; 6661.16Saugustss int s; 6671.16Saugustss 6681.16Saugustss if (!sc) { 6691.16Saugustss DPRINTF(("sc not found at poll")); 6701.16Saugustss return 0; /* just to make sure */ 6711.16Saugustss } 6721.16Saugustss 6731.16Saugustss s = splusb(); 6741.16Saugustss if (events & (POLLIN | POLLRDNORM)) 6751.16Saugustss if (sc->qcount) { 6761.16Saugustss revents = events & (POLLIN | POLLRDNORM); 6771.16Saugustss } else { 6781.16Saugustss sc->state |= UMS_SELECT; 6791.16Saugustss selrecord(p, &sc->rsel); 6801.16Saugustss } 6811.16Saugustss splx(s); 6821.16Saugustss 6831.16Saugustss return revents; 6841.16Saugustss} 6851.16Saugustss 6861.16Saugustssint 6871.16Saugustssums_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 6881.16Saugustss{ 6891.16Saugustss struct ums_softc *sc = devclass_get_softc(ums_devclass, UMSUNIT(dev)); 6901.16Saugustss int error = 0; 6911.16Saugustss int s; 6921.16Saugustss 6931.16Saugustss if (!sc) { 6941.16Saugustss DPRINTF(("sc not found at ioctl")); 6951.16Saugustss return ENOENT; 6961.16Saugustss } 6971.16Saugustss 6981.16Saugustss switch(cmd) { 6991.16Saugustss case MOUSE_GETHWINFO: 7001.16Saugustss *(mousehw_t *)addr = sc->hw; 7011.16Saugustss break; 7021.16Saugustss case MOUSE_GETMODE: 7031.16Saugustss *(mousemode_t *)addr = sc->mode; 7041.16Saugustss break; 7051.16Saugustss case MOUSE_GETLEVEL: 7061.16Saugustss *(int *)addr = sc->mode.level; 7071.16Saugustss break; 7081.16Saugustss case MOUSE_GETSTATUS: { 7091.16Saugustss mousestatus_t *status = (mousestatus_t *) addr; 7101.16Saugustss 7111.16Saugustss s = splusb(); 7121.16Saugustss *status = sc->status; 7131.16Saugustss sc->status.obutton = sc->status.button; 7141.16Saugustss sc->status.button = 0; 7151.16Saugustss sc->status.dx = sc->status.dy = sc->status.dz = 0; 7161.16Saugustss splx(s); 7171.16Saugustss 7181.16Saugustss if (status->dx || status->dy || status->dz) 7191.16Saugustss status->flags |= MOUSE_POSCHANGED; 7201.16Saugustss if (status->button != status->obutton) 7211.16Saugustss status->flags |= MOUSE_BUTTONSCHANGED; 7221.16Saugustss break; 7231.16Saugustss } 7241.16Saugustss default: 7251.16Saugustss error = ENOTTY; 7261.16Saugustss } 7271.16Saugustss 7281.16Saugustss return error; 7291.16Saugustss} 7301.16Saugustss#endif 7311.16Saugustss 7321.16Saugustss#if defined(__FreeBSD__) 7331.16SaugustssCDEV_DRIVER_MODULE(ums, usb, ums_driver, ums_devclass, 7341.16Saugustss UMS_CDEV_MAJOR, ums_cdevsw, usb_driver_load, 0); 7351.16Saugustss#endif 7361.3Saugustss 737