PERFORCE change 100971 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sat Jul 8 09:09:16 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=100971
Change 100971 by hselasky at 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) <<<
More information about the p4-projects
mailing list