/* Handle general USB interrupts and dispatch according to type. * This function implements TRM Figure 14-13. */ void S3C24X0_udc_irq(void) { struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array; u_int32_t save_idx = inl(S3C24X0_UDC_INDEX_REG); /* read interrupt sources */ u_int32_t usb_status = inl(S3C24X0_UDC_USB_INT_REG); u_int32_t usbd_status = inl(S3C24X0_UDC_EP_INT_REG); debug("< IRQ usbs=0x%02x, usbds=0x%02x start > \n", usb_status, usbd_status); /* clear interrupts */ outl(usb_status, S3C24X0_UDC_USB_INT_REG); if (usb_status & S3C24X0_UDC_USBINT_RESET) { //serial_putc('R'); debug("RESET pwr=0x%x\n", inl(S3C24X0_UDC_PWR_REG)); udc_setup_ep(udc_device, 0, ep0); outl(S3C24X0_UDC_EP0_CSR_SSE|S3C24X0_UDC_EP0_CSR_SOPKTRDY, S3C24X0_UDC_EP0_CSR_REG); ep0->state = EP0_IDLE; usbd_device_event_irq (udc_device, DEVICE_RESET, 0); } if (usb_status & S3C24X0_UDC_USBINT_RESUME) { debug("RESUME\n"); usbd_device_event_irq(udc_device, DEVICE_BUS_ACTIVITY, 0); } if (usb_status & S3C24X0_UDC_USBINT_SUSPEND) { debug("SUSPEND\n"); usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); } /* Endpoint Interrupts */ if (usbd_status) { int i; if (usbd_status & S3C24X0_UDC_INT_EP0) { outl(S3C24X0_UDC_INT_EP0, S3C24X0_UDC_EP_INT_REG); S3C24X0_udc_ep0(); } for (i = 1; i < 5; i++) { u_int32_t tmp = 1 << i; if (usbd_status & tmp) { /* FIXME: Handle EP X */ outl(tmp, S3C24X0_UDC_EP_INT_REG); S3C24X0_udc_epn(i); } } } S3C24X0_UDC_SETIX(save_idx); }
/* bi_modinit - commission bus interface driver */ int __init bi_modinit(void) { struct usb_bus_instance * bus; struct usb_device_instance * device; //extern const char __usbd_module_info[]; //printk(KERN_INFO "%s (dbg=\"%s\")\n", __usbd_module_info, dbg?dbg:""); if (0 != scan_debug_options("usb-bus",dbg_table,dbg)) { printk("Failed to scan dbg in bi_modinit\n"); } if (bi_udc_init()) { return(-EINVAL); } // register this bus interface driver and create the device driver instance if ((bus = usbd_register_bus(&bi_driver))==NULL) { bi_udc_exit(); return -EINVAL; } // see if we can scrounge up something to set a sort of unique device // address if (!udc_serial_init(bus)) { dbg_init(1,"serial: %s %04x", bus->serial_number_str, bus->serial_number); } if ((device = usbd_register_device(NULL, bus, 8))==NULL) { usbd_deregister_bus(bus); bi_udc_exit(); return -EINVAL; } #ifdef CONFIG_PM // register with power management pm_dev = pm_register(PM_USB_DEV, PM_SYS_UNKNOWN, bi_pm_event); pm_dev->data = device; #endif bus->device = device; device_array[0] = device; // initialize the device { struct usb_endpoint_instance *endpoint = device->bus->endpoint_array + 0; // setup endpoint zero endpoint->endpoint_address = 0; endpoint->tx_attributes = 0; endpoint->tx_transferSize = 255; endpoint->tx_packetSize = udc_ep0_packetsize(); endpoint->rcv_attributes = 0; endpoint->rcv_transferSize = 0x8; endpoint->rcv_packetSize = udc_ep0_packetsize(); udc_setup_ep(device, 0, endpoint); } // hopefully device enumeration will finish this process udc_startup_events(device); #ifdef CONFIG_PM dbg_pm(0,"pm_dev->callback#%p",pm_dev->callback); if (!udc_connected()) { /* Fake a call from the PM system to suspend the UDC until it is needed (cable connect, etc) */ (void) bi_pm_event(pm_dev,PM_SUSPEND,NULL); /* There appears to be no constant for this, but inspection of arch/arm/mach-l7200/apm.c:send_event() shows that the suspended state is 3 (i.e. pm_send_all(PM_SUSPEND, (void *)3)) corresponding to ACPI_D3. */ pm_dev->state = 3; } #endif if (dbgflg_usbdbi_tick > 0) { // start ticker ticker_kickoff(); } dbgLEAVE(dbgflg_usbdbi_init,1); return 0; }
/* bi_modinit - commission bus interface driver */ static int __init bi_modinit (void) { extern const char __usbd_module_info[]; struct usb_bus_instance *bus; struct usb_device_instance *device; struct bi_data *data; printk (KERN_INFO "%s (dbg=\"%s\")\n", __usbd_module_info, dbg ? dbg : ""); // process debug options if (0 != scan_debug_options ("usbd-bi", dbg_table, dbg)) { return -EINVAL; } // check if we can see the UDC if (bi_udc_init ()) { return -EINVAL; } // allocate a bi private data structure if ((data = kmalloc (sizeof (struct bi_data), GFP_KERNEL)) == NULL) { bi_udc_exit (); return -EINVAL; } memset (data, 0, sizeof (struct bi_data)); // register this bus interface driver and create the device driver instance if ((bus = usbd_register_bus (&bi_driver)) == NULL) { kfree (data); bi_udc_exit (); return -EINVAL; } bus->privdata = data; // see if we can scrounge up something to set a sort of unique device address if (!udc_serial_init (bus)) { dbg_init (1, "serial: %s %04x\n", bus->serial_number_str, bus->serial_number); } if ((device = usbd_register_device (NULL, bus, 8)) == NULL) { usbd_deregister_bus (bus); kfree (data); bi_udc_exit (); return -EINVAL; } #if defined(CONFIG_PM) && !defined(CONFIG_USBD_MONITOR) && !defined(CONFIG_USBD_MONITOR_MODULE) // register with power management pm_dev = pm_register (PM_USB_DEV, PM_SYS_UNKNOWN, bi_pm_event); pm_dev->data = device; #endif #ifdef CONFIG_DPM /* MVL-CEE */ bi_udc_ldm_driver_register(); bi_udc_ldm_device_register(); #endif bus->device = device; device_array[0] = device; // initialize the device { struct usb_endpoint_instance *endpoint = device->bus->endpoint_array + 0; // setup endpoint zero endpoint->endpoint_address = 0; endpoint->tx_attributes = 0; endpoint->tx_transferSize = 255; endpoint->tx_packetSize = udc_ep0_packetsize (); endpoint->rcv_attributes = 0; endpoint->rcv_transferSize = 0x8; endpoint->rcv_packetSize = udc_ep0_packetsize (); udc_setup_ep (device, 0, endpoint); } // hopefully device enumeration will finish this process printk(KERN_INFO"bi_modinit: call udc_startup_events\n"); udc_startup_events (device); #if defined(CONFIG_PM) && !defined(CONFIG_USBD_MONITOR) && !defined(CONFIG_USBD_MONITOR_MODULE) dbg_pm (0, "pm_dev->callback#%p", pm_dev->callback); if (!udc_connected ()) { /* Fake a call from the PM system to suspend the UDC until it is needed (cable connect, etc) */ (void) bi_pm_event (pm_dev, PM_SUSPEND, NULL); /* There appears to be no constant for this, but inspection of arch/arm/mach-l7200/apm.c:send_event() shows that the suspended state is 3 (i.e. pm_send_all(PM_SUSPEND, (void *)3)) corresponding to ACPI_D3. */ pm_dev->state = 3; } #endif if (dbgflg_usbdbi_tick > 0) { // start ticker ticker_kickoff (); } #ifdef CONFIG_USBD_PROCFS { struct proc_dir_entry *p; // create proc filesystem entries if ((p = create_proc_entry ("usbd", 0, 0)) == NULL) { return -ENOMEM; } p->proc_fops = &usbd_proc_operations_functions; } #endif dbgLEAVE (dbgflg_usbdbi_init, 1); return 0; }
/* bi_config - commission bus interface driver */ static int bi_config(struct usb_device_instance *device) { int i; struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint_descriptor; int found_tx = 0; int found_rx = 0; dbg_init(1,"checking config: config: %d interface: %d alternate: %d", device->configuration, device->interface, device->alternate); bi_disable_endpoints(device); // audit configuration for compatibility if (!(interface = usbd_device_interface_descriptor(device, 0, device->configuration, device->interface, device->alternate))) { dbg_init(0,"cannot fetch interface descriptor c:%d i:%d a:%d", device->configuration, device->interface, device->alternate); return -EINVAL; } dbg_init(2, "endpoints: %d", interface->bNumEndpoints); // iterate across all endpoints for this configuration and verify they are valid for (i = 0; i < interface->bNumEndpoints; i++) { int transfersize; int physical_endpoint; int logical_endpoint; //dbg_init(0, "fetching endpoint %d", i); if (!(endpoint_descriptor = usbd_device_endpoint_descriptor_index(device, 0, device->configuration, device->interface, device->alternate, i))) { dbg_init(0, "cannot fetch endpoint descriptor: %d", i); continue; } // XXX check this transfersize = usbd_device_endpoint_transfersize(device, 0, device->configuration, device->interface, device->alternate, i); logical_endpoint = endpoint_descriptor->bEndpointAddress; if (!(physical_endpoint = udc_check_ep(logical_endpoint, endpoint_descriptor->wMaxPacketSize, device))) { dbg_init(2, "endpoint[%d]: l: %02x p: %02x transferSize: %d packetSize: %02x INVALID", i, logical_endpoint, physical_endpoint, transfersize, endpoint_descriptor->wMaxPacketSize); dbg_init(2, "invalid endpoint: %d %d", logical_endpoint, physical_endpoint); return -EINVAL; } else { struct usb_endpoint_instance *endpoint = device->bus->endpoint_array + physical_endpoint; dbg_init(2, "endpoint[%d]: l: %02x p: %02x transferSize: %d packetSize: %02x FOUND", i, logical_endpoint, physical_endpoint, transfersize, endpoint_descriptor->wMaxPacketSize); dbg_init(2,"epd->bEndpointAddress=%d", endpoint_descriptor->bEndpointAddress); endpoint->endpoint_address = endpoint_descriptor->bEndpointAddress; if (endpoint_descriptor->wMaxPacketSize > 64) { dbg_init(0,"incompatible with endpoint size: %x", endpoint_descriptor->wMaxPacketSize); return -EINVAL; } if (endpoint_descriptor->bEndpointAddress & IN) { found_tx++; endpoint->tx_attributes = endpoint_descriptor->bmAttributes; endpoint->tx_transferSize = transfersize&0xfff; endpoint->tx_packetSize = endpoint_descriptor->wMaxPacketSize; endpoint->last = 0; endpoint->tx_urb = NULL; } else { found_rx++; endpoint->rcv_attributes = endpoint_descriptor->bmAttributes; endpoint->rcv_transferSize = transfersize&0xfff; endpoint->rcv_packetSize = endpoint_descriptor->wMaxPacketSize; endpoint->rcv_urb = NULL; } } } if (device->status == USBD_OK) { for (i = 1; i < device->bus->driver->max_endpoints; i++) { struct usb_endpoint_instance *endpoint = device->bus->endpoint_array + i; // udc_setup_ep(device, i, endpoint->endpoint_address? endpoint : NULL); udc_setup_ep(device, i, endpoint); } } return 0; }
/* Handle general USB interrupts and dispatch according to type. * This function implements TRM Figure 14-13. */ void s3c2410_udc_irq(void) { struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array; u_int32_t save_idx = inl(S3C2410_UDC_INDEX_REG), idx2; /* read interrupt sources */ u_int32_t usb_status = inl(S3C2410_UDC_USB_INT_REG); u_int32_t usbd_status = inl(S3C2410_UDC_EP_INT_REG); u_int32_t pwr_reg = inl(S3C2410_UDC_PWR_REG); u_int32_t ep0csr = inl(S3C2410_UDC_IN_CSR1_REG); //debug("< IRQ usbs=0x%02x, usbds=0x%02x start >", usb_status, usbd_status); /* clear interrupts */ outl(usb_status, S3C2410_UDC_USB_INT_REG); if (usb_status & S3C2410_UDC_USBINT_RESET) { //serial_putc('R'); debug("RESET pwr=0x%x\n", inl(S3C2410_UDC_PWR_REG)); udc_setup_ep(udc_device, 0, ep0); outl(S3C2410_UDC_EP0_CSR_SSE|S3C2410_UDC_EP0_CSR_SOPKTRDY, S3C2410_UDC_EP0_CSR_REG); ep0->state = EP0_IDLE; usbd_device_event_irq (udc_device, DEVICE_RESET, 0); } if (usb_status & S3C2410_UDC_USBINT_RESUME) { debug("RESUME\n"); usbd_device_event_irq(udc_device, DEVICE_BUS_ACTIVITY, 0); } if (usb_status & S3C2410_UDC_USBINT_SUSPEND) { debug("SUSPEND\n"); usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); } /* Endpoint Interrupts */ if (usbd_status) { int i; if (usbd_status & S3C2410_UDC_INT_EP0) { outl(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG); s3c2410_udc_ep0(); } for (i = 1; i < 5; i++) { u_int32_t tmp = 1 << i; if (usbd_status & tmp) { /* FIXME: Handle EP X */ outl(tmp, S3C2410_UDC_EP_INT_REG); s3c2410_udc_epn(i); } } usbd_status = inl(S3C2410_UDC_EP_INT_REG); /* what else causes this interrupt? a receive! who is it? */ if (!usb_status && !usbd_status && !pwr_reg && !ep0csr) { debug("dual packet issue\n"); for (i = 1; i < 5; i++) { idx2 = inl(S3C2410_UDC_INDEX_REG); outl(i, S3C2410_UDC_INDEX_REG); if (inl(S3C2410_UDC_OUT_CSR1_REG) & 0x1) s3c2410_udc_epn(i); /* restore index */ outl(idx2, S3C2410_UDC_INDEX_REG); } } } S3C2410_UDC_SETIX(save_idx); }