From owner-p4-projects@FreeBSD.ORG Fri May 11 20:52:55 2007 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id BDF2616A408; Fri, 11 May 2007 20:52:55 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 7028F16A405 for ; Fri, 11 May 2007 20:52:55 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id 5F63E13C457 for ; Fri, 11 May 2007 20:52:55 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.8/8.13.8) with ESMTP id l4BKqt6g006360 for ; Fri, 11 May 2007 20:52:55 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.8/8.13.8/Submit) id l4BKqsrG006347 for perforce@freebsd.org; Fri, 11 May 2007 20:52:54 GMT (envelope-from hselasky@FreeBSD.org) Date: Fri, 11 May 2007 20:52:54 GMT Message-Id: <200705112052.l4BKqsrG006347@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 119692 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 11 May 2007 20:52:56 -0000 http://perforce.freebsd.org/chv.cgi?CH=119692 Change 119692 by hselasky@hselasky_mini_itx on 2007/05/11 20:52:01 This is a multi patch. I'm sorry I could not split it into three, but I was offline working on this for too long. The first part of this patch opens up the possibility for split control transfers. That means you can allocate any buffer greater or equal to wMaxPacketSize, to transfer any control transfer. This removes the need to allocate a 65535+8 bytes buffer to be able to process any control transfer. If a control transfer is not complete, it will block other control transfers from sending data. The block is removed when the USB transfer is stopped, freed, or has a short packet. The second part of this patch very much improves the synchronization mechanism that is used to make sure that the callbacks of stopped transfers are not called. Before a refcount was incremented to ensure that callbacks were not errornously called. This method has a problem, and that is if there is a flood of USB start/stop calls (+4GB), then the refcount might wrap so that the callback is called anyway. To make this system bullet proof, against this kind of attack, I now use the pointer returned by "curthread" as refcount. If another thread has taken over the callback, then simply the "usb_thread" variable will change, but never back to "curthread", because only the executing thread is allowed to set "usb_thread" equal to "curthread". The trick is to check that the "usb_thread" value is the same before doing the actual callback. The third part of this patch moves the control transfers into a config thread. This has the advantage that DELAY() calls become "msleep()" calls. It is obvious that this will improve the USB stack a little bit. Otherwise: Some code simplifications. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/ehci.c#29 edit .. //depot/projects/usb/src/sys/dev/usb/ehci.h#12 edit .. //depot/projects/usb/src/sys/dev/usb/ehci_pci.c#17 edit .. //depot/projects/usb/src/sys/dev/usb/ohci.c#23 edit .. //depot/projects/usb/src/sys/dev/usb/ohci.h#10 edit .. //depot/projects/usb/src/sys/dev/usb/ohci_pci.c#17 edit .. //depot/projects/usb/src/sys/dev/usb/uhci.c#24 edit .. //depot/projects/usb/src/sys/dev/usb/uhci.h#10 edit .. //depot/projects/usb/src/sys/dev/usb/uhci_pci.c#16 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.h#37 edit .. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#23 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/ehci.c#29 (text+ko) ==== @@ -63,6 +63,8 @@ #include #define INCLUDE_PCIXXX_H +#define usbd_config_td_cc ehci_config_copy +#define usbd_config_td_softc ehci_softc #include #include @@ -101,6 +103,9 @@ extern struct usbd_pipe_methods ehci_root_ctrl_methods; extern struct usbd_pipe_methods ehci_root_intr_methods; +static usbd_config_td_command_t ehci_root_ctrl_task; +static void ehci_root_ctrl_task_td(struct ehci_softc *sc, struct thread *ctd); + #define SC_HW_PHYSADDR(sc,what) \ ((sc)->sc_hw_page.physaddr + \ POINTER_TO_UNSIGNED(&(((struct ehci_hw_softc *)0)->what))) @@ -1267,9 +1272,12 @@ static void ehci_pcd_enable(ehci_softc_t *sc) { - struct usbd_callback_info info[1]; + struct thread *td; struct usbd_xfer *xfer; + struct usbd_xfer *xlist[2]; + td = curthread; + mtx_assert(&sc->sc_bus.mtx, MA_OWNED); sc->sc_eintrs |= EHCI_STS_PCD; @@ -1286,14 +1294,15 @@ ehci_device_done(xfer, USBD_NORMAL_COMPLETION); /* queue callback */ - info[0].xfer = xfer; - info[0].refcount = xfer->usb_refcount; + xlist[0] = xfer; + xlist[1] = NULL; + xfer->usb_thread = td; xfer->usb_root->memory_refcount++; mtx_unlock(&sc->sc_bus.mtx); - usbd_do_callback(&info[0],&info[1]); + usbd_do_callback(xlist, td); } else { @@ -1307,12 +1316,15 @@ { enum { FINISH_LIST_MAX = 16 }; - struct usbd_callback_info info[FINISH_LIST_MAX]; - struct usbd_callback_info *ptr = &info[0]; + struct usbd_xfer *xlist[FINISH_LIST_MAX+1]; + struct usbd_xfer **xptr = xlist; struct usbd_xfer *xfer; + struct thread *td; u_int32_t status; u_int8_t need_repeat = 0; + td = ctd; /* default value */ + mtx_lock(&sc->sc_bus.mtx); /* @@ -1338,6 +1350,8 @@ goto repeat; } + td = curthread; /* NULL is not a valid thread */ + sc->sc_bus.no_intrs++; DPRINTFN(15,("%s: real interrupt\n", @@ -1392,10 +1406,10 @@ ehci_device_done(xfer, USBD_NORMAL_COMPLETION); /* queue callback */ - ptr->xfer = xfer; - ptr->refcount = xfer->usb_refcount; - ptr++; + + *(xptr++) = xfer; + xfer->usb_thread = td; xfer->usb_root->memory_refcount++; } @@ -1431,14 +1445,14 @@ if(ehci_check_transfer(xfer, ctd)) { /* queue callback */ - ptr->xfer = xfer; - ptr->refcount = xfer->usb_refcount; - ptr++; + + *(xptr++) = xfer; + xfer->usb_thread = td; xfer->usb_root->memory_refcount++; /* check queue length */ - if(ptr >= &info[FINISH_LIST_MAX]) + if (xptr >= &xlist[FINISH_LIST_MAX]) { need_repeat = 1; break; @@ -1449,11 +1463,14 @@ done: mtx_unlock(&sc->sc_bus.mtx); - usbd_do_callback(&info[0],ptr); + /* zero terminate the callback list */ + *(xptr) = NULL; + + usbd_do_callback(xlist, td); if(need_repeat) { - ptr = &info[0]; + xptr = xlist; need_repeat = 0; @@ -1477,9 +1494,12 @@ static void ehci_timeout(struct usbd_xfer *xfer) { - struct usbd_callback_info info[1]; + struct thread *td; + struct usbd_xfer *xlist[2]; ehci_softc_t *sc = xfer->usb_sc; + td = curthread; + DPRINTF(("xfer=%p\n", xfer)); mtx_assert(&sc->sc_bus.mtx, MA_OWNED); @@ -1488,14 +1508,15 @@ ehci_device_done(xfer, USBD_TIMEOUT); /* queue callback */ - info[0].xfer = xfer; - info[0].refcount = xfer->usb_refcount; + xlist[0] = xfer; + xlist[1] = NULL; + xfer->usb_thread = td; xfer->usb_root->memory_refcount++; mtx_unlock(&sc->sc_bus.mtx); - usbd_do_callback(&info[0],&info[1]); + usbd_do_callback(xlist, td); return; } @@ -1503,7 +1524,12 @@ static void ehci_do_poll(struct usbd_bus *bus) { - ehci_interrupt_td(EHCI_BUS2SC(bus), curthread); + struct ehci_softc *sc = EHCI_BUS2SC(bus); + struct thread *ctd = curthread; + ehci_interrupt_td(sc, ctd); + mtx_lock(&(sc->sc_bus.mtx)); + ehci_root_ctrl_task_td(sc, ctd); + mtx_unlock(&(sc->sc_bus.mtx)); return; } @@ -1532,7 +1558,7 @@ uint32_t qh_endp; uint32_t qh_endphub; u_int32_t buf_offset; - u_int32_t len = xfer->length; + u_int32_t len; u_int32_t c_error = (xfer->udev->speed == USB_SPEED_HIGH) ? 0 : htole32(EHCI_QTD_SET_CERR(3)); @@ -1555,16 +1581,14 @@ force_short = (xfer->flags & USBD_FORCE_SHORT_XFER) ? 1 : 0; + len = xfer->length; + if(xfer->pipe->methods == &ehci_device_ctrl_methods) { - /* the first byte is "bmRequestType" */ + isread = xfer->control_isread; - isread = *((u_int8_t *)(buf_res.buffer)); - isread &= UT_READ; + if (xfer->flags & USBD_DEV_CONTROL_HEADER) { - /* - * check length ? - */ xfer->pipe->toggle_next = 1; usbd_page_dma_exit(td->page); @@ -1601,12 +1625,23 @@ } usbd_page_dma_enter(td_last->page); + } else { + if (len == 0) { + /* When the length is zero we + * queue a short packet! + * This also makes "td_last" + * non-zero. + */ + DPRINTFN(0, ("short transfer!\n")); + force_short = 1; + } + } } else { isread = (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN); - if (xfer->length == 0) { + if (len == 0) { /* When the length is zero we * queue a short packet! * This also makes "td_last" @@ -1713,6 +1748,8 @@ if(xfer->pipe->methods == &ehci_device_ctrl_methods) { + if (xfer->control_remainder == 0) { + usbd_page_dma_exit(td->page); /* STATUS message */ @@ -1732,10 +1769,14 @@ td->qtd_buffer[0] = 0; td->qtd_buffer_hi[0] = 0; + td->qtd_buffer[1] = 0; + td->qtd_buffer_hi[1] = 0; + td->len = 0; td_last = td; usbd_page_dma_enter(td_last->page); + } } usbd_page_dma_exit(td_last->page); @@ -1840,7 +1881,7 @@ u_int16_t i; u_int16_t m; - if(sc->sc_intrxfer) + if (sc->sc_intrxfer == xfer) { /* disable further interrupts */ sc->sc_intrxfer = NULL; @@ -2022,6 +2063,7 @@ static void ehci_device_done(struct usbd_xfer *xfer, usbd_status error) { + struct usbd_pipe_methods *methods = xfer->pipe->methods; ehci_softc_t *sc = xfer->usb_sc; u_int8_t need_delay; @@ -2044,8 +2086,8 @@ } } - if((xfer->pipe->methods == &ehci_device_bulk_methods) || - (xfer->pipe->methods == &ehci_device_ctrl_methods)) + if ((methods == &ehci_device_bulk_methods) || + (methods == &ehci_device_ctrl_methods)) { #ifdef USB_DEBUG if(ehcidebug > 8) @@ -2059,7 +2101,7 @@ EHCI_REMOVE_QH(xfer->qh_start, sc->sc_async_p_last); } - if(xfer->pipe->methods == &ehci_device_intr_methods) + if (methods == &ehci_device_intr_methods) { EHCI_REMOVE_QH(xfer->qh_start, sc->sc_intr_p_last[xfer->qh_pos]); } @@ -2071,7 +2113,7 @@ if(xfer->td_transfer_first && xfer->td_transfer_last) { - if(xfer->pipe->methods == &ehci_device_isoc_fs_methods) + if (methods == &ehci_device_isoc_fs_methods) { if(ehci_isoc_fs_done(sc, xfer)) { @@ -2079,7 +2121,7 @@ } } - if(xfer->pipe->methods == &ehci_device_isoc_hs_methods) + if (methods == &ehci_device_isoc_hs_methods) { if(ehci_isoc_hs_done(sc, xfer)) { @@ -2094,7 +2136,7 @@ /* finish root interrupt transfer * (will update xfer->buffer and xfer->actlen) */ - if(xfer->pipe->methods == &ehci_root_intr_methods) + if (methods == &ehci_root_intr_methods) { ehci_root_intr_done(sc, xfer); } @@ -2105,11 +2147,11 @@ /* remove interrupt info (if any) */ ehci_remove_interrupt_info(xfer); - if ((xfer->pipe->methods != &ehci_root_ctrl_methods) && - (xfer->pipe->methods != &ehci_root_intr_methods)) { + if ((methods != &ehci_root_ctrl_methods) && + (methods != &ehci_root_intr_methods)) { - if(((xfer->pipe->methods == &ehci_device_ctrl_methods) || - (xfer->pipe->methods == &ehci_device_bulk_methods)) && + if(((methods == &ehci_device_ctrl_methods) || + (methods == &ehci_device_bulk_methods)) && (sc->sc_doorbell_disable == 0)) { u_int32_t to = 100*1000; @@ -2259,6 +2301,11 @@ static void ehci_device_ctrl_enter(struct usbd_xfer *xfer) { + if (usbd_std_ctrl_enter(xfer)) { + /* error */ + return; + } + /* enqueue transfer */ usbd_transfer_enqueue(xfer); return; @@ -2985,6 +3032,12 @@ static void ehci_root_ctrl_close(struct usbd_xfer *xfer) { + ehci_softc_t *sc = xfer->usb_sc; + + if (sc->sc_hub_xfer == xfer) { + sc->sc_hub_xfer = NULL; + } + ehci_device_done(xfer, USBD_CANCELLED); return; } @@ -3022,9 +3075,8 @@ 0 }; -static const -usb_config_descriptor_t ehci_confd = -{ +static const struct ehci_config_desc ehci_confd = { + .confd = { sizeof(usb_config_descriptor_t), UDESC_CONFIG, {USB_CONFIG_DESCRIPTOR_SIZE + @@ -3035,11 +3087,9 @@ 0, UC_SELF_POWERED, 0 /* max power */ -}; + }, -static const -usb_interface_descriptor_t ehci_ifcd = -{ + .ifcd = { sizeof(usb_interface_descriptor_t), UDESC_INTERFACE, 0, @@ -3049,17 +3099,16 @@ UISUBCLASS_HUB, UIPROTO_HSHUBSTT, 0 -}; + }, -static const -usb_endpoint_descriptor_t ehci_endpd = -{ + .endpd = { sizeof(usb_endpoint_descriptor_t), UDESC_ENDPOINT, UE_DIR_IN | EHCI_INTR_ENDPT, UE_INTERRUPT, {8, 0}, /* max packet */ 255 + }, }; static const @@ -3075,7 +3124,7 @@ }; static void -ehci_disown(ehci_softc_t *sc, int index, int lowspeed) +ehci_disown(ehci_softc_t *sc, uint16_t index, uint8_t lowspeed) { u_int32_t port; u_int32_t v; @@ -3090,60 +3139,123 @@ static void ehci_root_ctrl_enter(struct usbd_xfer *xfer) { + if (usbd_std_ctrl_enter(xfer)) { + /* error */ + return; + } + + /* enqueue transfer */ + usbd_transfer_enqueue(xfer); + return; +} + +static void +ehci_root_ctrl_start(struct usbd_xfer *xfer) +{ ehci_softc_t *sc = xfer->usb_sc; + + sc->sc_hub_xfer = xfer; + + usbd_config_td_queue_command + (&(sc->sc_config_td), NULL, &ehci_root_ctrl_task, 0, 0); + + return; +} + +static void +ehci_root_ctrl_task(struct ehci_softc *sc, + struct ehci_config_copy *cc, uint16_t refcount) +{ + ehci_root_ctrl_task_td(sc, NULL); + return; +} + +static void +ehci_root_ctrl_task_td(struct ehci_softc *sc, struct thread *ctd) +{ + usb_device_request_t req; + struct usbd_xfer *xlist[2]; + struct usbd_xfer *xfer; + struct thread *td; + char *ptr; u_int32_t port; u_int32_t v; u_int16_t i; u_int16_t len; u_int16_t value; u_int16_t index; - u_int16_t l; - u_int16_t totlen = 0; - union { - usb_status_t stat; - usb_port_status_t ps; - usb_device_request_t req; - usb_hub_descriptor_t hubd; - usb_device_descriptor_t devd; - usb_device_qualifier_t odevd; - usb_config_descriptor_t confd; - usb_interface_descriptor_t ifcd; - usb_endpoint_descriptor_t endpd; - u_int8_t str_temp[128]; - u_int8_t byte_temp; - } u; + u_int8_t l; usbd_status err; mtx_assert(&sc->sc_bus.mtx, MA_OWNED); - if (xfer->length < sizeof(u.req)) { - err = USBD_INVAL; - goto done; + xfer = sc->sc_hub_xfer; + if (xfer == NULL) { + /* the transfer is gone */ + return; + } + + if (xfer->usb_thread != ctd) { + /* we should not call this transfer back */ + return; + } + + sc->sc_hub_xfer = NULL; + + td = ctd; + if (td == NULL) { + td = curthread; } - /* set default actual length */ - xfer->actlen = sizeof(u.req); + /* queue callback */ + xlist[0] = xfer; + xlist[1] = NULL; + + /* make sure that the memory does not disappear! */ + xfer->usb_thread = td; + xfer->usb_root->memory_refcount++; + + if (!(xfer->flags & USBD_DEV_CONTROL_HEADER)) { + + len = MIN(xfer->length, sc->sc_hub_len); + + /* set actual length */ + xfer->actlen = len; + + if (len) { - /* copy out "request" */ - usbd_copy_out(&(xfer->buf_data), 0, &u.req, sizeof(u.req)); + /* copy in data */ + usbd_copy_in(&(xfer->buf_data), 0, sc->sc_hub_ptr, len); - len = (xfer->length - sizeof(u.req)); + /* update pointer and length */ + sc->sc_hub_ptr += len; + sc->sc_hub_len -= len; + } - if (len != UGETW(u.req.wLength)) { - err = USBD_INVAL; + err = USBD_NORMAL_COMPLETION; goto done; } - value = UGETW(u.req.wValue); - index = UGETW(u.req.wIndex); + /* set default actual length, in case of error */ + xfer->actlen = sizeof(req); + + /* buffer reset */ + sc->sc_hub_ptr = sc->sc_hub_desc.temp; + sc->sc_hub_len = 0; + + /* copy out the USB request */ + usbd_copy_out(&(xfer->buf_data), 0, &req, sizeof(req)); + + value = UGETW(req.wValue); + index = UGETW(req.wIndex); DPRINTFN(2,("type=0x%02x request=0x%02x wLen=0x%04x " "wValue=0x%04x wIndex=0x%04x\n", - u.req.bmRequestType, u.req.bRequest, - len, value, index)); + req.bmRequestType, req.bRequest, + UGETW(req.wLength), value, index)); #define C(x,y) ((x) | ((y) << 8)) - switch(C(u.req.bRequest, u.req.bmRequestType)) { + switch(C(req.bRequest, req.bmRequestType)) { case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): @@ -3153,13 +3265,8 @@ */ break; case C(UR_GET_CONFIG, UT_READ_DEVICE): - if(len > 0) - { - u.byte_temp = sc->sc_conf; - totlen = 1; - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &u, totlen); - } + sc->sc_hub_len = 1; + sc->sc_hub_desc.temp[0] = sc->sc_conf; break; case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): switch(value >> 8) { @@ -3169,15 +3276,8 @@ err = USBD_IOERROR; goto done; } - totlen = min(len, sizeof(u.devd)); - - u.devd = ehci_devd; -#if 0 - USETW(u.devd.idVendor, - sc->sc_id_vendor); -#endif - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &u, totlen); + sc->sc_hub_len = sizeof(ehci_devd); + sc->sc_hub_desc.devd = ehci_devd; break; /* * We can't really operate at another speed, @@ -3190,9 +3290,8 @@ err = USBD_IOERROR; goto done; } - totlen = min(len, sizeof(ehci_odevd)); - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &ehci_odevd, totlen); + sc->sc_hub_len = sizeof(ehci_odevd); + sc->sc_hub_desc.odevd = ehci_odevd; break; /* * We can't really operate at another speed, @@ -3206,67 +3305,35 @@ err = USBD_IOERROR; goto done; } - totlen = l = min(len, sizeof(u.confd)); - len -= l; - - u.confd = ehci_confd; - u.confd.bDescriptorType = (value >> 8); - - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &u, l); - - l = min(len, sizeof(ehci_ifcd)); - totlen += l; - len -= l; - - usbd_copy_in(&(xfer->buf_data), sizeof(u.req) + - sizeof(u.confd), &ehci_ifcd, l); - - l = min(len, sizeof(ehci_endpd)); - totlen += l; - len -= l; - - usbd_copy_in(&(xfer->buf_data), sizeof(u.req) + - sizeof(u.confd) + sizeof(u.ifcd), - &ehci_endpd, l); + sc->sc_hub_len = sizeof(ehci_confd); + sc->sc_hub_desc.confd = ehci_confd; + sc->sc_hub_desc.confd.confd.bDescriptorType = + (value >> 8); break; case UDESC_STRING: - if(len == 0) - { - break; - } - switch (value & 0xff) { case 0: /* Language table */ - totlen = usbd_make_str_desc - (u.str_temp, sizeof(u.str_temp), - "\001"); + ptr = "\001"; break; case 1: /* Vendor */ - totlen = usbd_make_str_desc - (u.str_temp, sizeof(u.str_temp), - sc->sc_vendor); + ptr = sc->sc_vendor; break; case 2: /* Product */ - totlen = usbd_make_str_desc - (u.str_temp, sizeof(u.str_temp), - "EHCI root hub"); + ptr = "EHCI root hub"; break; default: - totlen = usbd_make_str_desc - (u.str_temp, sizeof(u.str_temp), - ""); + ptr = ""; break; } - if (totlen > len) { - totlen = len; - } - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &u, totlen); + + sc->sc_hub_len = usbd_make_str_desc + (sc->sc_hub_desc.temp, + sizeof(sc->sc_hub_desc.temp), + ptr); break; default: err = USBD_IOERROR; @@ -3274,32 +3341,17 @@ } break; case C(UR_GET_INTERFACE, UT_READ_INTERFACE): - if(len > 0) - { - u.byte_temp = 0; - totlen = 1; - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &u, totlen); - } + sc->sc_hub_len = 1; + sc->sc_hub_desc.temp[0] = 0; break; case C(UR_GET_STATUS, UT_READ_DEVICE): - if(len > 1) - { - USETW(u.stat.wStatus,UDS_SELF_POWERED); - totlen = 2; - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &u, totlen); - } + sc->sc_hub_len = 2; + USETW(sc->sc_hub_desc.stat.wStatus,UDS_SELF_POWERED); break; case C(UR_GET_STATUS, UT_READ_INTERFACE): case C(UR_GET_STATUS, UT_READ_ENDPOINT): - if(len > 1) - { - USETW(u.stat.wStatus, 0); - totlen = 2; - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &u, totlen); - } + sc->sc_hub_len = 2; + USETW(sc->sc_hub_desc.stat.wStatus, 0); break; case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): if(value >= USB_MAX_DEVICES) @@ -3340,7 +3392,6 @@ err = USBD_IOERROR; goto done; } - port = EHCI_PORTSC(index); v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR; switch(value) { @@ -3409,31 +3460,24 @@ v = EOREAD4(sc, EHCI_HCSPARAMS); - u.hubd = ehci_hubd; - u.hubd.bNbrPorts = sc->sc_noport; - USETW(u.hubd.wHubCharacteristics, + sc->sc_hub_desc.hubd = ehci_hubd; + sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; + USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, (EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH) | (EHCI_HCS_P_INDICATOR(EREAD4(sc, EHCI_HCSPARAMS)) ? UHD_PORT_IND : 0)); - u.hubd.bPwrOn2PwrGood = 200; /* XXX can't find out? */ + sc->sc_hub_desc.hubd.bPwrOn2PwrGood = 200; /* XXX can't find out? */ for(l = 0; l < sc->sc_noport; l++) { /* XXX can't find out? */ - u.hubd.DeviceRemovable[l/8] &= ~(1 << (l % 8)); + sc->sc_hub_desc.hubd.DeviceRemovable[l/8] &= ~(1 << (l % 8)); } - u.hubd.bDescLength = (USB_HUB_DESCRIPTOR_SIZE-1) + ((sc->sc_noport + 7)/8); - totlen = min(len, u.hubd.bDescLength); - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &u, totlen); + sc->sc_hub_desc.hubd.bDescLength = (USB_HUB_DESCRIPTOR_SIZE-1) + ((sc->sc_noport + 7)/8); + sc->sc_hub_len = sc->sc_hub_desc.hubd.bDescLength; break; case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): - if(len < 4) - { - err = USBD_IOERROR; - goto done; - } - usbd_bzero(&(xfer->buf_data), sizeof(u.req), len); - totlen = len; + sc->sc_hub_len = 16; + bzero(sc->sc_hub_desc.temp, 16); break; case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): DPRINTFN(8,("get port status i=%d\n", @@ -3444,11 +3488,6 @@ err = USBD_IOERROR; goto done; } - if(len < 4) - { - err = USBD_IOERROR; - goto done; - } v = EOREAD4(sc, EHCI_PORTSC(index)); DPRINTFN(8,("port status=0x%04x\n", v)); i = UPS_HIGH_SPEED; @@ -3458,16 +3497,14 @@ if(v & EHCI_PS_OCA) i |= UPS_OVERCURRENT_INDICATOR; if(v & EHCI_PS_PR) i |= UPS_RESET; if(v & EHCI_PS_PP) i |= UPS_PORT_POWER; - USETW(u.ps.wPortStatus, i); + USETW(sc->sc_hub_desc.ps.wPortStatus, i); i = 0; if(v & EHCI_PS_CSC) i |= UPS_C_CONNECT_STATUS; if(v & EHCI_PS_PEC) i |= UPS_C_PORT_ENABLED; if(v & EHCI_PS_OCC) i |= UPS_C_OVERCURRENT_INDICATOR; if(sc->sc_isreset) i |= UPS_C_PORT_RESET; - USETW(u.ps.wPortChange, i); - totlen = min(len, sizeof(u.ps)); - usbd_copy_in(&(xfer->buf_data), sizeof(u.req), - &u, totlen); + USETW(sc->sc_hub_desc.ps.wPortChange, i); + sc->sc_hub_len = sizeof(sc->sc_hub_desc.ps); break; case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): err = USBD_IOERROR; @@ -3501,13 +3538,30 @@ /* Start reset sequence. */ v &= ~ (EHCI_PS_PE | EHCI_PS_PR); EOWRITE4(sc, port, v | EHCI_PS_PR); - /* Wait for reset to complete. */ - DELAY(1000*USB_PORT_ROOT_RESET_DELAY); + + if (ctd) { + /* polling */ + DELAY(USB_PORT_ROOT_RESET_DELAY * 1000); + } else { + /* Wait for reset to complete. */ + l = usbd_config_td_sleep + (&(sc->sc_config_td), + (hz * USB_PORT_ROOT_RESET_DELAY) / 1000); + } /* Terminate reset sequence. */ EOWRITE4(sc, port, v); - /* Wait for HC to complete reset. */ - DELAY(1000*EHCI_PORT_RESET_COMPLETE); + + if (ctd) { + /* polling */ + DELAY(EHCI_PORT_RESET_COMPLETE * 1000); + } else { + /* Wait for HC to complete reset. */ + l = usbd_config_td_sleep + (&(sc->sc_config_td), + (hz * EHCI_PORT_RESET_COMPLETE) / 1000); + } + v = EOREAD4(sc, port); DPRINTF(("ehci after reset, status=0x%08x\n", v)); if(v & EHCI_PS_PR) @@ -3559,23 +3613,46 @@ goto done; } - xfer->actlen = totlen + sizeof(u.req); + if (xfer->usb_thread != td) { + /* do nothing */ + return; + } + + len = xfer->length - sizeof(req); + if (len > sc->sc_hub_len) { + len = sc->sc_hub_len; + } + + /* update actual length */ + xfer->actlen += len; + + if (len) { + + /* copy in data, if any */ + usbd_copy_in(&(xfer->buf_data), sizeof(req), + sc->sc_hub_ptr, len); + + /* update pointer and length */ + sc->sc_hub_ptr += len; + sc->sc_hub_len -= len; + } err = USBD_NORMAL_COMPLETION; done: + if (xfer->usb_thread != td) { + /* do nothing */ + return; + } + /* transfer transferred */ ehci_device_done(xfer, err); - /* call callback recursively */ - __usbd_callback(xfer); + mtx_unlock(&(sc->sc_bus.mtx)); + + usbd_do_callback(xlist, td); - return; -} + mtx_lock(&(sc->sc_bus.mtx)); -static void -ehci_root_ctrl_start(struct usbd_xfer *xfer) -{ - /* not used */ return; } ==== //depot/projects/usb/src/sys/dev/usb/ehci.h#12 (text+ko) ==== @@ -395,21 +395,41 @@ ehci_sitd_t isoc_fs_start[EHCI_VIRTUAL_FRAMELIST_COUNT]; }; +struct ehci_config_desc { + usb_config_descriptor_t confd; + usb_interface_descriptor_t ifcd; + usb_endpoint_descriptor_t endpd; +} __packed; + +union ehci_hub_desc { + usb_status_t stat; + usb_port_status_t ps; + usb_device_descriptor_t devd; + usb_device_qualifier_t odevd; + usb_hub_descriptor_t hubd; + struct ehci_config_desc confd; + uint8_t temp[128]; +}; + typedef struct ehci_softc { struct usbd_page sc_hw_page; struct usbd_bus sc_bus; /* base device */ + struct usbd_config_td sc_config_td; struct __callout sc_tmo_pcd; LIST_HEAD(, usbd_xfer) sc_interrupt_list_head; + union ehci_hub_desc sc_hub_desc; struct ehci_hw_softc *sc_hw_ptr; struct resource *sc_io_res; struct resource *sc_irq_res; struct usbd_xfer *sc_intrxfer; + struct usbd_xfer *sc_hub_xfer; struct ehci_qh *sc_async_p_last; struct ehci_qh *sc_intr_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]; struct ehci_sitd *sc_isoc_fs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]; struct ehci_itd *sc_isoc_hs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]; void *sc_intr_hdl; >>> TRUNCATED FOR MAIL (1000 lines) <<<