Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/usb/input/uep.c
Show All 26 Lines | |||||
* | * | ||||
* $FreeBSD$ | * $FreeBSD$ | ||||
*/ | */ | ||||
/* | /* | ||||
* http://www.eeti.com.tw/pdf/Software%20Programming%20Guide_v2.0.pdf | * http://www.eeti.com.tw/pdf/Software%20Programming%20Guide_v2.0.pdf | ||||
*/ | */ | ||||
#include "opt_evdev.h" | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/callout.h> | #include <sys/callout.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <dev/usb/usb.h> | #include <dev/usb/usb.h> | ||||
#include <dev/usb/usbdi.h> | #include <dev/usb/usbdi.h> | ||||
#include <dev/usb/usbdi_util.h> | #include <dev/usb/usbdi_util.h> | ||||
#include <dev/usb/usbhid.h> | #include <dev/usb/usbhid.h> | ||||
#include "usbdevs.h" | #include "usbdevs.h" | ||||
#ifdef EVDEV_SUPPORT | |||||
#include <dev/evdev/input.h> | |||||
#include <dev/evdev/evdev.h> | |||||
#else | |||||
#include <sys/ioccom.h> | #include <sys/ioccom.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
#include <sys/tty.h> | #include <sys/tty.h> | ||||
#endif | |||||
#define USB_DEBUG_VAR uep_debug | #define USB_DEBUG_VAR uep_debug | ||||
#include <dev/usb/usb_debug.h> | #include <dev/usb/usb_debug.h> | ||||
#ifdef USB_DEBUG | #ifdef USB_DEBUG | ||||
static int uep_debug = 0; | static int uep_debug = 0; | ||||
static SYSCTL_NODE(_hw_usb, OID_AUTO, uep, CTLFLAG_RW, 0, "USB uep"); | static SYSCTL_NODE(_hw_usb, OID_AUTO, uep, CTLFLAG_RW, 0, "USB uep"); | ||||
Show All 22 Lines | enum { | ||||
UEP_INTR_DT, | UEP_INTR_DT, | ||||
UEP_N_TRANSFER, | UEP_N_TRANSFER, | ||||
}; | }; | ||||
struct uep_softc { | struct uep_softc { | ||||
struct mtx mtx; | struct mtx mtx; | ||||
struct usb_xfer *xfer[UEP_N_TRANSFER]; | struct usb_xfer *xfer[UEP_N_TRANSFER]; | ||||
#ifdef EVDEV_SUPPORT | |||||
struct evdev_dev *evdev; | |||||
#else | |||||
struct usb_fifo_sc fifo; | struct usb_fifo_sc fifo; | ||||
u_int pollrate; | u_int pollrate; | ||||
u_int state; | u_int state; | ||||
#define UEP_ENABLED 0x01 | #define UEP_ENABLED 0x01 | ||||
#endif | |||||
/* Reassembling buffer. */ | /* Reassembling buffer. */ | ||||
u_char buf[UEP_PACKET_LEN_MAX]; | u_char buf[UEP_PACKET_LEN_MAX]; | ||||
uint8_t buf_len; | uint8_t buf_len; | ||||
}; | }; | ||||
static usb_callback_t uep_intr_callback; | static usb_callback_t uep_intr_callback; | ||||
static device_probe_t uep_probe; | static device_probe_t uep_probe; | ||||
static device_attach_t uep_attach; | static device_attach_t uep_attach; | ||||
static device_detach_t uep_detach; | static device_detach_t uep_detach; | ||||
#ifdef EVDEV_SUPPORT | |||||
static evdev_open_t uep_ev_open; | |||||
static evdev_close_t uep_ev_close; | |||||
static const struct evdev_methods uep_evdev_methods = { | |||||
.ev_open = &uep_ev_open, | |||||
.ev_close = &uep_ev_close, | |||||
}; | |||||
#else /* !EVDEV_SUPPORT */ | |||||
static usb_fifo_cmd_t uep_start_read; | static usb_fifo_cmd_t uep_start_read; | ||||
static usb_fifo_cmd_t uep_stop_read; | static usb_fifo_cmd_t uep_stop_read; | ||||
static usb_fifo_open_t uep_open; | static usb_fifo_open_t uep_open; | ||||
static usb_fifo_close_t uep_close; | static usb_fifo_close_t uep_close; | ||||
static void uep_put_queue(struct uep_softc *, u_char *); | static void uep_put_queue(struct uep_softc *, u_char *); | ||||
static struct usb_fifo_methods uep_fifo_methods = { | static struct usb_fifo_methods uep_fifo_methods = { | ||||
.f_open = &uep_open, | .f_open = &uep_open, | ||||
.f_close = &uep_close, | .f_close = &uep_close, | ||||
.f_start_read = &uep_start_read, | .f_start_read = &uep_start_read, | ||||
.f_stop_read = &uep_stop_read, | .f_stop_read = &uep_stop_read, | ||||
.basename[0] = "uep", | .basename[0] = "uep", | ||||
}; | }; | ||||
#endif /* !EVDEV_SUPPORT */ | |||||
static int | static int | ||||
get_pkt_len(u_char *buf) | get_pkt_len(u_char *buf) | ||||
{ | { | ||||
if (buf[0] == UEP_PACKET_DIAG) { | if (buf[0] == UEP_PACKET_DIAG) { | ||||
int len; | int len; | ||||
len = buf[1] + 2; | len = buf[1] + 2; | ||||
Show All 17 Lines | default: | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
uep_process_pkt(struct uep_softc *sc, u_char *buf) | uep_process_pkt(struct uep_softc *sc, u_char *buf) | ||||
{ | { | ||||
int32_t x, y; | int32_t x, y; | ||||
#ifdef EVDEV_SUPPORT | |||||
int touch; | |||||
#endif | |||||
if ((buf[0] & 0xFE) != 0x80) { | if ((buf[0] & 0xFE) != 0x80) { | ||||
DPRINTF("bad input packet format 0x%.2x\n", buf[0]); | DPRINTF("bad input packet format 0x%.2x\n", buf[0]); | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Packet format is 5 bytes: | * Packet format is 5 bytes: | ||||
Show All 16 Lines | #endif | ||||
* | * | ||||
*/ | */ | ||||
x = (buf[1] << 7) | buf[2]; | x = (buf[1] << 7) | buf[2]; | ||||
y = (buf[3] << 7) | buf[4]; | y = (buf[3] << 7) | buf[4]; | ||||
DPRINTFN(2, "x %u y %u\n", x, y); | DPRINTFN(2, "x %u y %u\n", x, y); | ||||
#ifdef EVDEV_SUPPORT | |||||
touch = buf[0] & (1 << 0); | |||||
if (touch) { | |||||
evdev_push_abs(sc->evdev, ABS_X, x); | |||||
evdev_push_abs(sc->evdev, ABS_Y, y); | |||||
} | |||||
evdev_push_key(sc->evdev, BTN_TOUCH, touch); | |||||
evdev_sync(sc->evdev); | |||||
#else | |||||
uep_put_queue(sc, buf); | uep_put_queue(sc, buf); | ||||
#endif | |||||
} | } | ||||
static void | static void | ||||
uep_intr_callback(struct usb_xfer *xfer, usb_error_t error) | uep_intr_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct uep_softc *sc = usbd_xfer_softc(xfer); | struct uep_softc *sc = usbd_xfer_softc(xfer); | ||||
int len; | int len; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | while (len > 0) { | ||||
sc->buf_len = len; | sc->buf_len = len; | ||||
} | } | ||||
p += pkt_len; | p += pkt_len; | ||||
len -= pkt_len; | len -= pkt_len; | ||||
} | } | ||||
} | } | ||||
case USB_ST_SETUP: | case USB_ST_SETUP: | ||||
tr_setup: | tr_setup: | ||||
#ifndef EVDEV_SUPPORT | |||||
/* check if we can put more data into the FIFO */ | /* check if we can put more data into the FIFO */ | ||||
if (usb_fifo_put_bytes_max(sc->fifo.fp[USB_FIFO_RX]) != 0) { | if (usb_fifo_put_bytes_max(sc->fifo.fp[USB_FIFO_RX]) == 0) | ||||
usbd_xfer_set_frame_len(xfer, 0, | break; | ||||
usbd_xfer_max_len(xfer)); | #endif | ||||
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); | |||||
usbd_transfer_submit(xfer); | usbd_transfer_submit(xfer); | ||||
} | |||||
break; | break; | ||||
default: | default: | ||||
if (error != USB_ERR_CANCELLED) { | if (error != USB_ERR_CANCELLED) { | ||||
/* try clear stall first */ | /* try clear stall first */ | ||||
usbd_xfer_set_stall(xfer); | usbd_xfer_set_stall(xfer); | ||||
goto tr_setup; | goto tr_setup; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | uep_attach(device_t dev) | ||||
error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, | error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, | ||||
sc->xfer, uep_config, UEP_N_TRANSFER, sc, &sc->mtx); | sc->xfer, uep_config, UEP_N_TRANSFER, sc, &sc->mtx); | ||||
if (error) { | if (error) { | ||||
DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(error)); | DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(error)); | ||||
goto detach; | goto detach; | ||||
} | } | ||||
#ifdef EVDEV_SUPPORT | |||||
sc->evdev = evdev_alloc(); | |||||
evdev_set_name(sc->evdev, device_get_desc(dev)); | |||||
evdev_set_phys(sc->evdev, device_get_nameunit(dev)); | |||||
evdev_set_id(sc->evdev, BUS_USB, uaa->info.idVendor, | |||||
uaa->info.idProduct, 0); | |||||
evdev_set_serial(sc->evdev, usb_get_serial(uaa->device)); | |||||
evdev_set_methods(sc->evdev, sc, &uep_evdev_methods); | |||||
evdev_support_prop(sc->evdev, INPUT_PROP_DIRECT); | |||||
evdev_support_event(sc->evdev, EV_SYN); | |||||
evdev_support_event(sc->evdev, EV_ABS); | |||||
evdev_support_event(sc->evdev, EV_KEY); | |||||
evdev_support_key(sc->evdev, BTN_TOUCH); | |||||
evdev_support_abs(sc->evdev, ABS_X, 0, 0, UEP_MAX_X, 0, 0, 0); | |||||
evdev_support_abs(sc->evdev, ABS_Y, 0, 0, UEP_MAX_Y, 0, 0, 0); | |||||
error = evdev_register_mtx(sc->evdev, &sc->mtx); | |||||
if (error) { | |||||
DPRINTF("evdev_register_mtx error=%s\n", usbd_errstr(error)); | |||||
goto detach; | |||||
} | |||||
#else /* !EVDEV_SUPPORT */ | |||||
error = usb_fifo_attach(uaa->device, sc, &sc->mtx, &uep_fifo_methods, | error = usb_fifo_attach(uaa->device, sc, &sc->mtx, &uep_fifo_methods, | ||||
&sc->fifo, device_get_unit(dev), -1, uaa->info.bIfaceIndex, | &sc->fifo, device_get_unit(dev), -1, uaa->info.bIfaceIndex, | ||||
UID_ROOT, GID_OPERATOR, 0644); | UID_ROOT, GID_OPERATOR, 0644); | ||||
if (error) { | if (error) { | ||||
DPRINTF("usb_fifo_attach error=%s\n", usbd_errstr(error)); | DPRINTF("usb_fifo_attach error=%s\n", usbd_errstr(error)); | ||||
goto detach; | goto detach; | ||||
} | } | ||||
#endif /* !EVDEV_SUPPORT */ | |||||
sc->buf_len = 0; | sc->buf_len = 0; | ||||
return (0); | return (0); | ||||
detach: | detach: | ||||
uep_detach(dev); | uep_detach(dev); | ||||
return (ENOMEM); /* XXX */ | return (ENOMEM); /* XXX */ | ||||
} | } | ||||
static int | static int | ||||
uep_detach(device_t dev) | uep_detach(device_t dev) | ||||
{ | { | ||||
struct uep_softc *sc = device_get_softc(dev); | struct uep_softc *sc = device_get_softc(dev); | ||||
#ifdef EVDEV_SUPPORT | |||||
evdev_free(sc->evdev); | |||||
#else | |||||
usb_fifo_detach(&sc->fifo); | usb_fifo_detach(&sc->fifo); | ||||
#endif | |||||
usbd_transfer_unsetup(sc->xfer, UEP_N_TRANSFER); | usbd_transfer_unsetup(sc->xfer, UEP_N_TRANSFER); | ||||
mtx_destroy(&sc->mtx); | mtx_destroy(&sc->mtx); | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef EVDEV_SUPPORT | |||||
static void | static void | ||||
uep_ev_close(struct evdev_dev *evdev, void *ev_softc) | |||||
{ | |||||
struct uep_softc *sc = (struct uep_softc *)ev_softc; | |||||
mtx_assert(&sc->mtx, MA_OWNED); | |||||
usbd_transfer_stop(sc->xfer[UEP_INTR_DT]); | |||||
} | |||||
static int | |||||
uep_ev_open(struct evdev_dev *evdev, void *ev_softc) | |||||
{ | |||||
struct uep_softc *sc = (struct uep_softc *)ev_softc; | |||||
mtx_assert(&sc->mtx, MA_OWNED); | |||||
usbd_transfer_start(sc->xfer[UEP_INTR_DT]); | |||||
return (0); | |||||
} | |||||
#else /* !EVDEV_SUPPORT */ | |||||
static void | |||||
uep_start_read(struct usb_fifo *fifo) | uep_start_read(struct usb_fifo *fifo) | ||||
{ | { | ||||
struct uep_softc *sc = usb_fifo_softc(fifo); | struct uep_softc *sc = usb_fifo_softc(fifo); | ||||
u_int rate; | u_int rate; | ||||
if ((rate = sc->pollrate) > 1000) | if ((rate = sc->pollrate) > 1000) | ||||
rate = 1000; | rate = 1000; | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
if (fflags & FREAD) { | if (fflags & FREAD) { | ||||
struct uep_softc *sc = usb_fifo_softc(fifo); | struct uep_softc *sc = usb_fifo_softc(fifo); | ||||
sc->state &= ~(UEP_ENABLED); | sc->state &= ~(UEP_ENABLED); | ||||
usb_fifo_free_buffer(fifo); | usb_fifo_free_buffer(fifo); | ||||
} | } | ||||
} | } | ||||
#endif /* !EVDEV_SUPPORT */ | |||||
static devclass_t uep_devclass; | static devclass_t uep_devclass; | ||||
static device_method_t uep_methods[] = { | static device_method_t uep_methods[] = { | ||||
DEVMETHOD(device_probe, uep_probe), | DEVMETHOD(device_probe, uep_probe), | ||||
DEVMETHOD(device_attach, uep_attach), | DEVMETHOD(device_attach, uep_attach), | ||||
DEVMETHOD(device_detach, uep_detach), | DEVMETHOD(device_detach, uep_detach), | ||||
{ 0, 0 }, | { 0, 0 }, | ||||
}; | }; | ||||
static driver_t uep_driver = { | static driver_t uep_driver = { | ||||
.name = "uep", | .name = "uep", | ||||
.methods = uep_methods, | .methods = uep_methods, | ||||
.size = sizeof(struct uep_softc), | .size = sizeof(struct uep_softc), | ||||
}; | }; | ||||
DRIVER_MODULE(uep, uhub, uep_driver, uep_devclass, NULL, NULL); | DRIVER_MODULE(uep, uhub, uep_driver, uep_devclass, NULL, NULL); | ||||
MODULE_DEPEND(uep, usb, 1, 1, 1); | MODULE_DEPEND(uep, usb, 1, 1, 1); | ||||
#ifdef EVDEV_SUPPORT | |||||
MODULE_DEPEND(uep, evdev, 1, 1, 1); | |||||
#endif | |||||
MODULE_VERSION(uep, 1); | MODULE_VERSION(uep, 1); | ||||
USB_PNP_HOST_INFO(uep_devs); | USB_PNP_HOST_INFO(uep_devs); |