Date: Sat, 8 Jul 2006 09:09:14 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 100971 for review Message-ID: <200607080909.k6899EJf044122@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=100971 Change 100971 by hselasky@hselasky_mini_itx on 2006/07/08 09:09:13 All USB hosts controllers now allocate DMA-able memory in chunks of PAGE_SIZE bytes. This should allow the USB system to operate also when then host memory becomes fragmented. There are alot of changes. Please test. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/ehci.c#6 edit .. //depot/projects/usb/src/sys/dev/usb/ehci.h#3 edit .. //depot/projects/usb/src/sys/dev/usb/ehci_pci.c#5 edit .. //depot/projects/usb/src/sys/dev/usb/ohci.c#6 edit .. //depot/projects/usb/src/sys/dev/usb/ohci.h#3 edit .. //depot/projects/usb/src/sys/dev/usb/ohci_pci.c#5 edit .. //depot/projects/usb/src/sys/dev/usb/uhci.c#6 edit .. //depot/projects/usb/src/sys/dev/usb/uhci.h#3 edit .. //depot/projects/usb/src/sys/dev/usb/uhci_pci.c#5 edit .. //depot/projects/usb/src/sys/dev/usb/usb.c#5 edit .. //depot/projects/usb/src/sys/dev/usb/usb.h#4 edit .. //depot/projects/usb/src/sys/dev/usb/usb_port.h#5 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.c#7 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.h#11 edit .. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#6 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/ehci.c#6 (text+ko) ==== @@ -60,8 +60,6 @@ #include <sys/lock.h> #include <sys/malloc.h> -#include <machine/bus.h> /* bus_space_xxx() */ - #define INCLUDE_PCIXXX_H #include <dev/usb/usb_port.h> @@ -671,11 +669,11 @@ static void ehci_dump_sqtds(ehci_qtd_t *sqtd) { - int i; + u_int16_t i; u_int32_t stop; stop = 0; - for(i = 0; sqtd && (i < 20) && !stop; sqtd = sqtd->next, i++) + for(i = 0; sqtd && (i < 20) && !stop; sqtd = sqtd->obj_next, i++) { ehci_dump_sqtd(sqtd); stop = sqtd->qtd_next & htole32(EHCI_LINK_TERMINATE); @@ -987,7 +985,7 @@ /* the transfer is done, compute actual length and status */ for (; td != NULL; - td = td->next) + td = ((td == xfer->td_transfer_last) ? NULL : td->obj_next)) { if(td->qtd_status & htole32(EHCI_QTD_ACTIVE)) { @@ -1123,7 +1121,7 @@ for(td = xfer->td_transfer_first; td != NULL; - td = td->next) + td = ((td == xfer->td_transfer_last) ? NULL : td->obj_next)) { u_int32_t status; @@ -1403,7 +1401,7 @@ if((xfer)->interrupt_list.le_prev) { LIST_REMOVE((xfer), interrupt_list); - (xfer)->interrupt_list.le_prev = 0; + (xfer)->interrupt_list.le_prev = NULL; } return; } @@ -1411,19 +1409,20 @@ static void ehci_setup_standard_chain(struct usbd_xfer *xfer, ehci_qh_t **qh_last) { + struct usbd_page_search buf_res; /* the EHCI hardware can handle at most five 4k crossing per TD */ - u_int32_t average = ((unsigned)(EHCI_PAGE_SIZE / xfer->max_packet_size)) - * xfer->max_packet_size; + u_int32_t average = (EHCI_PAGE_SIZE - (EHCI_PAGE_SIZE % + xfer->max_packet_size)); u_int32_t qtd_status; - u_int32_t physbuffer = xfer->physbuffer; + u_int32_t buf_offset; u_int32_t len = xfer->length; u_int32_t c_error = (xfer->udev->speed == USB_SPEED_HIGH) ? 0 : htole32(EHCI_QTD_SET_CERR(3)); u_int8_t isread; u_int8_t shortpkt = 0; - ehci_qtd_t *td; + ehci_qtd_t *td_last = NULL; ehci_qh_t *qh; DPRINTFN(8, ("addr=%d endpt=%d len=%d speed=%d\n", @@ -1432,41 +1431,43 @@ td = (xfer->td_transfer_first = xfer->td_start); + buf_offset = 0; + usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res); + if(xfer->pipe->methods == &ehci_device_ctrl_methods) { - isread = ((usb_device_request_t *)(xfer->buffer))-> - bmRequestType & UT_READ; + /* the first byte is "bmRequestType" */ + + isread = *((u_int8_t *)(buf_res.buffer)); + isread &= UT_READ; - /* xfer->length = sizeof(usb_device_request_t) + - * UGETW(req->wLength) - * check length ?? + /* + * check length ? */ xfer->pipe->toggle_next = 1; /* SETUP message */ - td->next = (td+1); - td->qtd_next = (td+1)->qtd_self; - td->qtd_altnext = htole32(EHCI_LINK_TERMINATE); - td->qtd_status = c_error | htole32 (EHCI_QTD_ACTIVE | EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) | EHCI_QTD_SET_TOGGLE(0) | EHCI_QTD_SET_BYTES(sizeof(usb_device_request_t))); - td->qtd_buffer[0] = htole32(physbuffer); + td->qtd_buffer[0] = htole32(buf_res.physaddr); td->qtd_buffer_hi[0] = 0; + + buf_offset += sizeof(usb_device_request_t); + usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res); + td->qtd_buffer[1] = - htole32(physbuffer + sizeof(usb_device_request_t)) & - htole32(~0xfff); + htole32(buf_res.physaddr & (~0xFFF)); td->qtd_buffer_hi[1] = 0; td->len = sizeof(usb_device_request_t); - - physbuffer += sizeof(usb_device_request_t); len -= sizeof(usb_device_request_t); - td++; + td_last = td; + td = td->obj_next; } else { @@ -1474,8 +1475,8 @@ if(xfer->length == 0) { - /* must allow access to (td-1), - * so xfer->length cannot be zero + /* must allow access to "td_last", + * so xfer->length cannot be zero! */ printf("%s: setting USBD_FORCE_SHORT_XFER!\n", __FUNCTION__); @@ -1524,27 +1525,33 @@ average = len; } - if(((void *)td) >= xfer->td_end) + if(td == NULL) { panic("%s: software wants to write more data " "than there is in the buffer!", __FUNCTION__); } - /* fill out TD */ + /* link in last TD */ - td->next = (td+1); - td->qtd_next = (td+1)->qtd_self; + if (td_last) { + td_last->qtd_next = td->qtd_self; + /* short transfers should terminate the transfer: */ + td_last->qtd_altnext = htole32(EHCI_LINK_TERMINATE); + } - /* short transfers should terminate the transfer: */ - td->qtd_altnext = htole32(EHCI_LINK_TERMINATE); + /* fill out current TD */ td->qtd_status = qtd_status | htole32(EHCI_QTD_SET_BYTES(average)); - td->qtd_buffer[0] = htole32(physbuffer); + td->qtd_buffer[0] = htole32(buf_res.physaddr); td->qtd_buffer_hi[0] = 0; + + buf_offset += average; + usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res); + td->qtd_buffer[1] = - htole32(physbuffer + average) & htole32(~0xfff); + htole32(buf_res.physaddr & (~0xFFF)); td->qtd_buffer_hi[1] = 0; td->len = average; @@ -1562,13 +1569,19 @@ qtd_status ^= htole32(EHCI_QTD_TOGGLE_MASK); } - physbuffer += average; len -= average; - td++; + td_last = td; + td = td->obj_next; } if(xfer->pipe->methods == &ehci_device_ctrl_methods) { + /* link in last TD */ + + td_last->qtd_next = td->qtd_self; + /* short transfers should terminate the transfer: */ + td_last->qtd_altnext = htole32(EHCI_LINK_TERMINATE); + /* STATUS message */ td->qtd_status = c_error | (isread ? @@ -1586,26 +1599,17 @@ td->qtd_buffer[0] = 0; td->qtd_buffer_hi[0] = 0; - td->next = NULL; - td->qtd_next = htole32(EHCI_LINK_TERMINATE); - td->qtd_altnext = htole32(EHCI_LINK_TERMINATE); td->len = 0; + td_last = td; + } - physbuffer += 0; - len -= 0; - td++; - } - else - { - (td-1)->next = NULL; - (td-1)->qtd_next = htole32(EHCI_LINK_TERMINATE); - (td-1)->qtd_altnext = htole32(EHCI_LINK_TERMINATE); - (td-1)->qtd_status |= htole32(EHCI_QTD_IOC); - } + td_last->qtd_next = htole32(EHCI_LINK_TERMINATE); + td_last->qtd_altnext = htole32(EHCI_LINK_TERMINATE); + td_last->qtd_status |= htole32(EHCI_QTD_IOC); /* must have at least one frame! */ - xfer->td_transfer_last = (td-1); + xfer->td_transfer_last = td_last; #ifdef USB_DEBUG if(ehcidebug > 8) @@ -1615,9 +1619,11 @@ ehci_dump_sqtds(xfer->td_start); } #endif + qh = xfer->qh_start; - /* qh_link filled when the QH is added */ + /* the "qh_link" field is filled when the QH is added */ + qh->qh_endp = htole32 (EHCI_QH_SET_ADDR(xfer->address) | EHCI_QH_SET_ENDPT(UE_GET_ADDR(xfer->endpoint)) | @@ -1626,8 +1632,6 @@ EHCI_QH_SET_NRL(8) /* XXX */ ); - /* XXX have data toogle in qh */ - switch (xfer->udev->speed) { case USB_SPEED_LOW: qh->qh_endp |= htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_LOW)| @@ -1683,26 +1687,35 @@ static void ehci_root_intr_done(ehci_softc_t *sc, struct usbd_xfer *xfer) { + struct usbd_page_search buf_res; u_int8_t *p; - int i, m; + u_int16_t i; + u_int16_t m; if(sc->sc_intrxfer) { /* disable further interrupts */ sc->sc_intrxfer = NULL; - p = xfer->buffer; - m = min(sc->sc_noport, (xfer->length * 8) - 1); - memset(p, 0, xfer->length); - for(i = 1; i <= m; i++) + /* clear all bits */ + usbd_bzero(&(xfer->buf_data), 0, xfer->length); + + /* set bits */ + m = (xfer->length * 8); + i = (sc->sc_noport + 1); + m = min(m,i); + for(i = 1; i < m; i++) { /* pick out CHANGE bits from the status register */ if(EOREAD4(sc, EHCI_PORTSC(i)) & EHCI_PS_CLEAR) { - p[i/8] |= 1 << (i%8); + usbd_get_page(&(xfer->buf_data), i/8, &buf_res); + p = buf_res.buffer; + *p |= 1 << (i % 8); + + DPRINTF(("port %d changed\n", i)); } } - DPRINTF(("change=0x%02x\n", *p)); xfer->actlen = xfer->length; } return; @@ -1724,9 +1737,10 @@ while(nframes--) { - if(((void *)td) >= xfer->td_end) + if(td == NULL) { - td = xfer->td_start; + panic("%s:%d: out of TD's\n", + __FUNCTION__, __LINE__); } if(pp_last >= &sc->sc_isoc_fs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]) @@ -1766,7 +1780,7 @@ pp_last++; plen++; - td++; + td = td->obj_next; } xfer->actlen = actlen; @@ -1790,9 +1804,10 @@ while(nframes--) { - if(((void *)td) >= xfer->td_end) + if(td == NULL) { - td = xfer->td_start; + panic("%s:%d: out of TD's\n", + __FUNCTION__, __LINE__); } if(pp_last >= &sc->sc_isoc_hs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]) @@ -1836,7 +1851,7 @@ pp_last++; td_no = 0; - td++; + td = td->obj_next; } } xfer->actlen = actlen; @@ -1915,8 +1930,8 @@ } } - xfer->td_transfer_first = 0; - xfer->td_transfer_last = 0; + xfer->td_transfer_first = NULL; + xfer->td_transfer_last = NULL; } /* finish root interrupt transfer @@ -2044,6 +2059,8 @@ .close = ehci_device_bulk_close, .enter = ehci_device_bulk_enter, .start = ehci_device_bulk_start, + .copy_in = usbd_std_bulk_intr_copy_in, + .copy_out = usbd_std_bulk_intr_copy_out, }; /*---------------------------------------------------------------------------* @@ -2075,15 +2092,6 @@ { ehci_softc_t *sc = xfer->usb_sc; - DPRINTFN(3,("type=0x%02x, request=0x%02x, " - "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n", - ((usb_device_request_t *)(xfer->buffer))->bmRequestType, - ((usb_device_request_t *)(xfer->buffer))->bRequest, - UGETW(((usb_device_request_t *)(xfer->buffer))->wValue), - UGETW(((usb_device_request_t *)(xfer->buffer))->wIndex), - UGETW(((usb_device_request_t *)(xfer->buffer))->wLength), - xfer->address, xfer->endpoint)); - /* setup TD's and QH */ ehci_setup_standard_chain(xfer, &sc->sc_async_p_last); @@ -2104,6 +2112,8 @@ .close = ehci_device_ctrl_close, .enter = ehci_device_ctrl_enter, .start = ehci_device_ctrl_start, + .copy_in = usbd_std_ctrl_copy_in, + .copy_out = usbd_std_ctrl_copy_out, }; /*---------------------------------------------------------------------------* @@ -2194,6 +2204,8 @@ .close = ehci_device_intr_close, .enter = ehci_device_intr_enter, .start = ehci_device_intr_start, + .copy_in = usbd_std_bulk_intr_copy_in, + .copy_out = usbd_std_bulk_intr_copy_out, }; /*---------------------------------------------------------------------------* @@ -2225,9 +2237,7 @@ /* initialize all TD's */ - for(td = xfer->td_start; - ((void *)td) < xfer->td_end; - td++) + for(td = xfer->td_start; td; td = td->obj_next) { td->sitd_portaddr = sitd_portaddr; @@ -2269,14 +2279,16 @@ static void ehci_device_isoc_fs_enter(struct usbd_xfer *xfer) { + struct usbd_page_search buf_res; ehci_softc_t *sc = xfer->usb_sc; - u_int32_t physbuffer; + u_int32_t buf_offset; u_int32_t nframes; u_int16_t *plen; #ifdef USB_DEBUG u_int8_t once = 1; #endif ehci_sitd_t *td; + ehci_sitd_t *td_last = NULL; ehci_sitd_t **pp_last; DPRINTFN(5,("xfer=%p next=%d nframes=%d\n", @@ -2307,7 +2319,8 @@ return; } - physbuffer = xfer->physbuffer; + buf_offset = 0; + usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res); plen = xfer->frlengths; @@ -2321,9 +2334,10 @@ while(nframes--) { - if(((void *)td) >= xfer->td_end) + if(td == NULL) { - td = xfer->td_start; + panic("%s:%d: out of TD's\n", + __FUNCTION__, __LINE__); } if(pp_last >= &sc->sc_isoc_fs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]) @@ -2334,28 +2348,27 @@ /* reuse sitd_portaddr and sitd_back from last transfer */ /* TODO: implement support for multiple transactions */ - if(*plen > 188) + if(*plen > xfer->max_frame_size) { #ifdef USB_DEBUG if(once) { once = 0; - printf("%s: frame length(%d) exceeds %d bytes " - "(frame truncated)\n", - __FUNCTION__, *plen, 188); + printf("%s: frame length(%d) exceeds %d " + "bytes (frame truncated)\n", + __FUNCTION__, *plen, + xfer->max_frame_size); } #endif + *plen = xfer->max_frame_size; + } - /* set new frame length, so that - * a valid transfer can be setup, - * even if synchronization with - * physbuffer is lost - */ - *plen = 188; - } + td->sitd_bp[0] = htole32(buf_res.physaddr); + + buf_offset += *plen; + usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res); - td->sitd_bp[0] = htole32(physbuffer); - td->sitd_bp[1] = htole32((physbuffer + *plen) & ~0xFFF); + td->sitd_bp[1] = htole32(buf_res.physaddr & (~0xFFF)); if(UE_GET_DIR(xfer->endpoint) == UE_DIR_OUT) { @@ -2386,12 +2399,12 @@ EHCI_APPEND_FS_TD(td, *pp_last); pp_last++; - physbuffer += *plen; plen++; - td++; + td_last = td; + td = td->obj_next; } - xfer->td_transfer_last = (td-1); + xfer->td_transfer_last = td_last; /* update isoc_next */ xfer->pipe->isoc_next = (pp_last - &sc->sc_isoc_fs_p_last[0]) & @@ -2426,6 +2439,8 @@ .close = ehci_device_isoc_fs_close, .enter = ehci_device_isoc_fs_enter, .start = ehci_device_isoc_fs_start, + .copy_in = usbd_std_isoc_copy_in, + .copy_out = usbd_std_isoc_copy_out, }; /*---------------------------------------------------------------------------* @@ -2438,9 +2453,7 @@ /* initialize all TD's */ - for(td = xfer->td_start; - ((void *)td) < xfer->td_end; - td++) + for(td = xfer->td_start; td; td = td->obj_next) { /* set TD inactive */ td->itd_status[0] = 0; @@ -2483,10 +2496,11 @@ static void ehci_device_isoc_hs_enter(struct usbd_xfer *xfer) { + struct usbd_page_search buf_res; ehci_softc_t *sc = xfer->usb_sc; u_int32_t status; u_int32_t page_addr; - u_int32_t physbuffer; + u_int32_t buf_offset; u_int32_t nframes; u_int16_t *plen; u_int8_t page_no; @@ -2495,6 +2509,7 @@ u_int8_t once = 1; #endif ehci_itd_t *td; + ehci_itd_t *td_last = NULL; ehci_itd_t **pp_last; DPRINTFN(5,("xfer=%p next=%d nframes=%d\n", @@ -2525,9 +2540,10 @@ return; } - physbuffer = xfer->physbuffer; + buf_offset = 0; + usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res); - page_addr = physbuffer & ~0xFFF; + page_addr = buf_res.physaddr & ~0xFFF; page_no = 0; td_no = 0; @@ -2543,9 +2559,10 @@ while(nframes--) { - if(((void *)td) >= xfer->td_end) + if(td == NULL) { - td = xfer->td_start; + panic("%s:%d: out of TD's\n", + __FUNCTION__, __LINE__); } if(pp_last >= &sc->sc_isoc_hs_p_last[EHCI_VIRTUAL_FRAMELIST_COUNT]) @@ -2554,7 +2571,7 @@ } /* range check */ - if(*plen > 0xC00) + if(*plen > xfer->max_frame_size) { #ifdef USB_DEBUG if(once) @@ -2562,15 +2579,10 @@ once = 0; printf("%s: frame length(%d) exceeds %d bytes " "(frame truncated)\n", - __FUNCTION__, *plen, 0xC00); + __FUNCTION__, *plen, xfer->max_frame_size); } #endif - /* set new frame length, so that - * a valid transfer can be setup, - * even if synchronization with - * physbuffer is lost - */ - *plen = 0xC00; + *plen = xfer->max_frame_size; } if(td_no == 0) @@ -2603,7 +2615,7 @@ EHCI_ITD_ACTIVE| EHCI_ITD_IOC| EHCI_ITD_SET_PG(page_no)| - (physbuffer & 0xFFF)); + (buf_res.physaddr & 0xFFF)); } else { @@ -2611,15 +2623,16 @@ (EHCI_ITD_SET_LEN(*plen)| EHCI_ITD_ACTIVE| EHCI_ITD_SET_PG(page_no)| - (physbuffer & 0xFFF)); + (buf_res.physaddr & 0xFFF)); } - physbuffer += *plen; + buf_offset += *plen; + usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res); - if((physbuffer ^ page_addr) & ~0xFFF) + if((buf_res.physaddr ^ page_addr) & ~0xFFF) { /* new page needed */ - page_addr = physbuffer & ~0xFFF; + page_addr = buf_res.physaddr & ~0xFFF; page_no++; if(page_no < 7) @@ -2669,11 +2682,12 @@ page_no = 0; td_no = 0; - td++; + td_last = td; + td = td->obj_next; } } - xfer->td_transfer_last = (td-1); + xfer->td_transfer_last = td_last; /* update isoc_next */ xfer->pipe->isoc_next = (pp_last - &sc->sc_isoc_hs_p_last[0]) & @@ -2708,6 +2722,8 @@ .close = ehci_device_isoc_hs_close, .enter = ehci_device_isoc_hs_enter, .start = ehci_device_isoc_hs_start, + .copy_in = usbd_std_isoc_copy_in, + .copy_out = usbd_std_isoc_copy_out, }; /*---------------------------------------------------------------------------* @@ -2737,7 +2753,7 @@ static const usb_device_descriptor_t ehci_devd = { - USB_DEVICE_DESCRIPTOR_SIZE, + sizeof(usb_device_descriptor_t), UDESC_DEVICE, /* type */ {0x00, 0x02}, /* USB version */ UDCLASS_HUB, /* class */ @@ -2752,7 +2768,7 @@ static const usb_device_qualifier_t ehci_odevd = { - USB_DEVICE_DESCRIPTOR_SIZE, + sizeof(usb_device_qualifier_t), UDESC_DEVICE_QUALIFIER, /* type */ {0x00, 0x02}, /* USB version */ UDCLASS_HUB, /* class */ @@ -2766,7 +2782,7 @@ static const usb_config_descriptor_t ehci_confd = { - USB_CONFIG_DESCRIPTOR_SIZE, + sizeof(usb_config_descriptor_t), UDESC_CONFIG, {USB_CONFIG_DESCRIPTOR_SIZE + USB_INTERFACE_DESCRIPTOR_SIZE + @@ -2781,7 +2797,7 @@ static const usb_interface_descriptor_t ehci_ifcd = { - USB_INTERFACE_DESCRIPTOR_SIZE, + sizeof(usb_interface_descriptor_t), UDESC_INTERFACE, 0, 0, @@ -2795,7 +2811,7 @@ static const usb_endpoint_descriptor_t ehci_endpd = { - USB_ENDPOINT_DESCRIPTOR_SIZE, + sizeof(usb_endpoint_descriptor_t), UDESC_ENDPOINT, UE_DIR_IN | EHCI_INTR_ENDPT, UE_INTERRUPT, @@ -2806,7 +2822,7 @@ static const usb_hub_descriptor_t ehci_hubd = { - USB_HUB_DESCRIPTOR_SIZE, + 0, /* dynamic length */ UDESC_HUB, 0, {0,0}, @@ -2815,28 +2831,6 @@ {0}, }; -static int -ehci_str(usb_string_descriptor_t *p, int l, char *s) -{ - int i; - - if(l == 0) - { - return (0); - } - p->bLength = (2 * strlen(s)) + 2; - if(l == 1) - { - return (1); - } - p->bDescriptorType = UDESC_STRING; - l -= 2; - for(i = 0; s[i] && (l > 1); i++, l -= 2) - { - USETW2(p->bString[i], 0, s[i]); - } - return ((2 * i) + 2); -} static void ehci_disown(ehci_softc_t *sc, int index, int lowspeed) @@ -2855,38 +2849,59 @@ ehci_root_ctrl_enter(struct usbd_xfer *xfer) { ehci_softc_t *sc = xfer->usb_sc; - usb_device_request_t *req = xfer->buffer; - void *buf; - int port, i; - int len, value, index, l, totlen = 0; - usb_port_status_t ps; - usb_hub_descriptor_t hubd; + 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; usbd_status err; - u_int32_t v; - DPRINTFN(2,("type=0x%02x request=0x%02x\n", - req->bmRequestType, req->bRequest)); + mtx_assert(&sc->sc_bus.mtx, MA_OWNED); - mtx_assert(&sc->sc_bus.mtx, MA_OWNED); + if (xfer->length < sizeof(u.req)) { + err = USBD_INVAL; + goto done; + } /* set default actual length */ - xfer->actlen = sizeof(*req); + xfer->actlen = sizeof(u.req); + + /* copy out "request" */ + usbd_copy_out(&(xfer->buf_data), 0, &u.req, sizeof(u.req)); - len = UGETW(req->wLength); - value = UGETW(req->wValue); - index = UGETW(req->wIndex); + len = (xfer->length - sizeof(u.req)); - if(len != 0) - { - buf = (req+1); + if (len != UGETW(u.req.wLength)) { + err = USBD_INVAL; + goto done; } - else - { - buf = NULL; - } + + value = UGETW(u.req.wValue); + index = UGETW(u.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)); #define C(x,y) ((x) | ((y) << 8)) - switch(C(req->bRequest, req->bmRequestType)) { + switch(C(u.req.bRequest, u.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): @@ -2898,12 +2913,13 @@ case C(UR_GET_CONFIG, UT_READ_DEVICE): if(len > 0) { - *(u_int8_t *)buf = sc->sc_conf; - totlen = 1; + u.byte_temp = sc->sc_conf; + totlen = 1; + usbd_copy_in(&(xfer->buf_data), sizeof(u.req), + &u, totlen); } break; case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): - DPRINTFN(8,("wValue=0x%04x\n", value)); switch(value >> 8) { case UDESC_DEVICE: if((value & 0xff) != 0) @@ -2911,19 +2927,20 @@ err = USBD_IOERROR; goto done; } - totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); - memcpy(buf, &ehci_devd, l); + totlen = min(len, sizeof(u.devd)); + + u.devd = ehci_devd; #if 0 - if(len >= 12) - { - USETW(((usb_device_descriptor_t *)buf)->idVendor, - sc->sc_id_vendor); - } + USETW(u.devd.idVendor, + sc->sc_id_vendor); #endif + usbd_copy_in(&(xfer->buf_data), sizeof(u.req), + &u, totlen); break; /* - * We can't really operate at another speed, but the spec says - * we need this descriptor. + * We can't really operate at another speed, + * but the specification says we need this + * descriptor: */ case UDESC_DEVICE_QUALIFIER: if((value & 0xff) != 0) @@ -2931,12 +2948,14 @@ err = USBD_IOERROR; goto done; } - totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); - memcpy(buf, &ehci_odevd, l); + totlen = min(len, sizeof(ehci_odevd)); + usbd_copy_in(&(xfer->buf_data), sizeof(u.req), + &ehci_odevd, totlen); break; /* - * We can't really operate at another speed, but the spec says - * we need this descriptor. + * We can't really operate at another speed, + * but the specification says we need this + * descriptor: */ case UDESC_OTHER_SPEED_CONFIGURATION: case UDESC_CONFIG: @@ -2945,40 +2964,67 @@ err = USBD_IOERROR; goto done; } - totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE); - memcpy(buf, &ehci_confd, l); - ((usb_config_descriptor_t *)buf)->bDescriptorType = - value >> 8; - buf = ((u_int8_t *)buf) + l; + totlen = l = min(len, sizeof(u.confd)); len -= l; - l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE); + + 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; - memcpy(buf, &ehci_ifcd, l); - buf = ((u_int8_t *)buf) + l; len -= l; - l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE); + + usbd_copy_in(&(xfer->buf_data), sizeof(u.req) + + sizeof(u.confd), &ehci_ifcd, l); + + l = min(len, sizeof(ehci_endpd)); totlen += l; - memcpy(buf, &ehci_endpd, l); + len -= l; + + usbd_copy_in(&(xfer->buf_data), sizeof(u.req) + + sizeof(u.confd) + sizeof(u.ifcd), + &ehci_endpd, l); break; + case UDESC_STRING: if(len == 0) { break; } - *(u_int8_t *)buf = 0; - totlen = 1; + switch (value & 0xff) { case 0: /* Language table */ - totlen = ehci_str(buf, len, "\001"); - break; + totlen = usbd_make_str_desc + (u.str_temp, sizeof(u.str_temp), + "\001"); + break; + case 1: /* Vendor */ - totlen = ehci_str(buf, len, sc->sc_vendor); - break; + totlen = usbd_make_str_desc + (u.str_temp, sizeof(u.str_temp), + sc->sc_vendor); + break; + case 2: /* Product */ - totlen = ehci_str(buf, len, "EHCI root hub"); - break; + totlen = usbd_make_str_desc + (u.str_temp, sizeof(u.str_temp), + "EHCI root hub"); + break; + default: + totlen = usbd_make_str_desc + (u.str_temp, sizeof(u.str_temp), + ""); + break; } >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200607080909.k6899EJf044122>