if (ret)
return;
- dprintf(1, "keyboard initialized\n");
+ dprintf(1, "PS2 keyboard initialized\n");
}
void
****************************************************************/
static int
-set_protocol(u32 endp, u16 val)
+set_protocol(struct usb_pipe *pipe, u16 val)
{
struct usb_ctrlrequest req;
req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
req.wValue = val;
req.wIndex = 0;
req.wLength = 0;
- return send_default_control(endp, &req, NULL);
+ return send_default_control(pipe, &req, NULL);
}
static int
-set_idle(u32 endp, int ms)
+set_idle(struct usb_pipe *pipe, int ms)
{
struct usb_ctrlrequest req;
req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
req.wValue = (ms/4)<<8;
req.wIndex = 0;
req.wLength = 0;
- return send_default_control(endp, &req, NULL);
+ return send_default_control(pipe, &req, NULL);
}
#define KEYREPEATWAITMS 500
#define KEYREPEATMS 33
int
-usb_keyboard_init(u32 endp, struct usb_interface_descriptor *iface, int imax)
+usb_keyboard_init(struct usb_pipe *pipe
+ , struct usb_interface_descriptor *iface, int imax)
{
if (! CONFIG_USB_KEYBOARD)
return -1;
if (keyboard_pipe)
// XXX - this enables the first found keyboard (could be random)
return -1;
- dprintf(2, "usb_keyboard_setup %x\n", endp);
+ dprintf(2, "usb_keyboard_setup %x\n", pipe->endp);
// Find intr in endpoint.
struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
dprintf(1, "No keyboard intr in?\n");
return -1;
}
- u32 inendp = mkendpFromDesc(endp, epdesc);
// Enable "boot" protocol.
- int ret = set_protocol(endp, 1);
+ int ret = set_protocol(pipe, 1);
if (ret)
return -1;
// Periodically send reports to enable key repeat.
- ret = set_idle(endp, KEYREPEATMS);
+ ret = set_idle(pipe, KEYREPEATMS);
if (ret)
return -1;
- struct usb_pipe *pipe = alloc_intr_pipe(inendp, epdesc->bInterval);
- if (!pipe)
+ u32 inendp = mkendpFromDesc(pipe, epdesc);
+ keyboard_pipe = alloc_intr_pipe(inendp, epdesc->bInterval);
+ if (!keyboard_pipe)
return -1;
- keyboard_pipe = pipe;
+ dprintf(1, "USB keyboard initialized\n");
return 0;
}
// usb-hid.c
struct usb_interface_descriptor;
-int usb_keyboard_init(u32 endp, struct usb_interface_descriptor *iface
- , int imax);
+struct usb_pipe;
+int usb_keyboard_init(struct usb_pipe *pipe
+ , struct usb_interface_descriptor *iface, int imax);
void usb_keyboard_setup(void);
void usb_check_key(void);
#include "usb.h" // struct usb_s
static int
-get_hub_desc(struct usb_hub_descriptor *desc, u32 endp)
+get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc)
{
struct usb_ctrlrequest req;
req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE;
req.wValue = USB_DT_HUB<<8;
req.wIndex = 0;
req.wLength = sizeof(*desc);
- return send_default_control(endp, &req, desc);
+ return send_default_control(pipe, &req, desc);
}
static int
-set_port_feature(int port, int feature, u32 endp)
+set_port_feature(struct usb_pipe *pipe, int port, int feature)
{
struct usb_ctrlrequest req;
req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
req.wValue = feature;
req.wIndex = port;
req.wLength = 0;
- return send_default_control(endp, &req, NULL);
+ return send_default_control(pipe, &req, NULL);
}
static int
-clear_port_feature(int port, int feature, u32 endp)
+clear_port_feature(struct usb_pipe *pipe, int port, int feature)
{
struct usb_ctrlrequest req;
req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
req.wValue = feature;
req.wIndex = port;
req.wLength = 0;
- return send_default_control(endp, &req, NULL);
+ return send_default_control(pipe, &req, NULL);
}
static int
-get_port_status(int port, struct usb_port_status *sts, u32 endp)
+get_port_status(struct usb_pipe *pipe, int port, struct usb_port_status *sts)
{
struct usb_ctrlrequest req;
req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER;
req.wValue = 0;
req.wIndex = port;
req.wLength = sizeof(*sts);
- return send_default_control(endp, &req, sts);
+ return send_default_control(pipe, &req, sts);
}
// Configure a usb hub and then find devices connected to it.
int
-usb_hub_init(u32 endp)
+usb_hub_init(struct usb_pipe *pipe)
{
if (!CONFIG_USB_HUB)
- return 0;
+ return -1;
struct usb_hub_descriptor desc;
- int ret = get_hub_desc(&desc, endp);
+ int ret = get_hub_desc(pipe, &desc);
if (ret)
return ret;
// Turn on power to all ports.
int i;
for (i=1; i<=desc.bNbrPorts; i++) {
- ret = set_port_feature(i, USB_PORT_FEAT_POWER, endp);
+ ret = set_port_feature(pipe, i, USB_PORT_FEAT_POWER);
if (ret)
goto fail;
}
// possibly wait USB_TIME_ATTDB.
// Detect down stream devices.
- struct usb_s *cntl = endp2cntl(endp);
+ struct usb_s *cntl = endp2cntl(pipe->endp);
int totalcount = 0;
for (i=1; i<=desc.bNbrPorts; i++) {
struct usb_port_status sts;
- ret = get_port_status(i, &sts, endp);
+ ret = get_port_status(pipe, i, &sts);
if (ret)
goto fail;
if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
continue;
// Reset port.
- ret = set_port_feature(i, USB_PORT_FEAT_RESET, endp);
+ ret = set_port_feature(pipe, i, USB_PORT_FEAT_RESET);
if (ret)
goto fail;
// Wait for reset to complete.
u64 end = calc_future_tsc(USB_TIME_DRST * 2);
for (;;) {
- ret = get_port_status(i, &sts, endp);
+ ret = get_port_status(pipe, i, &sts);
if (ret)
goto fail;
if (!(sts.wPortStatus & USB_PORT_STAT_RESET))
cntl, !!(sts.wPortStatus & USB_PORT_STAT_LOW_SPEED));
if (! count) {
// Shutdown port
- ret = clear_port_feature(i, USB_PORT_FEAT_ENABLE, endp);
+ ret = clear_port_feature(pipe, i, USB_PORT_FEAT_ENABLE);
if (ret)
goto fail;
}
totalcount += count;
}
- return totalcount;
+ dprintf(1, "Initialized USB HUB (%d ports used)\n", totalcount);
+ if (totalcount)
+ return 0;
+ return -1;
fail:
dprintf(1, "Failure on hub setup\n");
- return 0;
+ return -1;
}
#define __USB_HUB_H
// usb-hub.c
-int usb_hub_init(u32 endp);
+struct usb_pipe;
+int usb_hub_init(struct usb_pipe *pipe);
/****************************************************************
int
usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
{
- dprintf(1, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
+ dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
, op->drive_g, 0, op->count, blocksize, op->buf_fl);
struct usbdrive_s *udrive_g = container_of(
op->drive_g, struct usbdrive_s, drive);
// Configure a usb msc device.
int
-usb_msc_init(u32 endp, struct usb_interface_descriptor *iface, int imax)
+usb_msc_init(struct usb_pipe *pipe
+ , struct usb_interface_descriptor *iface, int imax)
{
if (!CONFIG_USB_MSC)
return -1;
iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT);
if (!indesc || !outdesc)
goto fail;
- u32 inendp = mkendpFromDesc(endp, indesc);
+ u32 inendp = mkendpFromDesc(pipe, indesc);
struct usb_pipe *bulkin = alloc_bulk_pipe(inendp);
- u32 outendp = mkendpFromDesc(endp, outdesc);
+ u32 outendp = mkendpFromDesc(pipe, outdesc);
struct usb_pipe *bulkout = alloc_bulk_pipe(outendp);
if (!bulkin || !bulkout)
goto fail;
struct disk_op_s;
int usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
struct usb_interface_descriptor;
-int usb_msc_init(u32 endp, struct usb_interface_descriptor *iface, int imax);
+struct usb_pipe;
+int usb_msc_init(struct usb_pipe *pipe
+ , struct usb_interface_descriptor *iface, int imax);
int process_usb_op(struct disk_op_s *op);
#define FIT (1 << 31)
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
static int
start_ohci(struct usb_s *cntl, struct ohci_hcca *hcca)
{
}
// Init memory
- writel(&cntl->ohci.regs->ed_controlhead, (u32)cntl->ohci.control_ed);
+ writel(&cntl->ohci.regs->ed_controlhead, 0);
writel(&cntl->ohci.regs->ed_bulkhead, 0);
writel(&cntl->ohci.regs->hcca, (u32)hcca);
// Allocate memory
struct ohci_hcca *hcca = memalign_high(256, sizeof(*hcca));
struct ohci_ed *intr_ed = malloc_high(sizeof(*intr_ed));
- struct ohci_ed *control_ed = malloc_high(sizeof(*control_ed));
- if (!hcca || !intr_ed || !control_ed) {
+ if (!hcca || !intr_ed) {
warn_noalloc();
goto free;
}
int i;
for (i=0; i<ARRAY_SIZE(hcca->int_table); i++)
hcca->int_table[i] = (u32)intr_ed;
- memset(control_ed, 0, sizeof(*control_ed));
- control_ed->hwINFO = ED_SKIP;
- cntl->ohci.control_ed = control_ed;
int ret = start_ohci(cntl, hcca);
if (ret)
goto err;
int count = check_ohci_ports(cntl);
+ free_pipe(cntl->defaultpipe);
if (! count)
goto err;
return;
free:
free(hcca);
free(intr_ed);
- free(control_ed);
}
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
static int
wait_ed(struct ohci_ed *ed)
{
}
}
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+ohci_waittick(struct usb_s *cntl)
+{
+ barrier();
+ struct ohci_hcca *hcca = (void*)cntl->ohci.regs->hcca;
+ u32 startframe = hcca->frame_no;
+ u64 end = calc_future_tsc(1000 * 5);
+ for (;;) {
+ if (hcca->frame_no != startframe)
+ break;
+ if (check_time(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+}
+
+static void
+signal_freelist(struct usb_s *cntl)
+{
+ u32 v = readl(&cntl->ohci.regs->control);
+ if (v & OHCI_CTRL_CLE) {
+ writel(&cntl->ohci.regs->control, v & ~(OHCI_CTRL_CLE|OHCI_CTRL_BLE));
+ ohci_waittick(cntl);
+ writel(&cntl->ohci.regs->ed_controlcurrent, 0);
+ writel(&cntl->ohci.regs->ed_bulkcurrent, 0);
+ writel(&cntl->ohci.regs->control, v);
+ } else {
+ ohci_waittick(cntl);
+ }
+}
+
+struct ohci_pipe {
+ struct ohci_ed ed;
+ struct usb_pipe pipe;
+ void *data;
+ int count;
+ struct ohci_td *tds;
+};
+
+void
+ohci_free_pipe(struct usb_pipe *p)
+{
+ if (! CONFIG_USB_OHCI)
+ return;
+ struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+ u32 endp = pipe->pipe.endp;
+ dprintf(7, "ohci_free_pipe %x\n", endp);
+ struct usb_s *cntl = endp2cntl(endp);
+
+ u32 *pos = &cntl->ohci.regs->ed_controlhead;
+ for (;;) {
+ struct ohci_ed *next = (void*)*pos;
+ if (!next) {
+ // Not found?! Exit without freeing.
+ warn_internalerror();
+ return;
+ }
+ if (next == &pipe->ed) {
+ *pos = next->hwNextED;
+ signal_freelist(cntl);
+ free(pipe);
+ return;
+ }
+ pos = &next->hwNextED;
+ }
+}
+
+struct usb_pipe *
+ohci_alloc_control_pipe(u32 endp)
+{
+ if (! CONFIG_USB_OHCI)
+ return NULL;
+ struct usb_s *cntl = endp2cntl(endp);
+ dprintf(7, "ohci_alloc_control_pipe %x\n", endp);
+
+ // Allocate a queue head.
+ struct ohci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ pipe->ed.hwINFO = ED_SKIP;
+ pipe->pipe.endp = endp;
+
+ // Add queue head to controller list.
+ pipe->ed.hwNextED = cntl->ohci.regs->ed_controlhead;
+ barrier();
+ cntl->ohci.regs->ed_controlhead = (u32)&pipe->ed;
+ return &pipe->pipe;
+}
+
int
-ohci_control(u32 endp, int dir, const void *cmd, int cmdsize
+ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
, void *data, int datasize)
{
if (! CONFIG_USB_OHCI)
return -1;
-
+ if (datasize > 4096) {
+ // XXX - should support larger sizes.
+ warn_noalloc();
+ return -1;
+ }
+ struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+ u32 endp = pipe->pipe.endp;
dprintf(5, "ohci_control %x\n", endp);
struct usb_s *cntl = endp2cntl(endp);
int maxpacket = endp2maxsize(endp);
tds[2].hwBE = 0;
// Transfer data
- struct ohci_ed *ed = cntl->ohci.control_ed;
- ed->hwINFO = ED_SKIP;
+ pipe->ed.hwINFO = ED_SKIP;
barrier();
- ed->hwHeadP = (u32)&tds[0];
- ed->hwTailP = (u32)&tds[3];
+ pipe->ed.hwHeadP = (u32)&tds[0];
+ pipe->ed.hwTailP = (u32)&tds[3];
barrier();
- ed->hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
+ pipe->ed.hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
writel(&cntl->ohci.regs->cmdstatus, OHCI_CLF);
- int ret = wait_ed(ed);
- ed->hwINFO = ED_SKIP;
+ int ret = wait_ed(&pipe->ed);
+ pipe->ed.hwINFO = ED_SKIP;
if (ret)
- usleep(1); // XXX - in case controller still accessing tds
+ ohci_waittick(cntl);
free(tds);
return ret;
}
-struct ohci_pipe {
- struct ohci_ed ed;
- struct usb_pipe pipe;
- void *data;
- int count;
- struct ohci_td *tds;
-};
-
struct usb_pipe *
ohci_alloc_intr_pipe(u32 endp, int frameexp)
{
}
int
-ohci_poll_intr(struct usb_pipe *pipe, void *data)
+ohci_poll_intr(struct usb_pipe *p, void *data)
{
ASSERT16();
if (! CONFIG_USB_OHCI)
return -1;
- struct ohci_pipe *p = container_of(pipe, struct ohci_pipe, pipe);
- struct ohci_td *tds = GET_FLATPTR(p->tds);
- struct ohci_td *head = (void*)GET_FLATPTR(p->ed.hwHeadP);
- struct ohci_td *tail = (void*)GET_FLATPTR(p->ed.hwTailP);
- int count = GET_FLATPTR(p->count);
+ struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+ struct ohci_td *tds = GET_FLATPTR(pipe->tds);
+ struct ohci_td *head = (void*)GET_FLATPTR(pipe->ed.hwHeadP);
+ struct ohci_td *tail = (void*)GET_FLATPTR(pipe->ed.hwTailP);
+ int count = GET_FLATPTR(pipe->count);
int pos = (tail - tds + 1) % count;
struct ohci_td *next = &tds[pos];
if (head == next)
// XXX - check for errors.
// Copy data.
- u32 endp = GET_FLATPTR(p->pipe.endp);
+ u32 endp = GET_FLATPTR(pipe->pipe.endp);
int maxpacket = endp2maxsize(endp);
- void *pipedata = GET_FLATPTR(p->data);
+ void *pipedata = GET_FLATPTR(pipe->data);
void *intrdata = pipedata + maxpacket * pos;
memcpy_far(GET_SEG(SS), data
, FLATPTR_TO_SEG(intrdata), (void*)FLATPTR_TO_OFFSET(intrdata)
SET_FLATPTR(tail->hwNextTD, (u32)next);
SET_FLATPTR(tail->hwBE, (u32)intrdata + maxpacket - 1);
- SET_FLATPTR(p->ed.hwTailP, (u32)next);
+ SET_FLATPTR(pipe->ed.hwTailP, (u32)next);
return 0;
}
// usb-ohci.c
struct usb_s;
void ohci_init(void *data);
-int ohci_control(u32 endp, int dir, const void *cmd, int cmdsize
+struct usb_pipe;
+void ohci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *ohci_alloc_control_pipe(u32 endp);
+int ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
, void *data, int datasize);
struct usb_pipe *ohci_alloc_intr_pipe(u32 endp, int frameexp);
int ohci_poll_intr(struct usb_pipe *pipe, void *data);
#define OHCI_CTRL_CBSR (3 << 0)
#define OHCI_CTRL_PLE (1 << 2)
#define OHCI_CTRL_CLE (1 << 4)
+#define OHCI_CTRL_BLE (1 << 5)
#define OHCI_CTRL_HCFS (3 << 6)
# define OHCI_USB_RESET (0 << 6)
# define OHCI_USB_OPER (2 << 6)
#include "pci_regs.h" // PCI_BASE_ADDRESS_4
#include "usb.h" // struct usb_s
#include "farptr.h" // GET_FLATPTR
+#include "biosvar.h" // GET_GLOBAL
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
static void
reset_uhci(struct usb_s *cntl)
struct uhci_td *term_td = malloc_high(sizeof(*term_td));
struct uhci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
struct uhci_qh *intr_qh = malloc_high(sizeof(*intr_qh));
- struct uhci_qh *data_qh = malloc_high(sizeof(*data_qh));
struct uhci_qh *term_qh = malloc_high(sizeof(*term_qh));
- if (!term_td || !fl || !intr_qh || !data_qh || !term_qh) {
+ if (!term_td || !fl || !intr_qh || !term_qh) {
warn_noalloc();
free(term_td);
free(fl);
free(intr_qh);
- free(data_qh);
free(term_qh);
return;
}
term_qh->element = (u32)term_td;
term_qh->link = UHCI_PTR_TERM;
- // Setup primary queue head.
- memset(data_qh, 0, sizeof(*data_qh));
- data_qh->element = UHCI_PTR_TERM;
- data_qh->link = (u32)term_qh | UHCI_PTR_QH;
- cntl->uhci.qh = data_qh;
-
// Set schedule to point to primary intr queue head
memset(intr_qh, 0, sizeof(*intr_qh));
intr_qh->element = UHCI_PTR_TERM;
- intr_qh->link = (u32)data_qh | UHCI_PTR_QH;
+ intr_qh->link = (u32)term_qh | UHCI_PTR_QH;
int i;
for (i=0; i<ARRAY_SIZE(fl->links); i++)
fl->links[i] = (u32)intr_qh | UHCI_PTR_QH;
cntl->uhci.framelist = fl;
+ cntl->uhci.control_qh = cntl->uhci.bulk_qh = intr_qh;
barrier();
// Set the frame length to the default: 1 ms exactly
start_uhci(cntl);
int count = check_ports(cntl);
+ free_pipe(cntl->defaultpipe);
if (! count) {
// XXX - no devices; free data structures.
}
}
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
static int
wait_qh(struct usb_s *cntl, struct uhci_qh *qh)
{
}
}
+// Wait for next USB frame to start - for ensuring safe memory release.
static void
-uhci_waittick(void)
+uhci_waittick(struct usb_s *cntl)
+{
+ barrier();
+ u16 iobase = GET_GLOBAL(cntl->uhci.iobase);
+ u16 startframe = inw(iobase + USBFRNUM);
+ u64 end = calc_future_tsc(1000 * 5);
+ for (;;) {
+ if (inw(iobase + USBFRNUM) != startframe)
+ break;
+ if (check_time(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+}
+
+struct uhci_pipe {
+ struct uhci_qh qh;
+ struct uhci_td *next_td;
+ struct usb_pipe pipe;
+};
+
+void
+uhci_free_pipe(struct usb_pipe *p)
+{
+ if (! CONFIG_USB_UHCI)
+ return;
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ u32 endp = pipe->pipe.endp;
+ dprintf(7, "uhci_free_pipe %x\n", endp);
+ struct usb_s *cntl = endp2cntl(endp);
+
+ struct uhci_framelist *fl = cntl->uhci.framelist;
+ struct uhci_qh *pos = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
+ for (;;) {
+ u32 link = pos->link;
+ if (link == UHCI_PTR_TERM) {
+ // Not found?! Exit without freeing.
+ warn_internalerror();
+ return;
+ }
+ struct uhci_qh *next = (void*)(link & ~UHCI_PTR_BITS);
+ if (next == &pipe->qh) {
+ pos->link = next->link;
+ if (cntl->uhci.control_qh == next)
+ cntl->uhci.control_qh = pos;
+ if (cntl->uhci.bulk_qh == next)
+ cntl->uhci.bulk_qh = pos;
+ uhci_waittick(cntl);
+ free(pipe);
+ return;
+ }
+ pos = next;
+ }
+}
+
+struct usb_pipe *
+uhci_alloc_control_pipe(u32 endp)
{
- // XXX - implement real tick detection.
- msleep(2);
+ if (! CONFIG_USB_UHCI)
+ return NULL;
+ struct usb_s *cntl = endp2cntl(endp);
+ dprintf(7, "uhci_alloc_control_pipe %x\n", endp);
+
+ // Allocate a queue head.
+ struct uhci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ pipe->qh.element = UHCI_PTR_TERM;
+ pipe->next_td = 0;
+ pipe->pipe.endp = endp;
+
+ // Add queue head to controller list.
+ struct uhci_qh *control_qh = cntl->uhci.control_qh;
+ pipe->qh.link = control_qh->link;
+ barrier();
+ control_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+ if (cntl->uhci.bulk_qh == control_qh)
+ cntl->uhci.bulk_qh = &pipe->qh;
+ return &pipe->pipe;
}
int
-uhci_control(u32 endp, int dir, const void *cmd, int cmdsize
+uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
, void *data, int datasize)
{
+ ASSERT32FLAT();
if (! CONFIG_USB_UHCI)
return -1;
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ u32 endp = pipe->pipe.endp;
dprintf(5, "uhci_control %x\n", endp);
struct usb_s *cntl = endp2cntl(endp);
tds[i].buffer = 0;
// Transfer data
- struct uhci_qh *data_qh = cntl->uhci.qh;
barrier();
- data_qh->element = (u32)&tds[0];
- int ret = wait_qh(cntl, data_qh);
+ pipe->qh.element = (u32)&tds[0];
+ int ret = wait_qh(cntl, &pipe->qh);
if (ret) {
- data_qh->element = UHCI_PTR_TERM;
- uhci_waittick();
+ pipe->qh.element = UHCI_PTR_TERM;
+ uhci_waittick(cntl);
}
free(tds);
return ret;
dprintf(7, "uhci_alloc_bulk_pipe %x\n", endp);
// Allocate a queue head.
- struct uhci_qh *qh = malloc_low(sizeof(*qh));
- if (!qh) {
+ struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
+ if (!pipe) {
warn_noalloc();
return NULL;
}
- qh->element = UHCI_PTR_TERM;
- qh->next_td = 0;
- qh->pipe.endp = endp;
+ pipe->qh.element = UHCI_PTR_TERM;
+ pipe->next_td = 0;
+ pipe->pipe.endp = endp;
// Add queue head to controller list.
- struct uhci_qh *data_qh = cntl->uhci.qh;
- qh->link = data_qh->link;
+ struct uhci_qh *bulk_qh = cntl->uhci.bulk_qh;
+ pipe->qh.link = bulk_qh->link;
barrier();
- data_qh->link = (u32)qh | UHCI_PTR_QH;
+ bulk_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
- return &qh->pipe;
+ return &pipe->pipe;
}
static int
#define TDALIGN 16
int
-uhci_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize)
+uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
{
- struct uhci_qh *qh = container_of(pipe, struct uhci_qh, pipe);
- u32 endp = GET_FLATPTR(qh->pipe.endp);
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ u32 endp = GET_FLATPTR(pipe->pipe.endp);
dprintf(7, "uhci_send_bulk qh=%p endp=%x dir=%d data=%p size=%d\n"
- , qh, endp, dir, data, datasize);
+ , &pipe->qh, endp, dir, data, datasize);
int maxpacket = endp2maxsize(endp);
int lowspeed = endp2speed(endp);
int devaddr = endp2devaddr(endp) | (endp2ep(endp) << 7);
- int toggle = (u32)GET_FLATPTR(qh->next_td); // XXX
+ int toggle = (u32)GET_FLATPTR(pipe->next_td); // XXX
// Allocate 4 tds on stack (16byte aligned)
u8 tdsbuf[sizeof(struct uhci_td) * STACKTDS + TDALIGN - 1];
memset(tds, 0, sizeof(*tds) * STACKTDS);
// Enable tds
- SET_FLATPTR(qh->element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+ SET_FLATPTR(pipe->qh.element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
int tdpos = 0;
while (datasize) {
goto fail;
}
- SET_FLATPTR(qh->next_td, (void*)toggle); // XXX
+ SET_FLATPTR(pipe->next_td, (void*)toggle); // XXX
return 0;
fail:
dprintf(1, "uhci_send_bulk failed\n");
- SET_FLATPTR(qh->element, UHCI_PTR_TERM);
- uhci_waittick();
+ SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);
+ uhci_waittick(endp2cntl(endp));
return -1;
}
// Determine number of entries needed for 2 timer ticks.
int ms = 1<<frameexp;
int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms);
- struct uhci_qh *qh = malloc_low(sizeof(*qh));
+ struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
struct uhci_td *tds = malloc_low(sizeof(*tds) * count);
- if (!qh || !tds) {
+ if (!pipe || !tds) {
warn_noalloc();
goto fail;
}
if (maxpacket > sizeof(tds[0].data))
goto fail;
- qh->element = (u32)tds;
+ pipe->qh.element = (u32)tds;
int toggle = 0;
int i;
for (i=0; i<count; i++) {
toggle ^= TD_TOKEN_TOGGLE;
}
- qh->next_td = &tds[0];
- qh->pipe.endp = endp;
+ pipe->next_td = &tds[0];
+ pipe->pipe.endp = endp;
// Add to interrupt schedule.
struct uhci_framelist *fl = cntl->uhci.framelist;
if (frameexp == 0) {
// Add to existing interrupt entry.
struct uhci_qh *intr_qh = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
- qh->link = intr_qh->link;
+ pipe->qh.link = intr_qh->link;
barrier();
- intr_qh->link = (u32)qh | UHCI_PTR_QH;
+ intr_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+ if (cntl->uhci.control_qh == intr_qh)
+ cntl->uhci.control_qh = &pipe->qh;
+ if (cntl->uhci.bulk_qh == intr_qh)
+ cntl->uhci.bulk_qh = &pipe->qh;
} else {
int startpos = 1<<(frameexp-1);
- qh->link = fl->links[startpos];
+ pipe->qh.link = fl->links[startpos];
barrier();
for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
- fl->links[i] = (u32)qh | UHCI_PTR_QH;
+ fl->links[i] = (u32)&pipe->qh | UHCI_PTR_QH;
}
- return &qh->pipe;
+ return &pipe->pipe;
fail:
- free(qh);
+ free(pipe);
free(tds);
return NULL;
}
int
-uhci_poll_intr(struct usb_pipe *pipe, void *data)
+uhci_poll_intr(struct usb_pipe *p, void *data)
{
ASSERT16();
if (! CONFIG_USB_UHCI)
return -1;
- struct uhci_qh *qh = container_of(pipe, struct uhci_qh, pipe);
- struct uhci_td *td = GET_FLATPTR(qh->next_td);
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ struct uhci_td *td = GET_FLATPTR(pipe->next_td);
u32 status = GET_FLATPTR(td->status);
u32 token = GET_FLATPTR(td->token);
if (status & TD_CTRL_ACTIVE)
barrier();
SET_FLATPTR(td->status, (uhci_maxerr(0) | (status & TD_CTRL_LS)
| TD_CTRL_ACTIVE));
- SET_FLATPTR(qh->next_td, (void*)(next & ~UHCI_PTR_BITS));
+ SET_FLATPTR(pipe->next_td, (void*)(next & ~UHCI_PTR_BITS));
return 0;
}
#ifndef __USB_UHCI_H
#define __USB_UHCI_H
-#include "usb.h" // struct usb_pipe
-
// usb-uhci.c
-struct usb_s;
void uhci_init(void *data);
-int uhci_control(u32 endp, int dir, const void *cmd, int cmdsize
+struct usb_pipe;
+void uhci_free_pipe(struct usb_pipe *pipe);
+struct usb_pipe *uhci_alloc_control_pipe(u32 endp);
+int uhci_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
, void *data, int datasize);
struct usb_pipe *uhci_alloc_bulk_pipe(u32 endp);
int uhci_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
struct uhci_qh {
u32 link;
u32 element;
-
- // Software fields
- struct uhci_td *next_td;
- struct usb_pipe pipe;
} PACKED;
#define UHCI_PTR_BITS 0x000F
* Controller function wrappers
****************************************************************/
+// Free an allocated control or bulk pipe.
+void
+free_pipe(struct usb_pipe *pipe)
+{
+ ASSERT32FLAT();
+ if (!pipe)
+ return;
+ struct usb_s *cntl = endp2cntl(pipe->endp);
+ switch (cntl->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_free_pipe(pipe);
+ case USB_TYPE_OHCI:
+ return ohci_free_pipe(pipe);
+ }
+}
+
+// Allocate a control pipe (which can only be used by 32bit code)
+static struct usb_pipe *
+alloc_control_pipe(u32 endp)
+{
+ struct usb_s *cntl = endp2cntl(endp);
+ switch (cntl->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_alloc_control_pipe(endp);
+ case USB_TYPE_OHCI:
+ return ohci_alloc_control_pipe(endp);
+ }
+}
+
// Send a message on a control pipe using the default control descriptor.
static int
-send_control(u32 endp, int dir, const void *cmd, int cmdsize
+send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
, void *data, int datasize)
{
- struct usb_s *cntl = endp2cntl(endp);
+ ASSERT32FLAT();
+ struct usb_s *cntl = endp2cntl(pipe->endp);
switch (cntl->type) {
default:
case USB_TYPE_UHCI:
- return uhci_control(endp, dir, cmd, cmdsize, data, datasize);
+ return uhci_control(pipe, dir, cmd, cmdsize, data, datasize);
case USB_TYPE_OHCI:
- return ohci_control(endp, dir, cmd, cmdsize, data, datasize);
+ return ohci_control(pipe, dir, cmd, cmdsize, data, datasize);
}
}
}
}
+// Change endpoint characteristics of the default control pipe.
+static void
+usb_alter_control(struct usb_pipe *pipe, u32 endp)
+{
+ pipe->endp = endp;
+}
+
// Build an encoded "endp" from an endpoint descriptor.
u32
-mkendpFromDesc(u32 endp, struct usb_endpoint_descriptor *epdesc)
+mkendpFromDesc(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
{
+ u32 endp = pipe->endp;
return mkendp(endp2cntl(endp), endp2devaddr(endp)
, epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK
, endp2speed(endp), epdesc->wMaxPacketSize);
// Send a message to the default control pipe of a device.
int
-send_default_control(u32 endp, const struct usb_ctrlrequest *req, void *data)
+send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
+ , void *data)
{
- return send_control(endp, req->bRequestType & USB_DIR_IN
+ return send_control(pipe, req->bRequestType & USB_DIR_IN
, req, sizeof(*req), data, req->wLength);
}
// Get the first 8 bytes of the device descriptor.
static int
-get_device_info8(struct usb_device_descriptor *dinfo, u32 endp)
+get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo)
{
struct usb_ctrlrequest req;
req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
req.wValue = USB_DT_DEVICE<<8;
req.wIndex = 0;
req.wLength = 8;
- return send_default_control(endp, &req, dinfo);
+ return send_default_control(pipe, &req, dinfo);
}
static struct usb_config_descriptor *
-get_device_config(u32 endp)
+get_device_config(struct usb_pipe *pipe)
{
struct usb_config_descriptor cfg;
req.wValue = USB_DT_CONFIG<<8;
req.wIndex = 0;
req.wLength = sizeof(cfg);
- int ret = send_default_control(endp, &req, &cfg);
+ int ret = send_default_control(pipe, &req, &cfg);
if (ret)
return NULL;
if (!config)
return NULL;
req.wLength = cfg.wTotalLength;
- ret = send_default_control(endp, &req, config);
+ ret = send_default_control(pipe, &req, config);
if (ret)
return NULL;
//hexdump(config, cfg.wTotalLength);
return config;
}
-static u32
-set_address(u32 endp)
+static struct usb_pipe *
+set_address(struct usb_pipe *pipe)
{
- dprintf(3, "set_address %x\n", endp);
- struct usb_s *cntl = endp2cntl(endp);
+ ASSERT32FLAT();
+ dprintf(3, "set_address %x\n", pipe->endp);
+ struct usb_s *cntl = endp2cntl(pipe->endp);
if (cntl->maxaddr >= USB_MAXADDR)
return 0;
req.wValue = cntl->maxaddr + 1;
req.wIndex = 0;
req.wLength = 0;
- int ret = send_default_control(endp, &req, NULL);
+ int ret = send_default_control(pipe, &req, NULL);
if (ret)
return 0;
msleep(USB_TIME_SETADDR_RECOVERY);
cntl->maxaddr++;
- return mkendp(cntl, cntl->maxaddr, 0, endp2speed(endp), endp2maxsize(endp));
+ u32 endp = mkendp(cntl, cntl->maxaddr, 0
+ , endp2speed(pipe->endp), endp2maxsize(pipe->endp));
+ return alloc_control_pipe(endp);
}
static int
-set_configuration(u32 endp, u16 val)
+set_configuration(struct usb_pipe *pipe, u16 val)
{
struct usb_ctrlrequest req;
req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
req.wValue = val;
req.wIndex = 0;
req.wLength = 0;
- return send_default_control(endp, &req, NULL);
+ return send_default_control(pipe, &req, NULL);
}
int
configure_usb_device(struct usb_s *cntl, int lowspeed)
{
+ ASSERT32FLAT();
dprintf(3, "config_usb: %p %d\n", cntl, lowspeed);
// Get device info
+ struct usb_pipe *defpipe = cntl->defaultpipe;
u32 endp = mkendp(cntl, 0, 0, lowspeed, 8);
+ if (!defpipe) {
+ cntl->defaultpipe = defpipe = alloc_control_pipe(endp);
+ if (!defpipe)
+ return 0;
+ }
+ usb_alter_control(defpipe, endp);
struct usb_device_descriptor dinfo;
- int ret = get_device_info8(&dinfo, endp);
+ int ret = get_device_info8(defpipe, &dinfo);
if (ret)
return 0;
dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n"
if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64)
return 0;
endp = mkendp(cntl, 0, 0, lowspeed, dinfo.bMaxPacketSize0);
+ usb_alter_control(defpipe, endp);
// Get configuration
- struct usb_config_descriptor *config = get_device_config(endp);
+ struct usb_pipe *pipe = NULL;
+ struct usb_config_descriptor *config = get_device_config(defpipe);
if (!config)
return 0;
goto fail;
// Set the address and configure device.
- endp = set_address(endp);
- if (!endp)
+ pipe = set_address(defpipe);
+ if (!pipe)
goto fail;
- ret = set_configuration(endp, config->bConfigurationValue);
+ ret = set_configuration(pipe, config->bConfigurationValue);
if (ret)
goto fail;
// Configure driver.
- if (iface->bInterfaceClass == USB_CLASS_HUB) {
- free(config);
- return usb_hub_init(endp);
- }
int imax = (void*)config + config->wTotalLength - (void*)iface;
- if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
- ret = usb_msc_init(endp, iface, imax);
+ if (iface->bInterfaceClass == USB_CLASS_HUB)
+ ret = usb_hub_init(pipe);
+ else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
+ ret = usb_msc_init(pipe, iface, imax);
else
- ret = usb_keyboard_init(endp, iface, imax);
+ ret = usb_keyboard_init(pipe, iface, imax);
if (ret)
goto fail;
+ free_pipe(pipe);
free(config);
return 1;
fail:
dprintf(3, "init usb\n");
+ memset(&USBControllers, 0, sizeof(USBControllers));
usb_keyboard_setup();
// Look for USB controllers
#ifndef __USB_H
#define __USB_H
+struct usb_pipe {
+ u32 endp;
+};
+
// Local information for a usb controller.
struct usb_s {
u8 type;
u8 maxaddr;
u16 bdf;
+ struct usb_pipe *defaultpipe;
union {
struct {
u16 iobase;
- void *qh, *framelist;
+ void *control_qh, *bulk_qh, *framelist;
} uhci;
struct {
struct ohci_regs *regs;
- void *control_ed;
} ohci;
};
};
extern struct usb_s USBControllers[];
-struct usb_pipe {
- u32 endp;
-};
-
#define USB_MAXADDR 127
// usb.c
void usb_setup(void);
int configure_usb_device(struct usb_s *cntl, int lowspeed);
struct usb_ctrlrequest;
-int send_default_control(u32 endp, const struct usb_ctrlrequest *req
+int send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
, void *data);
int usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
+void free_pipe(struct usb_pipe *pipe);
struct usb_pipe *alloc_bulk_pipe(u32 endp);
struct usb_pipe *alloc_intr_pipe(u32 endp, int period);
int usb_poll_intr(struct usb_pipe *pipe, void *data);
struct usb_interface_descriptor;
struct usb_endpoint_descriptor *findEndPointDesc(
struct usb_interface_descriptor *iface, int imax, int type, int dir);
-u32 mkendpFromDesc(u32 endp, struct usb_endpoint_descriptor *epdesc);
+u32 mkendpFromDesc(struct usb_pipe *pipe
+ , struct usb_endpoint_descriptor *epdesc);
/****************************************************************