* TSC timer
****************************************************************/
-#define PIT_TICK_RATE 1193180 // Underlying HZ of PIT
-#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
#define CALIBRATE_COUNT 0x800 // Approx 1.7ms
// 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 || !control_ed) {
+ if (!hcca || !intr_ed || !control_ed) {
dprintf(1, "No ram for ohci init\n");
- return;
+ goto free;
}
memset(hcca, 0, sizeof(*hcca));
+ memset(intr_ed, 0, sizeof(*intr_ed));
+ intr_ed->hwINFO = ED_SKIP;
+ 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;
err:
stop_ohci(cntl);
+free:
free(hcca);
+ free(intr_ed);
free(control_ed);
}
};
struct usb_pipe *
-ohci_alloc_intr_pipe(u32 endp, int period)
+ohci_alloc_intr_pipe(u32 endp, int frameexp)
{
if (! CONFIG_USB_OHCI)
return NULL;
- dprintf(7, "ohci_alloc_intr_pipe %x %d\n", endp, period);
+ dprintf(7, "ohci_alloc_intr_pipe %x %d\n", endp, frameexp);
+ if (frameexp > 5)
+ frameexp = 5;
struct usb_s *cntl = endp2cntl(endp);
int maxpacket = endp2maxsize(endp);
int lowspeed = endp2speed(endp);
int devaddr = endp2devaddr(endp) | (endp2ep(endp) << 7);
- // XXX - just grab 20 for now.
- int count = 20;
+ // 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 ohci_pipe *pipe = malloc_low(sizeof(*pipe));
struct ohci_td *tds = malloc_low(sizeof(*tds) * count);
void *data = malloc_low(maxpacket * count);
ed->hwHeadP = (u32)&tds[0];
ed->hwTailP = (u32)&tds[count-1];
ed->hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
- ed->hwNextED = 0;
int i;
for (i=0; i<count-1; i++) {
tds[i].hwBE = tds[i].hwCBP + maxpacket - 1;
}
- // XXX - need schedule - just add to primary list for now.
+ // Add to interrupt schedule.
barrier();
struct ohci_hcca *hcca = (void*)cntl->ohci.regs->hcca;
- for (i=0; i<ARRAY_SIZE(hcca->int_table); i++)
- hcca->int_table[i] = (u32)ed;
+ if (frameexp == 0) {
+ // Add to existing interrupt entry.
+ struct ohci_ed *intr_ed = (void*)hcca->int_table[0];
+ ed->hwNextED = intr_ed->hwNextED;
+ intr_ed->hwNextED = (u32)ed;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ ed->hwNextED = hcca->int_table[startpos];
+ for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms)
+ hcca->int_table[i] = (u32)ed;
+ }
pipe->data = data;
pipe->count = count;
void ohci_init(void *data);
int ohci_control(u32 endp, int dir, const void *cmd, int cmdsize
, void *data, int datasize);
-struct usb_pipe *ohci_alloc_intr_pipe(u32 endp, int period);
+struct usb_pipe *ohci_alloc_intr_pipe(u32 endp, int frameexp);
int ohci_poll_intr(struct usb_pipe *pipe, void *data);
// Allocate ram for schedule storage
struct uhci_td *term_td = malloc_high(sizeof(*term_td));
struct uhci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
- struct uhci_qh *data_qh = malloc_low(sizeof(*data_qh));
+ 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 || !data_qh || !term_qh) {
+ if (!term_td || !fl || !intr_qh || !data_qh || !term_qh) {
+ free(term_td);
+ free(fl);
+ free(intr_qh);
+ free(data_qh);
+ free(term_qh);
dprintf(1, "No ram for uhci init\n");
return;
}
data_qh->link = (u32)term_qh | UHCI_PTR_QH;
cntl->uhci.qh = data_qh;
- // Set schedule to point to primary queue head
+ // 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;
int i;
- for (i=0; i<ARRAY_SIZE(fl->links); i++) {
- fl->links[i] = (u32)data_qh | UHCI_PTR_QH;
- }
+ for (i=0; i<ARRAY_SIZE(fl->links); i++)
+ fl->links[i] = (u32)intr_qh | UHCI_PTR_QH;
+ cntl->uhci.framelist = fl;
// Set the frame length to the default: 1 ms exactly
outb(USBSOF_DEFAULT, cntl->uhci.iobase + USBSOF);
}
struct usb_pipe *
-uhci_alloc_intr_pipe(u32 endp, int period)
+uhci_alloc_intr_pipe(u32 endp, int frameexp)
{
if (! CONFIG_USB_UHCI)
return NULL;
- dprintf(7, "uhci_alloc_intr_pipe %x %d\n", endp, period);
+ dprintf(7, "uhci_alloc_intr_pipe %x %d\n", endp, frameexp);
+ if (frameexp > 10)
+ frameexp = 10;
struct usb_s *cntl = endp2cntl(endp);
int maxpacket = endp2maxsize(endp);
int lowspeed = endp2speed(endp);
int devaddr = endp2devaddr(endp) | (endp2ep(endp) << 7);
- // XXX - just grab 20 for now.
- int count = 20;
+ // 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_td *tds = malloc_low(sizeof(*tds) * count);
- if (!qh || !tds)
- return NULL;
- if (maxpacket > sizeof(tds[0].data))
- // XXX - free qh/tds
+ if (!qh || !tds || maxpacket > sizeof(tds[0].data)) {
+ free(qh);
+ free(tds);
return NULL;
-
+ }
qh->element = (u32)tds;
int toggle = 0;
int i;
qh->next_td = &tds[0];
qh->pipe.endp = endp;
- // XXX - need schedule - just add to primary list for now.
- struct uhci_qh *data_qh = cntl->uhci.qh;
- qh->link = data_qh->link;
- data_qh->link = (u32)qh | UHCI_PTR_QH;
+ // 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;
+ intr_qh->link = (u32)qh | UHCI_PTR_QH;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ qh->link = fl->links[startpos];
+ for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
+ fl->links[i] = (u32)qh | UHCI_PTR_QH;
+ }
return &qh->pipe;
}
void uhci_init(void *data);
int uhci_control(u32 endp, int dir, const void *cmd, int cmdsize
, void *data, int datasize);
-struct usb_pipe *uhci_alloc_intr_pipe(u32 endp, int period);
+struct usb_pipe *uhci_alloc_intr_pipe(u32 endp, int frameexp);
int uhci_poll_intr(struct usb_pipe *pipe, void *data);
alloc_intr_pipe(u32 endp, int period)
{
struct usb_s *cntl = endp2cntl(endp);
+ // Find the exponential period of the requested time.
+ if (period <= 0)
+ period = 1;
+ int frameexp = __fls(period);
switch (cntl->type) {
default:
case USB_TYPE_UHCI:
- return uhci_alloc_intr_pipe(endp, period);
+ return uhci_alloc_intr_pipe(endp, frameexp);
case USB_TYPE_OHCI:
- return ohci_alloc_intr_pipe(endp, period);
+ return ohci_alloc_intr_pipe(endp, frameexp);
}
}
union {
struct {
u16 iobase;
- void *qh;
+ void *qh, *framelist;
} uhci;
struct {
struct ohci_regs *regs;
void lpt_setup(void);
// clock.c
+#define PIT_TICK_RATE 1193180 // Underlying HZ of PIT
+#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
static inline int check_time(u64 end) {
return (s64)(rdtscll() - end) > 0;
}