diff -urP linux-2.4.3-orig/arch/um/config.in linux-2.4.3/arch/um/config.in --- linux-2.4.3-orig/arch/um/config.in Sun Apr 15 20:32:55 2001 +++ linux-2.4.3/arch/um/config.in Sun Apr 15 20:33:52 2001 @@ -71,6 +71,8 @@ source fs/Config.in +source drivers/usb/Config.in + mainmenu_option next_comment comment 'Kernel hacking' bool 'Enable kernel debugging symbols' CONFIG_DEBUGSYM diff -urP linux-2.4.3-orig/arch/um/defconfig linux-2.4.3/arch/um/defconfig --- linux-2.4.3-orig/arch/um/defconfig Sun Apr 15 20:32:55 2001 +++ linux-2.4.3/arch/um/defconfig Sun Apr 15 20:33:52 2001 @@ -187,6 +187,83 @@ # CONFIG_NLS_UTF8 is not set # +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI_ALT is not set +# CONFIG_USB_OHCI is not set +CONFIG_USB_UMHCD=y + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PLUSB is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_NET1080 is not set + + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB misc drivers +# +# CONFIG_USB_RIO500 is not set + +# # Kernel hacking # CONFIG_DEBUGSYM=y diff -urP linux-2.4.3-orig/arch/um/drivers/Makefile linux-2.4.3/arch/um/drivers/Makefile --- linux-2.4.3-orig/arch/um/drivers/Makefile Sun Apr 15 20:32:55 2001 +++ linux-2.4.3/arch/um/drivers/Makefile Sun Apr 15 20:38:51 2001 @@ -25,6 +25,8 @@ CFLAGS_umn_user.o := $(USER_CFLAGS) CFLAGS_eth_kern.o := $(CFLAGS) CFLAGS_eth_user.o := $(USER_CFLAGS) +CFLAGS_umusb_user.o := $(USER_CFLAGS) +CFLAGS_umusb_kern.o := $(CFLAGS) obj-$(CONFIG_STDIO_CONSOLE) += stdio_console.o stdio_console_user.o obj-$(CONFIG_SSL) += ssl.o @@ -33,6 +35,7 @@ obj-$(CONFIG_BLK_DEV_UBD) += ubd.o ubd_user.o obj-$(CONFIG_NET_UMN) += umn_user.o umn_kern.o obj-$(CONFIG_NET_UM_ETH) += eth_kern.o eth_user.o +obj-$(CONFIG_USB_UMHCD) += umusb_kern.o umusb_user.o override CFLAGS = diff -urP linux-2.4.3-orig/arch/um/drivers/umusb_kern.c linux-2.4.3/arch/um/drivers/umusb_kern.c --- linux-2.4.3-orig/arch/um/drivers/umusb_kern.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.3/arch/um/drivers/umusb_kern.c Sun Apr 15 20:33:52 2001 @@ -0,0 +1,696 @@ +/* + * User-Mode Linux Interface driver for USB (take I). + * + * (c) 2001 Johan Verrept, Johan.Verrept@advalvas.be + * + * Fri Mar 16 06:50:05 CET 2001 : module compiled + * Fri Mar 16 21:00:00 CET 2001 : file created + * + * Code notes: + * I have integrated a Hub simulation. This is needed to get hubs + * working properly. Because the hub driver in the host system is + * needed to detect devices, we cannot disable it. the hub driver + * This means we cannot submit an interrupt to the hub endpoint. + * When a hub driver submits the interrupt urb, we store it. + * When the timer goes off, we check the port info on the hubs. + * If we detect a change in connected devices, we complete the + * interrupt urb. + * We have a race situation here we cannot avoid. + * If a device is plugged in and our hub driver poll the status + * of the hubport before the host hub driver does it will not + * detect the device. + * WORKAROUND: if the hub driver would check the wPortStatus + * against a known value, then it could capture a missed wPortChange. + * We would have to add more code in here to make sure that this + * check is fooled in the um hub driver. + */ + +#include "linux/config.h" +#include "linux/module.h" +#include "linux/kernel.h" +#include "linux/timer.h" +#include "linux/sched.h" +#include "linux/malloc.h" +#include "linux/usb.h" +#include "linux/init.h" + +/* USER includes */ + +#include "kern.h" +#include "kern_util.h" + +#include "umusb_kern.h" + +/* This enables debug printks */ +/* #define DEBUG */ + +/* 1 ms timeout for framecounter, 5 msec device poll interval */ +#define UMUSB_TIMEOUT HZ/10 + +#define min(a,b) (((a)<(b))?(a):(b)) + +typedef struct umusb_urbctx { + struct umusb_urbctx *next, *prev; + urb_t *urb; + struct usbdevfs_urb *uurb; + unsigned int expires; +} umusb_urbctx_t; + +typedef struct umusb_hubctx { + struct umusb_hubctx *next, *prev; + urb_t *interrupt; + umusb_hub_device_t *uhdev; +} umusb_hubctx_t; + +int umusb_unlink_urb (urb_t *urb); + +/*********** GLOBALS ************/ + +umusb_t *umusb_hcds = NULL; +struct timer_list umusb_poll_timer; +atomic_t umusb_frame_counter = ATOMIC_INIT (0); +unsigned int umusb_poll_counter = 0; +umusb_urbctx_t *umusb_pending_urbs = NULL; +umusb_hubctx_t *umusb_active_hubs = NULL; +unsigned int umusb_hub_interrupts_enabled = 0; + +umusb_device_t *umusb_last_reported_dev = NULL; + +/********************************************************************************** +* +* URB Utilities +* +***********************************************************************************/ + + +void umusb_urb_unlinkctx (umusb_urbctx_t *ctx) { + + if (!ctx) + return; + + if (ctx->next) + ctx->next->prev = ctx->prev; + + if (ctx->prev) + ctx->prev->next = ctx->next; + + if (umusb_pending_urbs == ctx) + umusb_pending_urbs = ctx->next; + + ctx->next = NULL; + ctx->prev = NULL; +} + + +int umusb_epnum_to_if (struct usb_device *dev, int epnum) { + int i, j, k, c; + + if (dev->actconfig) { + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { + j = dev->actconfig->interface[i].act_altsetting; + for (k = 0; k < dev->actconfig->interface[i].altsetting[j].bNumEndpoints; k++) + if (epnum == dev->actconfig->interface[i].altsetting[j].endpoint[k].bEndpointAddress) + return i; + }; + return -1; + } + + /* active configuration not yet set */ + for (c=0; c < dev->descriptor.bNumConfigurations ; c++) + for (i = 0; i < dev->config[c].bNumInterfaces; i++) { + j = dev->config[c].interface[i].act_altsetting; + for (k = 0; k < dev->config[c].interface[i].altsetting[j].bNumEndpoints; k++) + if (epnum == dev->config[c].interface[i].altsetting[j].endpoint[k].bEndpointAddress) + return i; + }; + + return -1; +} + + + +/********************************************************************************** +* +* URB processing +* +***********************************************************************************/ + +int umusb_urb_timeouts (unsigned long arg) { + umusb_urbctx_t *uurb, *next; + + if (!umusb_pending_urbs) + return 0; + + for ( next = ((uurb = umusb_pending_urbs)? uurb->next : NULL); uurb ; next = ((uurb = next) ? next->next: NULL) ) + if (uurb->expires < jiffies) { + printk ("UMUSBk: Timeout on uurb = 0x%p, urb = 0x%p\n", uurb, uurb->urb); + umusb_unlink_urb(uurb->urb); + uurb->urb->status = -ETIMEDOUT; + if (uurb->urb->complete) + uurb->urb->complete (uurb->urb); + } + + return 0; +}; + + +int umusb_complete_urb (struct usbdevfs_urb *uurb) { + urb_t *urb; + umusb_urbctx_t *ctx; + struct usb_device *dev; + umusb_device_t *udev; + int error; + + if (!uurb) + return -EINVAL; + + ctx = (umusb_urbctx_t *)uurb->usercontext; + urb = ctx->urb; + + dev = urb->dev; + udev = (umusb_device_t *)dev->hcpriv; + /* update urb */ + urb->status = ctx->uurb->status; + urb->actual_length = ctx->uurb->actual_length; + + printk ("UMUSBk: Completing urb (ctx = 0x%p, urb_t 0x%p, uurb 0x%p, status = %d)\n", ctx, urb, uurb, urb->status); + printk ("UMUSBk: urb->actual_length = %d\n", urb->actual_length); + switch (usb_pipetype (urb->pipe)) { + case PIPE_CONTROL: + memcpy (urb->transfer_buffer, ctx->uurb->buffer + sizeof(devrequest), urb->actual_length); + kfree (ctx->uurb->buffer); + + /* we need to capture hub port status messages to rewrite wPortChange*/ + if (udev->hubdev) { + devrequest *dr = (devrequest *) urb->setup_packet; + __u16 bmRType_bReq = dr->requesttype | dr->request << 8; + + if ( bmRType_bReq == (RH_GET_STATUS | RH_OTHER | RH_CLASS) ) { + /* rewrite wPortchange bits */ + unsigned short port = le16_to_cpu(dr->index); + unsigned long portbit = (1 << (port - 1)); + __u16 *wPortChangeData = (unsigned short *)(urb->transfer_buffer + 2); + __u16 wPortChange = le16_to_cpu( *wPortChangeData); + + printk ("UMUSBk: Detected Hub Port status check on hub 0x%p.\n", udev->hubdev); + if ( (portbit & udev->hubdev->cstatus) > 0) { + /* change has not been detected yet by usb system */ + wPortChange |= 1; + *wPortChangeData = cpu_to_le16 (wPortChange); + /* erase change bit */ + udev->hubdev->cstatus &= ~portbit; + + umusb_last_reported_dev = umusb_hubfinddevice (udev, port); + printk ("UMUSBk: Rewrote wPortChange to 0x%x on port %d, hubdev->cstatus = 0x%lx\n", wPortChange, port, udev->hubdev->cstatus); + } + } + } + break; + case PIPE_INTERRUPT: + memcpy (urb->transfer_buffer, ctx->uurb->buffer, urb->actual_length); + + if (!urb->interval) + break; + + if (urb->complete) + urb->complete (urb); + urb->status = -EINPROGRESS; + ctx->expires = urb->timeout ? jiffies + urb->timeout : 0; + error = umusb_submit_urb_user ( (umusb_device_t *)urb->dev->hcpriv, uurb); + + usb_dec_dev_use (dev); + return error; + default: + }; + + /* nuking ctx */ + umusb_urb_unlinkctx(ctx); + kfree(ctx); + + if (urb->complete) + urb->complete (urb); + + usb_dec_dev_use (dev); + return 0; +} + + +/********************************************************************************** +* +* Hub Simulation +* +***********************************************************************************/ +int umusb_hs_processurb(urb_t *urb) { + umusb_device_t * udev = (umusb_device_t *)urb->dev->hcpriv; + + if (usb_pipetype (urb->pipe) == PIPE_INTERRUPT) { + /* FIXME: the hub interrupt is not supported atm */ + if (udev->hubdev) { + umusb_hubctx_t *ctx = udev->hubdev->ctx; + + printk ("UMUSBk: Registering interrupt urb (0x%p) for hub (0x%p)\n", urb, urb->dev); + + /* check whether urb already submitted */ + if (ctx && ctx->interrupt) + return -EILSEQ; + if (!ctx) { + ctx = (umusb_hubctx_t *) kmalloc (sizeof(umusb_hubctx_t), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->prev = NULL; + ctx->next = umusb_active_hubs; + umusb_active_hubs = ctx; + } + ctx->interrupt = urb; + } + return 0; + } + if (usb_pipein(urb->pipe)) + return 1; + + /* simulate sets here */ + return 0; +} + +/********************************************************************************** +* +* Main Interrupt Handler +* +***********************************************************************************/ + +void umusb_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs) { + printk ("UMUSBk: Interrupt handler called (dev 0x%p).\n", dev_id); +} + +/********************************************************************************** +* +* Device Operations +* +***********************************************************************************/ + +/*************** Allocate Device ******************/ + +int umusb_alloc_dev (struct usb_device *dev) { + printk ("UMUSBk: umusb_alloc_dev (0x%p)\n", dev); + + /* hack. when I rewrite the wPortChange bit in the + get-status message of the parent hub, + I store this pointer. Ugly. + */ + dev->hcpriv = umusb_last_reported_dev; + + return 0; +} + +/*************** Free Device ******************/ + +int umusb_free_dev (struct usb_device *dev) { + printk ("UMUSBk: umusb_free_dev (0x%p)\n", dev); + return 0; +} + +/*************** Get Current Farme Number *****/ +/* + * synchronise this with a 1 ms tick ? + */ +int umusb_get_current_frame_number (struct usb_device *dev) { + int ret = atomic_read(&umusb_frame_counter); + printk ("UMUSBk: umusb_get_current_frame_number returns %d\n", ret); + return ret; +} + +/*************** Submit URB ******************/ + +int umusb_submit_urb (urb_t *urb) { + int error=0, send=1, intf; + umusb_urbctx_t *ctx; + struct usbdevfs_urb *uurb = NULL; + umusb_device_t * udev; + devrequest *dr; + + if (!urb) + return 0; + + /* sanity check urb */ + if (!urb->dev) + return -EINVAL; + + usb_inc_dev_use (urb->dev); + + udev = (umusb_device_t *)urb->dev->hcpriv; + + /* check whether this is the root hub, + * this is the first device, thus the first in the list. + */ + if (udev->hubdev) { + /* + if (!udev->prev) { + error = umusb_rh_processurb (urb); + goto fail; + } + */ + /* return on error or success, > 0 means not handled. */ + if ((error = umusb_hs_processurb(urb)) <= 0) + goto fail; + } + + ctx = (umusb_urbctx_t *) kmalloc (sizeof (umusb_urbctx_t) + sizeof(struct usbdevfs_urb), GFP_KERNEL); + if (!ctx) { + error = -ENOMEM; + goto fail; + } + + memset((void *) ctx, 0, sizeof (struct usbdevfs_urb) + sizeof (umusb_urbctx_t)); + uurb = (struct usbdevfs_urb *) (ctx + 1); + + /* general init */ + uurb->endpoint = (usb_pipeendpoint (urb->pipe)) | (urb->pipe & 0x80L); + uurb->buffer = urb->transfer_buffer; + uurb->buffer_length = urb->transfer_buffer_length; + uurb->actual_length = urb->actual_length; + uurb->number_of_packets = urb->number_of_packets; + uurb->signr = 0; + uurb->usercontext = ctx; + urb->hcpriv = ctx; + urb->status = -EINPROGRESS; + + /* specific init */ + switch (usb_pipetype (urb->pipe)) { + case PIPE_CONTROL: + uurb->type = USBDEVFS_URB_TYPE_CONTROL; + dr = (devrequest *)(urb->setup_packet); + + printk ("UMUSBk: ctrl req with type = %d, request %d\n", dr->requesttype, dr->request); + + if (dr->requesttype == USB_TYPE_STANDARD) { + switch (dr->request) { + case USB_REQ_SET_ADDRESS: + send = 0; + urb->status = 0; + udev->address = dr->value; + + if (urb->complete) + urb->complete(urb); + + error = 0; + goto error; + + case USB_REQ_SET_CONFIGURATION: + /* fake setconfig on claimed drivers */ + intf = umusb_epnum_to_if(urb->dev, usb_pipeendpoint(urb->pipe)); + if (!umusb_checkdriver (udev, intf)) + break; + send = 0; + urb->status = 0; + if (urb->complete) + urb->complete(urb); + + error = 0; + goto error; + + default: + } + } + + /* we need to prepend the setup_packet before the transfer_buffer */ + uurb->buffer_length = (sizeof(devrequest) + urb->transfer_buffer_length); + uurb->buffer = kmalloc (uurb->buffer_length, GFP_KERNEL); + memset (uurb->buffer, 0, uurb->buffer_length); + memcpy (uurb->buffer, urb->setup_packet, sizeof(devrequest)); + break; + + case PIPE_BULK: + case PIPE_INTERRUPT: /* interrupt urb are simulated using BULK transfers */ + uurb->type = USBDEVFS_URB_TYPE_BULK; + break; + + case PIPE_ISOCHRONOUS: + uurb->type = USBDEVFS_URB_TYPE_ISO; + + printk ("UMUSBk: Warning PIPE_ISOCHRONOUS not supported yet.\n"); + + error = -EINVAL; /* not supported yet */ + goto error; + + default: + error = -EINVAL; + goto error; + break; + }; + + printk ("UMUSBk: Submitting urb with pipe 0x%x, endpoint = 0x%x, buffer 0x%p\n", urb->pipe, uurb->endpoint, uurb->buffer); + printk ("UMUSBk: buffer_length %d, actual_length = %d, usercontext 0x%p\n", uurb->buffer_length, uurb->actual_length, uurb->usercontext); + + if (send) { + ctx->next = umusb_pending_urbs; + ctx->prev = NULL; + if (ctx->next) + ctx->next->prev = ctx; + ctx->uurb = uurb; + ctx->urb = urb; + ctx->expires = urb->timeout ? jiffies + urb->timeout : 0; + + error = umusb_submit_urb_user ( udev, uurb); + if (error<0) { + switch (usb_pipetype (urb->pipe)) { + case PIPE_CONTROL: + kfree (uurb->buffer); + default: + } + goto error; + } + umusb_pending_urbs = ctx; + } + + return 0; + error: + kfree(uurb); + fail: + usb_dec_dev_use (urb->dev); + return error; +} + +/*************** Unlink URB ******************/ + +int umusb_unlink_urb (urb_t *urb) { + umusb_urbctx_t *ctx = (umusb_urbctx_t *)urb->hcpriv; + umusb_device_t *dev = (umusb_device_t *)urb->dev->hcpriv; + + printk ("UMUSBk: Unlinking urb (ctx = 0x%p, urb_t 0x%p, dev 0x%p)\n", ctx, urb, dev); + umusb_unlink_urb_user (dev, ctx->uurb); + + umusb_urb_unlinkctx(ctx); + + switch (usb_pipetype (urb->pipe)) { + case PIPE_CONTROL: + urb->actual_length = ctx->uurb->actual_length; + memcpy (urb->transfer_buffer, ctx->uurb->buffer, urb->actual_length); + kfree (ctx->uurb->buffer); + break; + default: + }; + + kfree(ctx); + + return 0; +} + +/*************** Device Operations ******************/ + +struct usb_operations umusb_devops = { + umusb_alloc_dev, + umusb_free_dev, + umusb_get_current_frame_number, + umusb_submit_urb, + umusb_unlink_urb +}; + + +/********************************************************************************** +* +* Startup +* +***********************************************************************************/ + + +static int umusb_start_usb(umusb_t *ctx) { + int err; + struct usb_bus *bus; + struct usb_device *dev, *rootdev; + umusb_device_t *rdev; + + /* create bus */ + bus = usb_alloc_bus (&umusb_devops); + if (!bus) + return -1; + + printk ("UMUSBk: Created usb_bus (0x%p)\n", bus); + ctx->bus = bus; + bus->hcpriv = ctx; + + usb_register_bus(bus); + + rdev = ctx->realbus->devices; + /* create device */ + dev = usb_alloc_dev (NULL, ctx->bus); + if (!dev) + return -1; + + printk ("UMUSBk: usb root device allocated (dev = 0x%p)\n", dev); + /* hub device init */ + dev->hcpriv = rdev; +/* + if ((err = um_request_irq (UMUSB_IRQ, rdev->fd, umusb_interrupt_handler, + SA_INTERRUPT | SA_SHIRQ, "UMUSB", rdev)) !=0) { + printk ("UMUSBk: allocating interrupt failed (%d)\n", err); + return err; + } +*/ + ctx->bus->root_hub = dev; + usb_connect (dev); + + printk ("UMUSBk: Announcing new rootdevice (dev->devnum = %d)\n", dev->devnum); + if (usb_new_device(dev) != 0) { + usb_free_dev (dev); + return -1; + } + + return 0; + rootdev = dev; + for (rdev = rdev->next; rdev ; rdev = rdev->next) { + /* create device */ + dev = usb_alloc_dev (rootdev, ctx->bus); + if (!dev) + continue; +/* + if ((err = um_request_irq (UMUSB_IRQ, rdev->fd, umusb_interrupt_handler, + SA_INTERRUPT | SA_SHIRQ, "UMUSB", rdev)) !=0) { + printk ("UMUSBk: allocating interrupt failed\n"); + return err; + } +*/ + /* device init */ + dev->hcpriv = rdev; + + usb_connect (dev); + + if (usb_new_device(dev) != 0) { + usb_free_dev (dev); + continue; + }; + + printk("UMUSBk: Created new device (dev = 0x%p, devnum = %d)\n", dev, dev->devnum); + }; + + return 0; +} + +/********************************************************************************** +* +* Interrupt routine +* +***********************************************************************************/ + +void umusb_interrupt (unsigned long arg) { + int status = 0; + + if (umusb_pending_urbs) { + umusb_urbctx_t *uurb, *next; + for (uurb = umusb_pending_urbs; uurb ; uurb = next) { + next = uurb->next; + status = umusb_interrupt_handler_user (uurb->urb->dev->hcpriv); + + if ( (status == -EAGAIN) && uurb->expires && (uurb->expires < jiffies)) { + printk ("UMUSBk: Timeout on uurb = 0x%p, urb = 0x%p\n", uurb->uurb, uurb->urb); + umusb_unlink_urb(uurb->urb); + uurb->urb->status = -ETIMEDOUT; + if (uurb->urb->complete) + uurb->urb->complete (uurb->urb); + } + }; + } + + if (umusb_hub_interrupts_enabled && umusb_active_hubs) { + umusb_hubctx_t *hub, *next; + unsigned long bitmap; + umusb_device_t *udev; + + for (hub = umusb_active_hubs; hub; hub = next) { + next = hub->next; + /* check hub status changes here */ + if (!hub->interrupt) + continue; + + udev = (umusb_device_t *)hub->interrupt->dev->hcpriv; + umusb_checkhubportchange (udev, &bitmap); + if (bitmap) { + urb_t *urb = hub->interrupt; + + printk ("UMUSBk: Hub Interrupt on hub 0x%p, devnum %d, host devnum %d, bitmap 0x%x\r\n", hub, urb->dev->devnum, ((umusb_device_t *)urb->dev->hcpriv)->devnum, bitmap); + + /* first rescan bus to be sure we know the devices ourself. expensive! */ + umusb_scanbus(udev->bus); + + urb->status = 0; + if (urb->complete) + urb->complete (urb); + + /* reset status */ + urb->status = -EINPROGRESS; + } + } + } + umusb_poll_timer.expires = jiffies + UMUSB_TIMEOUT; + add_timer (&umusb_poll_timer); +} + +/********************************************************************************** +* +* Init and cleanup +* +***********************************************************************************/ + +int umusb_hcd_init (void) { + int i, num; + umusb_bus_t *bus; + + printk("UMUSBk: UserMode HCD initialising.\n"); + /* let's scan for hcd's */ + num = umusb_scanhcd(); + + umusb_hcds = kmalloc( sizeof(umusb_t) * num, GFP_KERNEL); + + if (!umusb_hcds) { + printk ("UMUSB: kmem_cache_create for umusb_desc failed (out of memory)"); + return -ENOMEM; + } + + memset ((void *)umusb_hcds, 0, sizeof(umusb_t) * num); + + /* frame interrupt faker */ + init_timer (&umusb_poll_timer); + umusb_poll_timer.expires = jiffies + UMUSB_TIMEOUT; + umusb_poll_timer.data = (unsigned long) (&umusb_poll_timer); + umusb_poll_timer.function = umusb_interrupt; + add_timer (&umusb_poll_timer); + + for (i=0, bus = umusb_busses; i < num && bus; i++, bus = bus->next) { + printk ("UMUSBk: Adding bus (ctx = 0x%p, bus = 0x%p).\n", umusb_hcds + i, bus); + umusb_hcds[i].realbus = bus; + umusb_scanbus(bus); + umusb_start_usb (&(umusb_hcds[i])); + } + + umusb_hub_interrupts_enabled = 1; + return 0; +} + + +void umusb_hcd_cleanup (void) { + if (umusb_hcds) + kfree (umusb_hcds); + return; +} + +module_init (umusb_hcd_init); +module_exit (umusb_hcd_cleanup); diff -urP linux-2.4.3-orig/arch/um/drivers/umusb_kern.h linux-2.4.3/arch/um/drivers/umusb_kern.h --- linux-2.4.3-orig/arch/um/drivers/umusb_kern.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.3/arch/um/drivers/umusb_kern.h Sun Apr 15 20:33:52 2001 @@ -0,0 +1,66 @@ + +#include "umusb_user.h" + + +/************ TYPES ************/ + +typedef struct umusb { + struct usb_bus *bus; + + umusb_bus_t *realbus; + } umusb_t; + +/* ------------------------------------------------------------------------- + Virtual Root HUB + ------------------------------------------------------------------------- */ +/* destination of request */ +#define RH_DEVICE 0x00 +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +/* Our Vendor Specific feature */ +#define RH_REMOVE_EP 0x00 + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 diff -urP linux-2.4.3-orig/arch/um/drivers/umusb_user.c linux-2.4.3/arch/um/drivers/umusb_user.c --- linux-2.4.3-orig/arch/um/drivers/umusb_user.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.3/arch/um/drivers/umusb_user.c Sun Apr 15 20:33:52 2001 @@ -0,0 +1,470 @@ +/* + * User Mode Linux USB HCD, Userspace part. + * + * Copyright 2001, Johan Verrept (Johan.Verrept@advalvas.be) + * + * Licensed under the GPL + * + * Credits: + * - Device sacnning code based on libusb-0.1.1, + * Johannes Erdfelt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "umusb_user.h" +#include "user_util.h" +#include "kern_util.h" +#include "user.h" + + +#define UMUSB_DIRNAME "/proc/bus/usb" +/* 1 ms timeout */ + +/* consts */ +unsigned char *umusb_dirname = UMUSB_DIRNAME; + +/* local (global) data */ +umusb_bus_t *umusb_busses; +spinlock_t umusb_busses_lock = SPIN_LOCK_UNLOCKED; + +/* spinlock_t umusb_pollfds_lock = SPIN_LOCK_UNLOCKED;*/ +struct pollfd *umusb_pollfds = NULL; +unsigned int umusb_pollfds_size = 0; + +extern int umusb_completeurb (struct usbdevfs_urb *urb); + +/************ LOCAL FUNCTIONS ***********/ + +int umusb_buildpollfds (void) { + umusb_bus_t *bus; + umusb_device_t *dev; + int count = 0, i; + struct pollfd *tmp; + + for (bus = umusb_busses ; bus ; bus = bus->next) + count += bus->devcount; + + tmp = (struct pollfd *) um_kmalloc(sizeof(struct pollfd)*count); + + i=count; + for (bus=umusb_busses; bus; bus = bus->next) + for (dev=bus->devices; dev; dev = dev->next) { + i--; + tmp [i].fd = dev->fd; + tmp [i].events = POLLIN | POLLHUP | POLLOUT; + tmp [i].revents = 0; + } + + /* spin_lock_irq (&umusb_pollfds_lock);*/ + if (umusb_pollfds) + kfree (umusb_pollfds); + + umusb_pollfds = tmp; + umusb_pollfds_size = count; + printk ("UMUSBu: umusb_pollfds 0x%p, umusb_pollfds_size 0x%d\n", umusb_pollfds, umusb_pollfds_size); + /* spin_unlock_irq (&umusb_pollfds_lock);*/ + + return count; + } + +/************ IFACE FUNCTIONS ***********/ +int umusb_scanbus (umusb_bus_t *bus) { + DIR *dir; + struct dirent *entry; + unsigned char path[PATH_MAX + 1]; + unsigned char desc[64]; + umusb_device_t *dev, *last; + int devnum, desc_len, ret, newdev = 0; + + printk ("UMUSBu: Scanning Bus (0x%p)...\n", bus); + snprintf (path, PATH_MAX, "%s/%03d", umusb_dirname, bus->busnum); + + dir = opendir(path); + if (!dir) + return -errno; + + last = bus->devices; + while ((entry = readdir(dir)) != NULL) { + /* Skip anything starting with a . */ + if (entry->d_name[0] == '.') + continue; + + devnum = atoi(entry->d_name); + + /* do we have this device already ? (allows rescanning) */ + for (dev = bus->devices; dev && dev->devnum != devnum ; dev = dev->next); + if (dev) + continue; + + dev = (umusb_device_t *) um_kmalloc (sizeof (umusb_device_t)); + if (!dev) + continue; + + memset ((void*)dev, 0, sizeof(umusb_device_t)); + + dev->bus = bus; + dev->devnum = devnum; + + snprintf (path, PATH_MAX, "%s/%03d/%03d", umusb_dirname, bus->busnum, dev->devnum); + dev->fd = open (path, O_RDWR); + if (dev->fd < 0) { + kfree (dev); + continue; + }; + + /* determine length */ + desc_len = 0; + while ( (ret = read(dev->fd, desc, 64))) desc_len += ret; + lseek (dev->fd, SEEK_SET, 0); + dev->desc = (unsigned char *) um_kmalloc (desc_len); + if (dev->desc < 0) { + kfree (dev); + continue; + } + ret = read (dev->fd, dev->desc, desc_len); + if (ret != desc_len) { + kfree (dev); + continue; + } + dev->desc_len = desc_len; + + if (umusb_ishub(dev)) { + dev->hubdev = um_kmalloc (sizeof(umusb_hub_device_t)); + memset (dev->hubdev, 0, sizeof(umusb_hub_device_t)); + umusb_gethubports (dev, NULL); + } + + printk ("UMUSBu: New device found (devnum = %d, dev = 0x%p, fd = %d, hubctx = 0x%p)\n", devnum, dev, dev->fd, dev->hubdev); + + spin_lock (bus->devlock); + dev->next = NULL; + dev->prev = last; + if (last) + last->next = dev; + else + bus->devices = dev; + bus->devcount++; + last = dev; + spin_unlock (bus->devlock); + + newdev++; + } + + if (newdev > 0) umusb_buildpollfds(); + printk ("UMUSBu: Bus scan complete, bus has %d devices, %d new\n", bus->devcount, newdev); + closedir (dir); + return 0; + } + +int umusb_clearbus (umusb_bus_t *bus) { + umusb_device_t *dev, *nextdev; + + if (!bus) + return -EINVAL; + + if (!bus->devices) + return 0; + + for (dev = bus->devices; (nextdev = dev->next); dev=nextdev) + kfree(dev); + kfree(dev); + + return 0; + } + +int umusb_scanhcd (void) { + DIR *dir; + struct dirent *entry; + umusb_bus_t *bus, *last; + int busnum, ret, count = 0; + + dir = opendir (umusb_dirname); + if (!dir) { + printk ("Sorry, cannot seem to find %s\n", umusb_dirname); + return -EINVAL; + }; + + printk ("UMUSBu: Scanning system for busses (HCDs)\n"); + + last = umusb_busses; + + /* We create a virtual UM HCD per real HCD */ + while((entry = readdir(dir)) != NULL) { + /* Skip anything starting with a . */ + if (entry->d_name[0] == '.') + continue; + + ret = strspn(entry->d_name, "0123456789"); + if (ret != strlen(entry->d_name)) + continue; + + busnum = atoi(entry->d_name); + + /* this allows rescan. unlikely, unless after an insmod in the parent kernel */ + for (bus = umusb_busses; bus && bus->busnum != busnum ; bus = bus->next); + if (bus) + continue; + + bus = (umusb_bus_t *)um_kmalloc( sizeof(umusb_bus_t)); + if (!bus) + continue; + + memset ((void *)bus, 0, sizeof(umusb_bus_t)); + + bus->busnum = busnum; + + printk ("UMUSBu: Identified bus (busnum = %d, bus = 0x%p)\n", busnum, bus); + + spin_lock (&umusb_busses_lock); + bus->next = NULL; + bus->prev = last; + if (last) + last->next = bus; + else + umusb_busses = bus; + last = bus; + spin_unlock (&umusb_busses_lock); + + count++; + } + + printk("UMUSBu: System contains %d busses\n", count); + closedir(dir); + return count; + } + +int umusb_cleaup (void) { + umusb_bus_t *bus, *nextbus; + umusb_device_t *dev, *nextdev; + + spin_lock (&umusb_busses_lock); + for (bus = umusb_busses; bus && (nextbus = bus->next); bus=nextbus) { + /* flush devices */ + spin_lock (&bus->devlock); + if (bus->devices) { + for (dev = bus->devices; dev && (nextdev = dev->next); dev=nextdev) + kfree(dev); + } + spin_unlock (&bus->devlock); + kfree (bus); + }; + + umusb_busses = NULL; + spin_unlock (&umusb_busses_lock); + + return 0; + } + +int umusb_interface_claimed (umusb_device_t *dev, int iface) { + /* test whether the iface is claimed */ + return 0; + } + + +int umusb_submit_urb_user (umusb_device_t *dev, struct usbdevfs_urb *urb) { + int ret = ioctl (dev->fd, USBDEVFS_SUBMITURB, urb); + if (ret < 0 ) { + printk ("umusb_submit_urb_user failed, retval = %d, errno = %d\n", ret, errno); + } + return ret; + } + +int umusb_unlink_urb_user (umusb_device_t *dev, struct usbdevfs_urb *urb) { + int ret = ioctl (dev->fd, USBDEVFS_DISCARDURB, urb); + return ret; + }; + +int umusb_read_descriptor (umusb_device_t *dev, unsigned char *data, int len, int offset) { + int ret = ((len+offset) > dev->desc_len) ? (dev->desc_len - offset) : len; + + memcpy (data, dev->desc+offset, ret ); + return ret; + } + +int umusb_set_configuration (umusb_device_t *dev, int conf) { + int ret = ioctl (dev->fd, USBDEVFS_SETCONFIGURATION, &conf); + return ret; + } + +/************************************************** +** Hub Utilities +***************************************************/ +int umusb_gethubports (umusb_device_t *dev, char *nports) { + int ret; + struct usbdevfs_ioctl ioctrl; + + if (!dev->hubdev) + return 0; + + /* cache this stuff */ + if (dev->hubdev->portinfo.nports) { + return dev->hubdev->portinfo.nports; + } + + ioctrl.ioctl_code = USBDEVFS_HUB_PORTINFO; + ioctrl.data = &dev->hubdev->portinfo; + ioctrl.ifno = 0; + + ret = ioctl ( dev->fd, USBDEVFS_IOCTL, &ioctrl); + if (ret < 0) + return ret; + + /* clean status */ + memset (dev->hubdev->portinfo.port, 0, 127); + + if (nports) + *nports = dev->hubdev->portinfo.nports; + + return 0; +} + +int umusb_checkhubportstatus (umusb_device_t *dev, unsigned long *bitmap) { + unsigned int i, ports; + unsigned char *portmap; + + if (!dev->hubdev) + return -EINVAL; + + if (ports > 32) + return -EINVAL; + + ports = dev->hubdev->portinfo.nports; + portmap = dev->hubdev->portinfo.port; + + for (i=0; i < ports ; i++) + if (portmap[i]) + *bitmap |= (1 << i); + + return 0; +} + +int umusb_checkhubportchange (umusb_device_t *dev, unsigned long *bitmap) { + struct usbdevfs_hub_portinfo info; + struct usbdevfs_ioctl ioctrl; + unsigned int ret, i, ports; + unsigned long bit; + unsigned char *portmap; + + if (!dev || !dev->hubdev) + return -EINVAL; + + ports = dev->hubdev->portinfo.nports; + portmap = dev->hubdev->portinfo.port; + + ioctrl.ioctl_code = USBDEVFS_HUB_PORTINFO; + ioctrl.data = &info; + ioctrl.ifno = 0; + + ret = ioctl ( dev->fd, USBDEVFS_IOCTL, &ioctrl); + if (ret <0) + return -errno; + + *bitmap = 0; + for (i=0; i < ports; i++ ) + if (portmap[i] != info.port[i]) { + *bitmap |= (1 << i); + portmap[i] = info.port[i]; + } + + /* update recorded cstatus */ + dev->hubdev->cstatus |= *bitmap; + + return 0; +} + +umusb_device_t *umusb_hubfinddevice(umusb_device_t *dev, unsigned int port) { + int devnum = dev->hubdev->portinfo.port[port-1]; + umusb_device_t *child; + + spin_lock (&dev->bus->devlock); + + for (child = dev->bus->devices; child ; child = child->next) + if (child->devnum == devnum) + break; + + spin_unlock (&dev->bus->devlock); + + return child; +}; + +int umusb_checkdriver (umusb_device_t *dev, int interface) { + struct usbdevfs_getdriver driver; + int ret; + + driver.interface = interface; + ret = ioctl (dev->fd, USBDEVFS_GETDRIVER, &driver); + if (ret) { + printk ("UMUSBk: umusb_checkdriver failed (%d)\n", ret); + /* we return 1 so hcd thinks this device is taken this is safer. */ + return 1; + } + + return (driver.driver[0] > 0); + } + +int umusb_ishub (umusb_device_t *dev) { + struct usbdevfs_getdriver driver; + int ret; + + driver.interface = 0; + ret = ioctl (dev->fd, USBDEVFS_GETDRIVER, &driver); + if (ret) { + printk ("UMUSBk: umusb_ishub failed(dev = 0x%p) err = %d\n", dev, ret); + return 0; + } + + return ((driver.driver[0]=='h') && + (driver.driver[1]=='u') && + (driver.driver[2]=='b') && + (driver.driver[3]=='\0') ); + } + + +/****************** INTERNAL FUNCTIONS *********************/ + +int umusb_interrupt_handler_user (umusb_device_t *dev) { + int err; + struct usbdevfs_urb *urb; + + err = ioctl (dev->fd, USBDEVFS_REAPURBNDELAY, &urb); + if (err<0) { + if (err != -EAGAIN ) + printk ("UMUSBu: USBDEVFS_REAPURBNDELAY failed (%d) %s.\n", errno, strerror(errno)); + return err; + } + + return umusb_complete_urb (urb); + }; + +void umusb_poll (unsigned long arg) { + int num, i, err, flags; + struct pollfd *pfd; + struct usbdevfs_urb *urb; + + if (!umusb_pollfds || !umusb_pollfds_size) + return; + + while ((num = poll (umusb_pollfds, umusb_pollfds_size, 0))) + for (i = 0, pfd = umusb_pollfds; (i < umusb_pollfds_size) && num; i++, pfd++) + if (pfd->revents!=0) { + /* handle event */ + pfd->revents = 0; + err = ioctl (pfd->fd, USBDEVFS_REAPURBNDELAY, &urb); + if (err) + umusb_complete_urb (urb); + pfd->revents=0; + }; + + return; + } diff -urP linux-2.4.3-orig/arch/um/drivers/umusb_user.h linux-2.4.3/arch/um/drivers/umusb_user.h --- linux-2.4.3-orig/arch/um/drivers/umusb_user.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.3/arch/um/drivers/umusb_user.h Sun Apr 15 20:33:52 2001 @@ -0,0 +1,65 @@ + + +#undef UMUSB_USER_H_KERNEL + +#ifdef __KERNEL__ +#define UMUSB_USER_H_KERNEL +#undef __KERNEL__ +#endif + +#include + +#ifdef UMUSB_USER_H_KERNEL +#define __KERNEL__ +#endif + +struct usb_device; + +struct umusb_bus; +extern struct umusb_hubctx; + +typedef struct umusb_hub_device { + struct usbdevfs_hub_portinfo portinfo; + + struct umusb_hubctx *ctx; + unsigned long cstatus; +} umusb_hub_device_t; + +typedef struct umusb_device { + struct umusb_device *next, *prev; + + int devnum; + int fd; + int address; + umusb_hub_device_t *hubdev; + + void *dev; + unsigned char *desc; + unsigned int desc_len; + + struct umusb_bus *bus; + } umusb_device_t; + +typedef struct umusb_bus { + struct umusb_bus *next, *prev; + + int busnum; + + int devcount; + struct umusb_device *devices; + spinlock_t devlock; + } umusb_bus_t; + + +extern umusb_bus_t *umusb_busses; + +extern int umusb_scanhcd (void); +extern int umusb_scanbus (umusb_bus_t *bus); +extern int umusb_clearbus (umusb_bus_t *bus); +extern int umusb_submit_urb_user (umusb_device_t *dev, struct usbdevfs_urb *urb); +extern int umusb_unlink_urb_user (umusb_device_t *dev, struct usbdevfs_urb *urb); +extern int umusb_interrupt_handler_user (umusb_device_t *dev); +extern int umusb_read_descriptor (umusb_device_t *dev, unsigned char *data, int len, int offset); +extern int umusb_gethubports (umusb_device_t *dev, char *nports); +extern int umusb_checkdriver (umusb_device_t *dev, int interface); +extern int umusb_ishub (umusb_device_t *dev); diff -urP linux-2.4.3-orig/arch/um/kernel/irq_user.c linux-2.4.3/arch/um/kernel/irq_user.c --- linux-2.4.3-orig/arch/um/kernel/irq_user.c Sun Apr 15 20:32:56 2001 +++ linux-2.4.3/arch/um/kernel/irq_user.c Sun Apr 15 20:41:13 2001 @@ -11,60 +11,66 @@ #include #include #include +#include #include "user_util.h" #include "kern_util.h" #include "user.h" +#define ASSERT(x...) if (!(x)) {\ + printk ("ASSERT failed at %s:%d\n", __FILE__, __LINE__);\ + stop();\ + } + struct irq_fd { struct irq_fd *next; void *id; int fd; int irq; int pid; + short events; }; static struct irq_fd *active_fds = NULL; -static fd_set active_fd_mask; -static int max_fd = -1; +static struct irq_fd **last_fds = &active_fds; +static struct pollfd *pollfds = NULL; +static int pollfds_num = 0; +static int pollfds_size = 0; extern int io_count, intr_count; void sigio_handler(int sig, void *sc, int usermode) { struct irq_fd *irq_fd, *next; - struct timeval tv; - fd_set fds; - int i, n, fd; - - while(1){ - tv.tv_sec = 0; - tv.tv_usec = 0; - fds = active_fd_mask; - if((n = select(max_fd + 1, &fds, NULL, NULL, &tv)) < 0){ - printk("sigio_handler : select returned %d, " - "errno = %d\n", n, errno); + struct pollfd *pfd; + int n; + + while(1) { + if((n = poll (pollfds, pollfds_num, 0)) < 0){ + printk ("sigio_handler : poll returned %d, " + "errno %d\n", n, errno); break; } if(n == 0) break; - for(i=0;i<=max_fd;i++){ - if(FD_ISSET(i, &fds)) FD_CLR(i, &active_fd_mask); - } - for(irq_fd=active_fds;irq_fd != NULL;irq_fd = next){ - /* These mysterious assignments protect us against + for (irq_fd=active_fds, pfd = pollfds; irq_fd != NULL; irq_fd = next, pfd++) { + ASSERT(irq_fd->fd == pfd->fd); + /* This mysterious assignment protects us against * the irq handler freeing the irq from under us. */ next = irq_fd->next; - fd = irq_fd->fd; - if(FD_ISSET(irq_fd->fd, &fds)) - do_IRQ(irq_fd->irq, usermode); - } + if (pfd->revents) { + pfd->events = 0; /* disable */ + do_IRQ (irq_fd->irq, usermode); + } + } } } int activate_fd(int irq, int fd, void *dev_id) { struct irq_fd *new_fd; + struct pollfd *tmp_pfd; int pid, retval; + int events = POLLIN | POLLPRI; for(new_fd = active_fds;new_fd;new_fd = new_fd->next){ if(new_fd->fd == fd){ @@ -87,37 +93,72 @@ } new_fd = um_kmalloc(sizeof(*new_fd)); if(new_fd == NULL) return(-ENOMEM); - new_fd->next = active_fds; + new_fd->next = NULL; new_fd->id = dev_id; new_fd->irq = irq; new_fd->fd = fd; - new_fd->pid = current_external_pid(); - active_fds = new_fd; - if(fd > max_fd) max_fd = fd; - FD_SET(fd, &active_fd_mask); + new_fd->pid = external_pid(NULL); + new_fd->events = events; + + *last_fds = new_fd; + last_fds = &(new_fd->next); + + pollfds_num++; + if (pollfds_num > pollfds_size) { + tmp_pfd = pollfds; + pollfds = um_kmalloc (pollfds_num * sizeof (struct pollfd)); + if (tmp_pfd) { + memcpy (pollfds, tmp_pfd, (sizeof(struct pollfd)*pollfds_size)); + kfree (tmp_pfd); + } + pollfds_size = pollfds_num; + } + tmp_pfd = pollfds + (pollfds_num-1); + tmp_pfd->fd = fd; + tmp_pfd->events = events; + tmp_pfd->revents = 0; + return(0); } void free_irq_fd(void *dev_id) { + int i; struct irq_fd **prev; + struct pollfd *pfd; prev = &active_fds; + pfd = pollfds; while(*prev != NULL){ if((*prev)->id == dev_id){ struct irq_fd *old_fd = *prev; + ASSERT (pfd->fd == old_fd->fd); + memcpy (pfd, pfd+1, ((unsigned long)(pollfds+pollfds_num) - (unsigned long) (pfd+1))); + pollfds_num--; + + if (last_fds == &(old_fd->next)) + last_fds = prev; + *prev = (*prev)->next; - FD_CLR(old_fd->fd, &active_fd_mask); kfree(old_fd); return; } prev = &(*prev)->next; + pfd++; + i++; } } void reactivate_fd(int fd) { - FD_SET(fd, &active_fd_mask); + struct pollfd *pfd; + struct irq_fd *ifd; + + for (ifd = active_fds, pfd = pollfds; ifd && (ifd->fd != fd); ifd = ifd->next, pfd++) ASSERT (ifd->fd == pfd->fd); + if (!ifd) + return; + + pfd->events = ifd->events; } void forward_interrupts(int pid) diff -urP linux-2.4.3-orig/drivers/usb/Config.in linux-2.4.3/drivers/usb/Config.in --- linux-2.4.3-orig/drivers/usb/Config.in Sun Apr 15 20:32:04 2001 +++ linux-2.4.3/drivers/usb/Config.in Sun Apr 15 20:33:52 2001 @@ -25,6 +25,10 @@ fi dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB + if [ "$CONFIG_USERMODE" == "y" ]; then + bool ' User Mode HCD' CONFIG_USB_UMHCD $CONFIG_USB + fi + comment 'USB Device Class drivers' dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL diff -urP linux-2.4.3-orig/include/asm-um/irq.h linux-2.4.3/include/asm-um/irq.h --- linux-2.4.3-orig/include/asm-um/irq.h Sun Apr 15 20:30:51 2001 +++ linux-2.4.3/include/asm-um/irq.h Sun Apr 15 20:33:52 2001 @@ -14,8 +14,9 @@ #define UM_ETH_IRQ 4 #define SSL_IRQ 5 #define ACCEPT_IRQ 6 +#define UMUSB_IRQ 7 -#define LAST_IRQ ACCEPT_IRQ +#define LAST_IRQ UMUSB_IRQ #define NR_IRQS (LAST_IRQ + 1) extern int um_request_irq(unsigned int irq, int fd,