Initial version of uhci driver import from Linux 2.5 kernel. Currently compiles and links, but not usable (most probably will bugcheck when loaded). Also a lot of compile warnings exist. I will update UsbStack wiki page sometime soon to reflect direction of my work. Modified: trunk/reactos/drivers/usb/cromwell/Makefile Modified: trunk/reactos/drivers/usb/cromwell/core/usb.c Modified: trunk/reactos/drivers/usb/cromwell/core/usbcore.def Modified: trunk/reactos/drivers/usb/cromwell/linux/linux_wrapper.h Modified: trunk/reactos/drivers/usb/cromwell/linux/usb.h Modified: trunk/reactos/drivers/usb/cromwell/sys/linuxwrapper.c Added: trunk/reactos/drivers/usb/cromwell/uhci/ Added: trunk/reactos/drivers/usb/cromwell/uhci/makefile Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci-debug.c Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci-hcd.c Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci-hcd.h Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci-hub.c Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci.def Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci.rc Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci_config.h Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci_main.c _____
Modified: trunk/reactos/drivers/usb/cromwell/Makefile --- trunk/reactos/drivers/usb/cromwell/Makefile 2005-04-11 08:41:58 UTC (rev 14586) +++ trunk/reactos/drivers/usb/cromwell/Makefile 2005-04-11 12:49:25 UTC (rev 14587) @@ -6,7 +6,7 @@
include $(PATH_TO_TOP)/rules.mak
-DRIVERS = core host +DRIVERS = core host uhci
all: $(DRIVERS)
_____
Modified: trunk/reactos/drivers/usb/cromwell/core/usb.c --- trunk/reactos/drivers/usb/cromwell/core/usb.c 2005-04-11 08:41:58 UTC (rev 14586) +++ trunk/reactos/drivers/usb/cromwell/core/usb.c 2005-04-11 12:49:25 UTC (rev 14587) @@ -688,7 +688,7 @@
* * A pointer to the device with the incremented reference counter is returned. */ -struct usb_device *usb_get_dev (struct usb_device *dev) +struct usb_device STDCALL *usb_get_dev (struct usb_device *dev) { struct device *tmp;
_____
Modified: trunk/reactos/drivers/usb/cromwell/core/usbcore.def --- trunk/reactos/drivers/usb/cromwell/core/usbcore.def 2005-04-11 08:41:58 UTC (rev 14586) +++ trunk/reactos/drivers/usb/cromwell/core/usbcore.def 2005-04-11 12:49:25 UTC (rev 14587) @@ -8,6 +8,7 @@
usb_alloc_urb@8 usb_free_urb@4 usb_get_urb@4 +usb_get_dev@4 usb_submit_urb@8 usb_unlink_urb@4 usb_bus_init@4 _____
Modified: trunk/reactos/drivers/usb/cromwell/linux/linux_wrapper.h --- trunk/reactos/drivers/usb/cromwell/linux/linux_wrapper.h 2005-04-11 08:41:58 UTC (rev 14586) +++ trunk/reactos/drivers/usb/cromwell/linux/linux_wrapper.h 2005-04-11 12:49:25 UTC (rev 14587) @@ -443,6 +443,8 @@
#define pci_unregister_driver(a) do {} while(0)
+#define pci_write_config_word(a,b,c) my_pci_write_config_word(a,b,c) + #define bus_register(a) do {} while(0) #define bus_unregister(a) do {} while(0)
_____
Modified: trunk/reactos/drivers/usb/cromwell/linux/usb.h --- trunk/reactos/drivers/usb/cromwell/linux/usb.h 2005-04-11 08:41:58 UTC (rev 14586) +++ trunk/reactos/drivers/usb/cromwell/linux/usb.h 2005-04-11 12:49:25 UTC (rev 14587) @@ -272,7 +272,7 @@
#define to_usb_device(d) container_of(d, struct usb_device, dev)
extern struct usb_device STDCALL *usb_alloc_dev(struct usb_device *parent, struct usb_bus *); -extern struct usb_device *usb_get_dev(struct usb_device *dev); +extern struct usb_device STDCALL *usb_get_dev(struct usb_device *dev); extern void STDCALL usb_put_dev(struct usb_device *dev);
/* mostly for devices emulating SCSI over USB */ _____
Modified: trunk/reactos/drivers/usb/cromwell/sys/linuxwrapper.c --- trunk/reactos/drivers/usb/cromwell/sys/linuxwrapper.c 2005-04-11 08:41:58 UTC (rev 14586) +++ trunk/reactos/drivers/usb/cromwell/sys/linuxwrapper.c 2005-04-11 12:49:25 UTC (rev 14587) @@ -290,6 +290,16 @@
return NULL; }
/*---------------------------------------------------------------------- --*/ +int my_pci_write_config_word(struct pci_dev *dev, int where, u16 val) +{ + //dev->bus, dev->devfn, where, val + OHCI_DEVICE_EXTENSION *dev_ext = (OHCI_DEVICE_EXTENSION *)dev->dev_ext; + + //FIXME: Is returning this value correct? + //FIXME: Mixing pci_dev and win structs isn't a good thing at all + return HalSetBusDataByOffset(PCIConfiguration, dev->bus->number, dev_ext->SystemIoSlotNumber, &val, where, sizeof(val)); +} +/*--------------------------------------------------------------------- ---*/ int my_request_irq(unsigned int irq, int (*handler)(int,void *, struct pt_regs *), unsigned long mode, const char *desc, void *data) _____
Added: trunk/reactos/drivers/usb/cromwell/uhci/makefile --- trunk/reactos/drivers/usb/cromwell/uhci/makefile 2005-04-11 08:41:58 UTC (rev 14586) +++ trunk/reactos/drivers/usb/cromwell/uhci/makefile 2005-04-11 12:49:25 UTC (rev 14587) @@ -0,0 +1,16 @@
+PATH_TO_TOP = ../../../.. + +TARGET_TYPE = export_driver + +TARGET_NAME = uhci + +TARGET_DDKLIBS = ntoskrnl.a usbcore.a + +TARGET_CFLAGS = -Wall -I$(PATH_TO_TOP)/ntoskrnl/include -DDEBUG_MODE + +TARGET_OBJECTS = \ + uhci-hcd.o uhci_main.o ../sys/ros_wrapper.o ../sys/linuxwrapper.o + +include $(PATH_TO_TOP)/rules.mak + +include $(TOOLS_PATH)/helper.mk _____
Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci-debug.c --- trunk/reactos/drivers/usb/cromwell/uhci/uhci-debug.c 2005-04-11 08:41:58 UTC (rev 14586) +++ trunk/reactos/drivers/usb/cromwell/uhci/uhci-debug.c 2005-04-11 12:49:25 UTC (rev 14587) @@ -0,0 +1,616 @@
+/* + * UHCI-specific debugging code. Invaluable when something + * goes wrong, but don't get in my face. + * + * Kernel visible pointers are surrounded in []'s and bus + * visible pointers are surrounded in ()'s + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2001 Johannes Erdfelt + */ + +#if 0 +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/proc_fs.h> +#include <linux/smp_lock.h> +#include <asm/io.h> +#endif + +#include "uhci-hcd.h" + +/* Handle REALLY large printk's so we don't overflow buffers */ +static inline void lprintk(char *buf) +{ + char *p; + + /* Just write one line at a time */ + while (buf) { + p = strchr(buf, '\n'); + if (p) + *p = 0; + printk(KERN_DEBUG "%s\n", buf); + buf = p; + if (buf) + buf++; + } +} + +static inline int uhci_is_skeleton_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int i; + + for (i = 0; i < UHCI_NUM_SKELQH; i++) + if (qh == uhci->skelqh[i]) + return 1; + + return 0; +} + +static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) +{ + char *out = buf; + char *spid; + u32 status, token; + + /* Try to make sure there's enough memory */ + if (len < 160) + return 0; + + status = td_status(td); + out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, le32_to_cpu(td->link)); + out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", + ((status >> 27) & 3), + (status & TD_CTRL_SPD) ? "SPD " : "", + (status & TD_CTRL_LS) ? "LS " : "", + (status & TD_CTRL_IOC) ? "IOC " : "", + (status & TD_CTRL_ACTIVE) ? "Active " : "", + (status & TD_CTRL_STALLED) ? "Stalled " : "", + (status & TD_CTRL_DBUFERR) ? "DataBufErr " : "", + (status & TD_CTRL_BABBLE) ? "Babble " : "", + (status & TD_CTRL_NAK) ? "NAK " : "", + (status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "", + (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "", + status & 0x7ff); + + token = td_token(td); + switch (uhci_packetid(token)) { + case USB_PID_SETUP: + spid = "SETUP"; + break; + case USB_PID_OUT: + spid = "OUT"; + break; + case USB_PID_IN: + spid = "IN"; + break; + default: + spid = "?"; + break; + } + + out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ", + token >> 21, + ((token >> 19) & 1), + (token >> 15) & 15, + (token >> 8) & 127, + (token & 0xff), + spid); + out += sprintf(out, "(buf=%08x)\n", le32_to_cpu(td->buffer)); + + return out - buf; +} + +static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) +{ + char *out = buf; + struct urb_priv *urbp; + struct list_head *head, *tmp; + struct uhci_td *td; + int i = 0, checked = 0, prevactive = 0; + + /* Try to make sure there's enough memory */ + if (len < 80 * 6) + return 0; + + out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "", + qh, le32_to_cpu(qh->link), le32_to_cpu(qh->element)); + + if (qh->element & UHCI_PTR_QH) + out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); + + if (qh->element & UHCI_PTR_DEPTH) + out += sprintf(out, "%*s Depth traverse\n", space, ""); + + if (qh->element & cpu_to_le32(8)) + out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, ""); + + if (!(qh->element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH))) + out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); + + if (!qh->urbp) { + out += sprintf(out, "%*s urbp == NULL\n", space, ""); + goto out; + } + + urbp = qh->urbp; + + head = &urbp->td_list; + tmp = head->next; + + td = list_entry(tmp, struct uhci_td, list); + + if (cpu_to_le32(td->dma_handle) != (qh->element & ~UHCI_PTR_BITS)) + out += sprintf(out, "%*s Element != First TD\n", space, ""); + + while (tmp != head) { + struct uhci_td *td = list_entry(tmp, struct uhci_td, list); + + tmp = tmp->next; + + out += sprintf(out, "%*s%d: ", space + 2, "", i++); + out += uhci_show_td(td, out, len - (out - buf), 0); + + if (i > 10 && !checked && prevactive && tmp != head && + debug <= 2) { + struct list_head *ntmp = tmp; + struct uhci_td *ntd = td; + int active = 1, ni = i; + + checked = 1; + + while (ntmp != head && ntmp->next != head && active) { + ntd = list_entry(ntmp, struct uhci_td, list); + + ntmp = ntmp->next; + + active = td_status(ntd) & TD_CTRL_ACTIVE; + + ni++; + } + + if (active && ni > i) { + out += sprintf(out, "%*s[skipped %d active TD's]\n", space, "", ni - i); + tmp = ntmp; + td = ntd; + i = ni; + } + } + + prevactive = td_status(td) & TD_CTRL_ACTIVE; + } + + if (list_empty(&urbp->queue_list) || urbp->queued) + goto out; + + out += sprintf(out, "%*sQueued QH's:\n", -space, "--"); + + head = &urbp->queue_list; + tmp = head->next; + + while (tmp != head) { + struct urb_priv *nurbp = list_entry(tmp, struct urb_priv, + queue_list); + tmp = tmp->next; + + out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space); + } + +out: + return out - buf; +} + +#define show_frame_num() \ + if (!shown) { \ + shown = 1; \ + out += sprintf(out, "- Frame %d\n", i); \ + } + +#ifdef CONFIG_PROC_FS +static const char *qh_names[] = { + "skel_int128_qh", "skel_int64_qh", + "skel_int32_qh", "skel_int16_qh", + "skel_int8_qh", "skel_int4_qh", + "skel_int2_qh", "skel_int1_qh", + "skel_ls_control_qh", "skel_fs_control_qh", + "skel_bulk_qh", "skel_term_qh" +}; + +#define show_qh_name() \ + if (!shown) { \ + shown = 1; \ + out += sprintf(out, "- %s\n", qh_names[i]); \ + } + +static int uhci_show_sc(int port, unsigned short status, char *buf, int len) +{ + char *out = buf; + + /* Try to make sure there's enough memory */ + if (len < 160) + return 0; + + out += sprintf(out, " stat%d = %04x %s%s%s%s%s%s%s%s%s%s\n", + port, + status, + (status & USBPORTSC_SUSP) ? " Suspend" : "", + (status & USBPORTSC_OCC) ? " OverCurrentChange" : "", + (status & USBPORTSC_OC) ? " OverCurrent" : "", + (status & USBPORTSC_PR) ? " Reset" : "", + (status & USBPORTSC_LSDA) ? " LowSpeed" : "", + (status & USBPORTSC_RD) ? " ResumeDetect" : "", + (status & USBPORTSC_PEC) ? " EnableChange" : "", + (status & USBPORTSC_PE) ? " Enabled" : "", + (status & USBPORTSC_CSC) ? " ConnectChange" : "", + (status & USBPORTSC_CCS) ? " Connected" : ""); + + return out - buf; +} + +static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) +{ + char *out = buf; + unsigned int io_addr = uhci->io_addr; + unsigned short usbcmd, usbstat, usbint, usbfrnum; + unsigned int flbaseadd; + unsigned char sof; + unsigned short portsc1, portsc2; + + /* Try to make sure there's enough memory */ + if (len < 80 * 6) + return 0; + + usbcmd = inw(io_addr + 0); + usbstat = inw(io_addr + 2); + usbint = inw(io_addr + 4); + usbfrnum = inw(io_addr + 6); + flbaseadd = inl(io_addr + 8); + sof = inb(io_addr + 12); + portsc1 = inw(io_addr + 16); + portsc2 = inw(io_addr + 18); + + out += sprintf(out, " usbcmd = %04x %s%s%s%s%s%s%s%s\n", + usbcmd, + (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ", + (usbcmd & USBCMD_CF) ? "CF " : "", + (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "", + (usbcmd & USBCMD_FGR) ? "FGR " : "", + (usbcmd & USBCMD_EGSM) ? "EGSM " : "", + (usbcmd & USBCMD_GRESET) ? "GRESET " : "", + (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "", + (usbcmd & USBCMD_RS) ? "RS " : ""); + + out += sprintf(out, " usbstat = %04x %s%s%s%s%s%s\n", + usbstat, + (usbstat & USBSTS_HCH) ? "HCHalted " : "", + (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "", + (usbstat & USBSTS_HSE) ? "HostSystemError " : "", + (usbstat & USBSTS_RD) ? "ResumeDetect " : "", + (usbstat & USBSTS_ERROR) ? "USBError " : "", + (usbstat & USBSTS_USBINT) ? "USBINT " : ""); + + out += sprintf(out, " usbint = %04x\n", usbint); + out += sprintf(out, " usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, + 0xfff & (4*(unsigned int)usbfrnum)); + out += sprintf(out, " flbaseadd = %08x\n", flbaseadd); + out += sprintf(out, " sof = %02x\n", sof); + out += uhci_show_sc(1, portsc1, out, len - (out - buf)); + out += uhci_show_sc(2, portsc2, out, len - (out - buf)); + + return out - buf; +} + +static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len) +{ + struct list_head *tmp; + char *out = buf; + int count = 0; + + if (len < 200) + return 0; + + out += sprintf(out, "urb_priv [%p] ", urbp); + out += sprintf(out, "urb [%p] ", urbp->urb); + out += sprintf(out, "qh [%p] ", urbp->qh); + out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe)); + out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT")); + + switch (usb_pipetype(urbp->urb->pipe)) { + case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO "); break; + case PIPE_INTERRUPT: out += sprintf(out, "INT "); break; + case PIPE_BULK: out += sprintf(out, "BLK "); break; + case PIPE_CONTROL: out += sprintf(out, "CTL "); break; + } + + out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : "")); + out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : "")); + + if (urbp->urb->status != -EINPROGRESS) + out += sprintf(out, "Status=%d ", urbp->urb->status); + //out += sprintf(out, "Inserttime=%lx ",urbp->inserttime); + //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime); + + count = 0; + list_for_each(tmp, &urbp->td_list) + count++; + out += sprintf(out, "TDs=%d ",count); + + if (urbp->queued) + out += sprintf(out, "queued\n"); + else { + count = 0; + list_for_each(tmp, &urbp->queue_list) + count++; + out += sprintf(out, "queued URBs=%d\n", count); + } + + return out - buf; +} + +static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len) +{ + char *out = buf; + struct list_head *head, *tmp; + int count; + + out += sprintf(out, "Main list URBs:"); + if (list_empty(&uhci->urb_list)) + out += sprintf(out, " Empty\n"); + else { + out += sprintf(out, "\n"); + count = 0; + head = &uhci->urb_list; + tmp = head->next; + while (tmp != head) { + struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); + + out += sprintf(out, " %d: ", ++count); + out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); + tmp = tmp->next; + } + } + + out += sprintf(out, "Remove list URBs:"); + if (list_empty(&uhci->urb_remove_list)) + out += sprintf(out, " Empty\n"); + else { + out += sprintf(out, "\n"); + count = 0; + head = &uhci->urb_remove_list; + tmp = head->next; + while (tmp != head) { + struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); + + out += sprintf(out, " %d: ", ++count); + out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); + tmp = tmp->next; + } + } + + out += sprintf(out, "Complete list URBs:"); + if (list_empty(&uhci->complete_list)) + out += sprintf(out, " Empty\n"); + else { + out += sprintf(out, "\n"); + count = 0; + head = &uhci->complete_list; + tmp = head->next; + while (tmp != head) { + struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); + + out += sprintf(out, " %d: ", ++count); + out += uhci_show_urbp(uhci, urbp, out, len - (out - buf)); + tmp = tmp->next; + } + } + + return out - buf; +} + +static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) +{ + unsigned long flags; + char *out = buf; + int i, j; + struct uhci_qh *qh; + struct uhci_td *td; + struct list_head *tmp, *head; + + spin_lock_irqsave(&uhci->schedule_lock, flags); + + out += sprintf(out, "HC status\n"); + out += uhci_show_status(uhci, out, len - (out - buf)); + + out += sprintf(out, "Frame List\n"); + for (i = 0; i < UHCI_NUMFRAMES; ++i) { + int shown = 0; + td = uhci->fl->frame_cpu[i]; + if (!td) + continue; + + if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) { + show_frame_num(); + out += sprintf(out, " frame list does not match td->dma_handle!\n"); + } + show_frame_num(); + + head = &td->fl_list; + tmp = head; + do { + td = list_entry(tmp, struct uhci_td, fl_list); + tmp = tmp->next; + out += uhci_show_td(td, out, len - (out - buf), 4); + } while (tmp != head); + } + + out += sprintf(out, "Skeleton QH's\n"); + + for (i = 0; i < UHCI_NUM_SKELQH; ++i) { + int shown = 0; + + qh = uhci->skelqh[i]; + + if (debug > 1) { + show_qh_name(); + out += uhci_show_qh(qh, out, len - (out - buf), 4); + } + + /* Last QH is the Terminating QH, it's different */ + if (i == UHCI_NUM_SKELQH - 1) { + if (qh->link != UHCI_PTR_TERM) + out += sprintf(out, " bandwidth reclamation on!\n"); + + if (qh->element != cpu_to_le32(uhci->term_td->dma_handle)) + out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); + + continue; + } + + j = (i < 7) ? 7 : i+1; /* Next skeleton */ + if (list_empty(&qh->list)) { + if (i < UHCI_NUM_SKELQH - 1) { + if (qh->link != + (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) { + show_qh_name(); + out += sprintf(out, " skeleton QH not linked to next skeleton QH!\n"); + } + } + + continue; + } + + show_qh_name(); + + head = &qh->list; + tmp = head->next; + + while (tmp != head) { + qh = list_entry(tmp, struct uhci_qh, list); + + tmp = tmp->next; + + out += uhci_show_qh(qh, out, len - (out - buf), 4); + } + + if (i < UHCI_NUM_SKELQH - 1) { + if (qh->link != + (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) + out += sprintf(out, " last QH not linked to next skeleton!\n"); + } + } + + if (debug > 2) + out += uhci_show_lists(uhci, out, len - (out - buf)); + + spin_unlock_irqrestore(&uhci->schedule_lock, flags); + + return out - buf; +} + +#define MAX_OUTPUT (64 * 1024) + +static struct proc_dir_entry *uhci_proc_root = NULL; + +struct uhci_proc { + int size; + char *data; + struct uhci_hcd *uhci; +}; + +static int uhci_proc_open(struct inode *inode, struct file *file) +{ + const struct proc_dir_entry *dp = PDE(inode); + struct uhci_hcd *uhci = dp->data; + struct uhci_proc *up; + int ret = -ENOMEM; + + lock_kernel(); + up = kmalloc(sizeof(*up), GFP_KERNEL); + if (!up) + goto out; + + up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL); + if (!up->data) { + kfree(up); + goto out; + } + + up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); + + file->private_data = up; + + ret = 0; +out: + unlock_kernel(); + return ret; +} + +static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence) +{ + struct uhci_proc *up; + loff_t new = -1; + + lock_kernel(); + up = file->private_data; + + switch (whence) { + case 0: + new = off; + break; + case 1: + new = file->f_pos + off; + break; + } + if (new < 0 || new > up->size) { + unlock_kernel(); + return -EINVAL; + } + unlock_kernel(); + return (file->f_pos = new); +} + +static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes, + loff_t *ppos) +{ + struct uhci_proc *up = file->private_data; + unsigned int pos; + unsigned int size; + + pos = *ppos; + size = up->size; + if (pos >= size) + return 0; + if (nbytes >= size) + nbytes = size; + if (pos + nbytes > size) + nbytes = size - pos; + + if (!access_ok(VERIFY_WRITE, buf, nbytes)) + return -EINVAL; + + if (copy_to_user(buf, up->data + pos, nbytes)) + return -EFAULT; + + *ppos += nbytes; + + return nbytes; +} + +static int uhci_proc_release(struct inode *inode, struct file *file) +{ + struct uhci_proc *up = file->private_data; + + kfree(up->data); + kfree(up); + + return 0; +} + +static struct file_operations uhci_proc_operations = { + .open = uhci_proc_open, + .llseek = uhci_proc_lseek, + .read = uhci_proc_read, +// write: uhci_proc_write, + .release = uhci_proc_release, +}; +#endif _____
Added: trunk/reactos/drivers/usb/cromwell/uhci/uhci-hcd.c --- trunk/reactos/drivers/usb/cromwell/uhci/uhci-hcd.c 2005-04-11 08:41:58 UTC (rev 14586) +++ trunk/reactos/drivers/usb/cromwell/uhci/uhci-hcd.c 2005-04-11 12:49:25 UTC (rev 14587) @@ -0,0 +1,2617 @@
+/* + * Universal Host Controller Interface driver for USB. + * + * Maintainer: Johannes Erdfelt johannes@erdfelt.com + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com + * (C) Copyright 1999 Randy Dunlap + * (C) Copyright 1999 Georg Acher, acher@in.tum.de + * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de + * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch + * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at + * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface + * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). + * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +#if 0 +#include <linux/config.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/proc_fs.h> +#ifdef CONFIG_USB_DEBUG +#define DEBUG +#else +#undef DEBUG +#endif +#include <linux/usb.h> + +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#endif + +#include "uhci_config.h" +#include "../usb_wrapper.h" +#include "../core/hcd.h" +#include "uhci-hcd.h" + +#if 0 +#include <linux/pm.h> +#endif + +/* + * Version Information + */ +#define DRIVER_VERSION "v2.1" +#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber" +#define DRIVER_DESC "USB Universal Host Controller Interface driver" + +/* + * debug = 0, no debugging messages + * debug = 1, dump failed URB's except for stalls + * debug = 2, dump all failed URB's (including stalls) + * show all queues in /proc/driver/uhci/[pci_addr] + * debug = 3, show all TD's in URB's when dumping + */ +#ifdef DEBUG +static int debug = 1; +#else +static int debug = 0; +#endif +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debug level"); +static char *errbuf; +#define ERRBUF_LEN (PAGE_SIZE * 8) + +#include "uhci-hub.c" +#include "uhci-debug.c" + +static kmem_cache_t *uhci_up_cachep; /* urb_priv */ + +static int uhci_get_current_frame_number(struct uhci_hcd *uhci); +static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb); +static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb); + +static void hc_state_transitions(struct uhci_hcd *uhci); + +/* If a transfer is still active after this much time, turn off FSBR */ +#define IDLE_TIMEOUT (HZ / 20) /* 50 ms */ +#define FSBR_DELAY (HZ / 20) /* 50 ms */ + +/* When we timeout an idle transfer for FSBR, we'll switch it over to */ +/* depth first traversal. We'll do it in groups of this number of TD's */ +/* to make sure it doesn't hog all of the bandwidth */ +#define DEPTH_INTERVAL 5 + +/* + * Technically, updating td->status here is a race, but it's not really a + * problem. The worst that can happen is that we set the IOC bit again + * generating a spurious interrupt. We could fix this by creating another + * QH and leaving the IOC bit always set, but then we would have to play + * games with the FSBR code to make sure we get the correct order in all + * the cases. I don't think it's worth the effort + */ +static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->frame_list_lock, flags); + uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); +} + +static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->frame_list_lock, flags); + uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); +} + +static inline void uhci_add_complete(struct uhci_hcd *uhci, struct urb *urb) +{ + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + unsigned long flags; + + spin_lock_irqsave(&uhci->complete_list_lock, flags); + list_add_tail(&urbp->complete_list, &uhci->complete_list); + spin_unlock_irqrestore(&uhci->complete_list_lock, flags); +} + +static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev) +{ + dma_addr_t dma_handle; + struct uhci_td *td; + + td = pci_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle); + if (!td) + return NULL; + + td->dma_handle = dma_handle; + + td->link = UHCI_PTR_TERM; + td->buffer = 0; + + td->frame = -1; + td->dev = dev; + + INIT_LIST_HEAD(&td->list); + INIT_LIST_HEAD(&td->fl_list); + + usb_get_dev(dev); + + return td; +} + +static inline void uhci_fill_td(struct uhci_td *td, __u32 status, + __u32 token, __u32 buffer) +{ + td->status = cpu_to_le32(status); + td->token = cpu_to_le32(token); + td->buffer = cpu_to_le32(buffer); +} + +/* + * We insert Isochronous URB's directly into the frame list at the beginning + */ +static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum) +{ + unsigned long flags; + + framenum %= UHCI_NUMFRAMES; + + spin_lock_irqsave(&uhci->frame_list_lock, flags); + + td->frame = framenum; + + /* Is there a TD already mapped there? */ + if (uhci->fl->frame_cpu[framenum]) { + struct uhci_td *ftd, *ltd; + + ftd = uhci->fl->frame_cpu[framenum]; + ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); + + list_add_tail(&td->fl_list, &ftd->fl_list); + + td->link = ltd->link; + mb(); + ltd->link = cpu_to_le32(td->dma_handle); + } else { + td->link = uhci->fl->frame[framenum]; + mb(); + uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle); + uhci->fl->frame_cpu[framenum] = td; + } + + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); +} + +static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) +{ + unsigned long flags; + + /* If it's not inserted, don't remove it */ + spin_lock_irqsave(&uhci->frame_list_lock, flags); + if (td->frame == -1 && list_empty(&td->fl_list)) + goto out; + + if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { + if (list_empty(&td->fl_list)) { + uhci->fl->frame[td->frame] = td->link; + uhci->fl->frame_cpu[td->frame] = NULL; + } else { + struct uhci_td *ntd; + + ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list); + uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle); + uhci->fl->frame_cpu[td->frame] = ntd; + } + } else { + struct uhci_td *ptd; + + ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list); + ptd->link = td->link; + } + + mb(); + td->link = UHCI_PTR_TERM; + + list_del_init(&td->fl_list); + td->frame = -1; + +out: + spin_unlock_irqrestore(&uhci->frame_list_lock, flags); +} + +/* + * Inserts a td into qh list at the top. + */ +static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, u32 breadth) +{ + struct list_head *tmp, *head; + struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct uhci_td *td, *ptd; + + if (list_empty(&urbp->td_list)) + return; + + head = &urbp->td_list; + tmp = head->next; + + /* Ordering isn't important here yet since the QH hasn't been */ + /* inserted into the schedule yet */ [truncated at 1000 lines; 3303 more skipped]