From a0803787f7b5b948412e9340e31619850e6d9105 Mon Sep 17 00:00:00 2001 From: augustss Date: Wed, 29 Jul 1998 20:50:11 +0000 Subject: [PATCH] Add functions to execute asynchronous requests and use these from interrupt context. [I had some feline debugging help here. I noticed that every time Kem, our kitty, jumped onto the USB keyboard the machine crashed.] --- sys/dev/usb/ukbd.c | 18 +++++----- sys/dev/usb/ums.c | 6 ++-- sys/dev/usb/usbdi.c | 78 ++++++++++++++++++++++++++++++++++++++-- sys/dev/usb/usbdi.h | 5 ++- sys/dev/usb/usbdi_util.c | 29 ++++++++++++++- sys/dev/usb/usbdi_util.h | 8 +++-- 6 files changed, 125 insertions(+), 19 deletions(-) diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c index a812cfd15a6e..fe0f397d4c98 100644 --- a/sys/dev/usb/ukbd.c +++ b/sys/dev/usb/ukbd.c @@ -1,4 +1,4 @@ -/* $NetBSD: ukbd.c,v 1.3 1998/07/26 17:42:49 augustss Exp $ */ +/* $NetBSD: ukbd.c,v 1.4 1998/07/29 20:50:11 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -141,8 +141,6 @@ struct ukbd_softc { struct ukbd_data sc_ndata; struct ukbd_data sc_odata; - int sc_state; -#define UKBD_NEEDCLEAR 0x01 /* needs clearing endpoint stall */ int sc_disconnected; /* device is gone */ int sc_leds; @@ -308,7 +306,7 @@ ukbd_intr(reqh, addr, status) if (status != USBD_NORMAL_COMPLETION) { DPRINTF(("ukbd_intr: status=%d\n", status)); - sc->sc_state |= UKBD_NEEDCLEAR; + usbd_clear_endpoint_stall_async(sc->sc_intrpipe); return; } @@ -391,7 +389,7 @@ ukbd_set_leds(v, leds) res |= NUM_LOCK; if (leds & WSKBD_LED_CAPS) res |= CAPS_LOCK; - usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT, 0, &res, 1); + usbd_set_report_async(sc->sc_iface, UHID_OUTPUT_REPORT, 0, &res, 1); } int @@ -432,7 +430,9 @@ ukbd_cngetc(v, type, data) struct ukbd_softc *sc = v; usbd_lock_token s; extern int usbd_use_polling; + int c; + DPRINTFN(1,("ukbd_cngetc: enter\n")); s = usbd_lock(); usbd_use_polling = 1; sc->sc_polling = 1; @@ -441,9 +441,11 @@ ukbd_cngetc(v, type, data) usbd_dopoll(sc->sc_iface); sc->sc_polling = 0; usbd_use_polling = 0; - *type = sc->sc_pollchar&0x80?WSCONS_EVENT_KEY_UP:WSCONS_EVENT_KEY_DOWN; - *data = sc->sc_pollchar & 0x7f; + c = sc->sc_pollchar; + *type = c & 0x80 ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; + *data = c & 0x7f; usbd_unlock(s); + DPRINTFN(1,("ukbd_cngetc: return 0x%02x\n", c)); } void @@ -451,5 +453,5 @@ ukbd_cnpollc(v, on) void *v; int on; { - DPRINTF(("ukbd_cnpollc: sc=%p on=%d\n", v, on)); + DPRINTFN(1,("ukbd_cnpollc: sc=%p on=%d\n", v, on)); } diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c index 03aa6668e09c..6276598588eb 100644 --- a/sys/dev/usb/ums.c +++ b/sys/dev/usb/ums.c @@ -1,4 +1,4 @@ -/* $NetBSD: ums.c,v 1.6 1998/07/28 21:21:47 augustss Exp $ */ +/* $NetBSD: ums.c,v 1.7 1998/07/29 20:50:12 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -91,8 +91,6 @@ struct ums_softc { struct hid_location sc_loc_x, sc_loc_y, sc_loc_z, sc_loc_btn1, sc_loc_btn2, sc_loc_btn3; - u_char sc_state; /* mouse driver state */ -#define UMS_NEEDCLEAR 0x04 /* needs clearing endpoint stall */ u_char sc_buttons; /* mouse button status */ int sc_disconnected; /* device is gone */ @@ -294,7 +292,7 @@ ums_intr(reqh, addr, status) if (status != USBD_NORMAL_COMPLETION) { DPRINTF(("ums_intr: status=%d\n", status)); - sc->sc_state |= UMS_NEEDCLEAR; + usbd_clear_endpoint_stall_async(sc->sc_intrpipe); return; } diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c index df32a4c2c027..caf0f3d53cf0 100644 --- a/sys/dev/usb/usbdi.c +++ b/sys/dev/usb/usbdi.c @@ -1,4 +1,4 @@ -/* $NetBSD: usbdi.c,v 1.6 1998/07/26 17:42:49 augustss Exp $ */ +/* $NetBSD: usbdi.c,v 1.7 1998/07/29 20:50:12 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -66,6 +66,8 @@ static void usbd_transfer_cb __P((usbd_request_handle reqh)); static void usbd_sync_transfer_cb __P((usbd_request_handle reqh)); static usbd_status usbd_do_transfer __P((usbd_request_handle reqh)); static usbd_status usbd_start __P((usbd_pipe_handle pipe)); +void usbd_do_request_async_cb + __P((usbd_request_handle, usbd_private_handle, usbd_status)); static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests; @@ -479,7 +481,7 @@ usbd_clear_endpoint_stall(pipe) req.bmRequestType = UT_WRITE_ENDPOINT; req.bRequest = UR_CLEAR_FEATURE; USETW(req.wValue, UF_ENDPOINT_STALL); - USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); /* XXX mask/ */ + USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); USETW(req.wLength, 0); r = usbd_do_request(dev, &req, 0); #if 0 @@ -492,6 +494,23 @@ XXX should we do this? return (r); } +usbd_status +usbd_clear_endpoint_stall_async(pipe) + usbd_pipe_handle pipe; +{ + usbd_device_handle dev = pipe->device; + usb_device_request_t req; + usbd_status r; + + req.bmRequestType = UT_WRITE_ENDPOINT; + req.bRequest = UR_CLEAR_FEATURE; + USETW(req.wValue, UF_ENDPOINT_STALL); + USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); + USETW(req.wLength, 0); + r = usbd_do_request_async(dev, &req, 0); + return (r); +} + usbd_status usbd_set_pipe_state(pipe, state) usbd_pipe_handle pipe; @@ -914,6 +933,13 @@ usbd_do_request(dev, req, data) usbd_request_handle reqh; usbd_status r; +#ifdef DIAGNOSTIC + if (!curproc) { + printf("usbd_do_request: not in process context\n"); + return (USBD_XXX); + } +#endif + reqh = usbd_alloc_request(); if (reqh == 0) return (USBD_NOMEM); @@ -938,6 +964,54 @@ usbd_do_request(dev, req, data) return (r); } +void +usbd_do_request_async_cb(reqh, priv, status) + usbd_request_handle reqh; + usbd_private_handle priv; + usbd_status status; +{ +#if defined(USB_DEBUG) || defined(DIAGNOSTIC) + if (reqh->actlen > reqh->length) + printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x%02x val=%d index=%d rlen=%d length=%d actlen=%d\n", + reqh->pipe->device->address, + reqh->request.bmRequestType, + reqh->request.bRequest, UGETW(reqh->request.wValue), + UGETW(reqh->request.wIndex), + UGETW(reqh->request.wLength), + reqh->length, reqh->actlen); +#endif + usbd_free_request(reqh); +} + +/* + * Execute a request without waiting for completion. + * Can be used from interrupt context. + */ +usbd_status +usbd_do_request_async(dev, req, data) + usbd_device_handle dev; + usb_device_request_t *req; + void *data; +{ + usbd_request_handle reqh; + usbd_status r; + + reqh = usbd_alloc_request(); + if (reqh == 0) + return (USBD_NOMEM); + r = usbd_setup_default_request( + reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data, + UGETW(req->wLength), 0, usbd_do_request_async_cb); + if (r != USBD_NORMAL_COMPLETION) { + usbd_free_request(reqh); + return (r); + } + r = usbd_transfer(reqh); + if (r != USBD_IN_PROGRESS) + return (r); + return (USBD_NORMAL_COMPLETION); +} + struct usbd_quirks * usbd_get_quirks(dev) usbd_device_handle dev; diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index 28aa44226367..0ad1575ad1a2 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -1,4 +1,4 @@ -/* $NetBSD: usbdi.h,v 1.3 1998/07/26 17:42:49 augustss Exp $ */ +/* $NetBSD: usbdi.h,v 1.4 1998/07/29 20:50:12 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -150,6 +150,7 @@ usbd_status usbd_abort_interface __P((usbd_interface_handle iface)); usbd_status usbd_reset_pipe __P((usbd_pipe_handle pipe)); usbd_status usbd_reset_interface __P((usbd_interface_handle iface)); usbd_status usbd_clear_endpoint_stall __P((usbd_pipe_handle pipe)); +usbd_status usbd_clear_endpoint_stall_async __P((usbd_pipe_handle pipe)); usbd_status usbd_set_pipe_state __P((usbd_pipe_handle pipe, usbd_pipe_state state)); usbd_status usbd_get_pipe_state @@ -207,6 +208,8 @@ usbd_status usbd_open_pipe_intr u_int32_t length, usbd_callback)); usbd_status usbd_do_request __P((usbd_device_handle pipe, usb_device_request_t *req, void *data)); +usbd_status usbd_do_request_async + __P((usbd_device_handle pipe, usb_device_request_t *req, void *data)); usb_interface_descriptor_t *usbd_get_interface_descriptor __P((usbd_interface_handle iface)); usb_config_descriptor_t *usbd_get_config_descriptor diff --git a/sys/dev/usb/usbdi_util.c b/sys/dev/usb/usbdi_util.c index d3ec56cc15a3..ca5197bfeae8 100644 --- a/sys/dev/usb/usbdi_util.c +++ b/sys/dev/usb/usbdi_util.c @@ -1,4 +1,4 @@ -/* $NetBSD: usbdi_util.c,v 1.2 1998/07/13 10:49:42 augustss Exp $ */ +/* $NetBSD: usbdi_util.c,v 1.3 1998/07/29 20:50:12 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -258,6 +258,33 @@ usbd_set_report(iface, type, id, data, len) return (usbd_do_request(dev, &req, data)); } +usbd_status +usbd_set_report_async(iface, type, id, data, len) + usbd_interface_handle iface; + int type; + int id; + void *data; + int len; +{ + usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); + usbd_device_handle dev; + usb_device_request_t req; + usbd_status r; + + DPRINTFN(4, ("usbd_set_report_async: len=%d\n", len)); + r = usbd_interface2device_handle(iface, &dev); + if (r != USBD_NORMAL_COMPLETION) + return (r); + if (!ifd) + return (USBD_INVAL); + req.bmRequestType = UT_WRITE_CLASS_INTERFACE; + req.bRequest = UR_SET_REPORT; + USETW2(req.wValue, type, id); + USETW(req.wIndex, ifd->bInterfaceNumber); + USETW(req.wLength, len); + return (usbd_do_request_async(dev, &req, data)); +} + usbd_status usbd_get_report(iface, type, id, data, len) usbd_interface_handle iface; diff --git a/sys/dev/usb/usbdi_util.h b/sys/dev/usb/usbdi_util.h index b6a463e5cbbb..5ae0d11ec6d9 100644 --- a/sys/dev/usb/usbdi_util.h +++ b/sys/dev/usb/usbdi_util.h @@ -1,4 +1,4 @@ -/* $NetBSD: usbdi_util.h,v 1.2 1998/07/13 10:49:42 augustss Exp $ */ +/* $NetBSD: usbdi_util.h,v 1.3 1998/07/29 20:50:12 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -57,9 +57,11 @@ usbd_status usbd_get_report_descriptor struct usb_hid_descriptor *usbd_get_hid_descriptor __P((usbd_interface_handle ifc)); usbd_status usbd_set_report - __P((usbd_interface_handle iface, int type, int id, void *data, int len)); + __P((usbd_interface_handle iface,int type,int id,void *data,int len)); +usbd_status usbd_set_report_async + __P((usbd_interface_handle iface,int type,int id,void *data,int len)); usbd_status usbd_get_report - __P((usbd_interface_handle iface, int type, int id, void *data, int len)); + __P((usbd_interface_handle iface,int type,int id,void *data,int len)); usbd_status usbd_set_idle __P((usbd_interface_handle iface, int duration, int id)); usbd_status usbd_alloc_report_desc