📄 wmmx.c
字号:
udcisr0 = UDCISR0; udcisr1 = UDCISR1 & 0xffff; while (udcisr0 || udcisr1) { u32 udccsr0 = UDCCSR0; WMMX_IRO(udcisr0, "------------------------> Interrupt"); /* For Endpoint0, Endpoint A-P */ for (ep = 0; udcisr0 != 0 && ep < 16 ; udcisr0 >>= 2, ep++) { if (udcisr0 & UDC_INT_PACKETCMP) { switch (ep_maps[ep].eptype) { case ep_control: wmmx_ep0(phys_ep_to_endpoints[0], udccsr0); break; case ep_bulk_in: case ep_interrupt: if (wmmx_usb_dma_configs[ep].dma_enabled) { wmmx_ep_reset_interrupt_status(ep); break; } wmmx_in_n(ep, phys_ep_to_endpoints[ep]); break; case ep_bulk_out: if (wmmx_usb_dma_configs[ep].dma_enabled) { wmmx_ep_reset_interrupt_status(ep); break; } while (UDCCSN(ep) & UDCCSR_PC) { wmmx_out_n(ep, phys_ep_to_endpoints[ep]); } break; case ep_iso_in: case ep_iso_out: wmmx_ep_reset_interrupt_status(ep); break; } } if (udcisr0 & UDC_INT_FIFOERROR) { printk("FIFO error on %d endpoint\n", ep); } } /* For Endpoint Q-X */ for ( ; udcisr1 != 0 && ep < 24; udcisr1 >>= 2, ep++) { /* I will rebuild ep_maps array */ if (udcisr1 & UDC_INT_PACKETCMP) { switch (ep_maps[ep].eptype) { case ep_bulk_in: case ep_interrupt: wmmx_in_n(ep, phys_ep_to_endpoints[ep]); break; case ep_bulk_out: while (UDCCSN(ep) & UDCCSR_PC) { wmmx_out_n(ep, phys_ep_to_endpoints[ep]); } break; case ep_iso_in: case ep_iso_out: wmmx_ep_reset_interrupt_status(ep); break; default: break; } } } udcisr0 = UDCISR0; udcisr1 = UDCISR1 & 0xffff; } /* Reset, Suspend, Resume interrupts */ udcisr1 = UDCISR1; /* UDC Reset */ if (udcisr1 & UDCISR1_IERS) { WMMX_CCR(udccr, "------------------------> Reset"); udc_suspended = 0; usbd_device_event (udc_device, DEVICE_RESET, 0); usbd_device_event (udc_device, DEVICE_ADDRESS_ASSIGNED, 0); UDCISR1 = UDCISR1_IERS; } /* UDC Resume */ if (udcisr1 & UDCISR1_IERU) { WMMX_CCR(udccr, "------------------------> Resume"); if (udc_suspended) { udc_suspended = 0; usbd_device_event (udc_device, DEVICE_BUS_ACTIVITY, 0); } UDCISR1 = UDCISR1_IERU; } /* UDC Suspend */ if (udcisr1 & UDCISR1_IESU) { WMMX_CCR(udccr, "------------------------> Suspend"); if (!udc_suspended) { udc_suspended = 1; usbd_device_event (udc_device, DEVICE_BUS_INACTIVE, 0); } UDCISR1 = UDCISR1_IESU; } /* Configuration Change Interrupt */ if (udcisr1 & UDCISR1_IECC) { WMMX_CCR(udccr, "------------------------> Configuration " "Changed"); UDCCR |= UDCCR_SMAC; udc_device->configuration = (UDCCR & UDCCR_ACN) >> UDCCR_ACN_S; udc_device->interface = (UDCCR & UDCCR_AIN) >> UDCCR_AIN_S; udc_device->alternate = (UDCCR & UDCCR_AAISN) >> UDCCR_AAISN_S; usbd_device_event(udc_device, DEVICE_CONFIGURED, 0); UDCISR1 = UDCISR1_IECC; } WMMX_CCR(UDCCR, "<-- Interrupt");}/* * Setting the endpoint configuration register */static int udc_set_endpoint(struct usb_endpoint_description* endpoint, int configuration, int interface, int alternate, int eps, int accum_size){ u32 config_reg; static int phys_endpoints = 0; phys_endpoints ++; config_reg = ((configuration << UDCCONR_CN_S) & UDCCONR_CN) | ((interface << UDCCONR_IN_S) & UDCCONR_IN) | ((alternate << UDCCONR_AISN_S) & UDCCONR_AISN) | ((eps << UDCCONR_EN_S) & UDCCONR_EN); logic_to_phys_eps[configuration][endpoint->bEndpointAddress & 0xf] = phys_endpoints; /* Double Buffering Enabled and Enable the EP */ config_reg |= UDCCONR_EE | UDCCONR_DE; if (endpoint->direction == IN) { config_reg |= UDCCONR_ED; /* Direction: IN */ } else { config_reg &= ~UDCCONR_ED; /* Direction: OUT*/ } config_reg |= ((endpoint->bmAttributes << UDCCONR_ET_S) & UDCCONR_ET) | ((endpoint->wMaxPacketSize << UDCCONR_MPS_S) & UDCCONR_MPS); UDCCN(phys_endpoints) = config_reg; ep_maps[phys_endpoints].logical = endpoint->bEndpointAddress; ep_maps[phys_endpoints].eptype = (((config_reg & UDCCONR_ET) >> UDCCONR_ET_S) << 1) | !!(config_reg & UDCCONR_ED); ep_maps[phys_endpoints].size = endpoint->wMaxPacketSize; ep_maps[phys_endpoints].accum_size = accum_size; return 0;}/* * Check the function driver and set UDC Endpoint A-X Configuration Registers */static int udc_check_function(struct usb_function_instance* function){ int total = 1; int i,j,k,m; struct usb_configuration_description* configuration; struct usb_interface_description* interface; struct usb_alternate_description* alternate; struct usb_endpoint_description* endpoint; if (function->function_driver->configurations > MAX_LOGICAL_CONFIGURATIONS) { printk(KERN_ERR"Too many configurations.\n"); return -1; } for (i = 0; i < function->function_driver->configurations; i++) { configuration = function->function_driver->configuration_description + i; for (j = 0; j < configuration->interfaces; j++) { int logical_endpoints = 1; interface = configuration->interface_list + j; for (k = 0; k < interface->alternates; k++) { alternate = interface->alternate_list + k; for (m = 0; m < alternate->endpoints; m++) { if (alternate->endpoints > MAX_LOGICAL_ENDPOINTS) { printk(KERN_ERR "Too many logical endpoints.\n"); return -1; } endpoint = alternate->endpoint_list + m; if (udc_set_endpoint(endpoint, i+1, j, k, logical_endpoints++, (interface->bInterfaceClass == USB_CLASS_MASS_STORAGE) ? WMMX_STORAGE_ACCUM_SIZE : 0) < 0) { printk(KERN_ERR "udc_set_endpoint() error.\n"); return -1; } total++; } } } } return total;}/* * Enable UDC configuration setting */static int udc_configuration_enable(struct usb_device_instance* device){ struct usb_function_instance* function; int count, i; count = i = 0; function = device->function_instance_array + i; if (!function) { printk(KERN_ERR"No valid function driver!\n"); return -1; } count = udc_check_function(function); if (count < 0) { printk(KERN_ERR"udc_check_function(...) failed.\n"); return -1; } return 0;}/* * Public Functions. *//* * udc_start_in_irq - start transmit * @eendpoint: endpoint instance * * Called by bus interface driver to see if we need to * start a data transmission. */void udc_start_in_irq (struct usb_endpoint_instance *endpoint){ int phys_ep = wmmx_logic_to_phys_ep(endpoint->endpoint_address & 0xf); if (endpoint->endpoint_address == 0) { struct urb* urb = endpoint->tx_urb; if (!urb) { printk(KERN_INFO "udc_start_in_irq() urb is NULL\n"); return; } wmmx_ep0xmit(endpoint, UDCCSR0); } else if (UDCCSN(phys_ep) & UDCCSR_FS) { if (wmmx_usb_dma_configs[phys_ep].dma_enabled) wmmx_start_n_dma(phys_ep, endpoint); else wmmx_start_n(phys_ep, endpoint); }}/* * udc_init - initialize * * Return non-zero if we cannot see device. */int udc_init (void){ int i; dbg_tx(6, "udc_init:\n"); udc_disable_interrupts (NULL); for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { memset(&wmmx_usb_dma_configs[i], 0, sizeof(struct wmmx_usb_dma_config)); } for (i = 0; i < 16; i++) { wmmx_dmach_to_configs[i] = NULL; } wmmx_usb_dma_next = wmmx_usb_dma_buffer = consistent_alloc(GFP_KERNEL, DMA_BUFFER_SIZE, &wmmx_usb_dma_phys_buffer); if (!wmmx_usb_dma_buffer) { printk(KERN_ERR"udc_init: consistent_alloc() failed\n"); return 1; } return 0;}/* * udc_start_in - start transmit * @eendpoint: endpoint instance * * Called by bus interface driver to see if we need to start * a data transmission. */void udc_start_in (struct usb_endpoint_instance *endpoint){ if (endpoint) { unsigned long flags; local_irq_save (flags); udc_start_in_irq(endpoint); local_irq_restore (flags); }}/* * udc_stall_ep - stall endpoint * @ep: physical endpoint * * Stall the endpoint. */void udc_stall_ep (unsigned int phys_ep){ dbg_usbe(5, "usc_stall_ep ep=%d\n", phys_ep); if (phys_ep < UDC_MAX_ENDPOINTS) { UDCCSN(phys_ep) |= UDCCSR_FST; }}/* * udc_reset_ep - reset endpoint * @ep: physical endpoint * reset the endpoint. * * returns : 0 if ok, -1 otherwise */void udc_reset_ep (unsigned int phys_ep){ if (phys_ep == 0) { UDCCSN(phys_ep) |= ((UDCCSN(phys_ep) & UDCCSR_DME) | UDCCSR_FEF); }}/* * udc_endpoint_halted - is endpoint halted * @ep: * * Return non-zero if endpoint is halted */int udc_endpoint_halted (unsigned int phys_ep){ return 0;}/* * udc_set_address - set the USB address for this device * @address: * * Called from control endpoint function after it decodes * a set address setup packet. */void udc_set_address (unsigned char address){}/* * udc_serial_init - set a serial number if available */int __init udc_serial_init (struct usb_bus_instance *bus){ return -EINVAL;}/* * udc_max_endpoints - max physical endpoints * * Return number of physical endpoints. */int udc_max_endpoints (void){ return UDC_MAX_ENDPOINTS;}/* * udc_check_ep - check logical endpoint * @lep: * * Return physical endpoint number to use for this logical * endpoint or zero if not valid. */int udc_check_ep(int logic_ep, int packetsize){ if (packetsize > 64) return 0; return wmmx_logic_to_phys_ep(logic_ep & 0x0f);}static int wmmx_usb_dma_init(unsigned int phys_ep, struct usb_endpoint_instance* endpoint){ wmmx_usb_dma_configs[phys_ep].ep = phys_ep; wmmx_usb_dma_configs[phys_ep].endpoint = endpoint; if (ep_maps[phys_ep].eptype == ep_bulk_in) { wmmx_usb_dma_configs[phys_ep].dma_channel = pxa_request_dma("WMMX DMA IN", 0, wmmx_usb_dma_tx_irq, &wmmx_usb_dma_configs[phys_ep]); if (wmmx_usb_dma_configs[phys_ep].dma_channel < 0) { printk(KERN_ERR "pxa_request_dma(WMMX DMA IN) " "failed %d\n", wmmx_usb_dma_configs[phys_ep].dma_channel); return 1; } if ((wmmx_usb_dma_next - wmmx_usb_dma_buffer) > DMA_BUFFER_SIZE) { printk(KERN_ERR"Out of memory\n"); return 1; } wmmx_usb_dma_configs[phys_ep].dma_buffer = wmmx_usb_dma_next; wmmx_usb_dma_configs[phys_ep].dma_phys_buffer = wmmx_usb_dma_phys_buffer + (wmmx_usb_dma_next - wmmx_usb_dma_buffer); wmmx_usb_dma_next = (void *)(((u32)wmmx_usb_dma_next + endpoint->tx_packetSize + 3) & ~3); wmmx_dmach_to_configs[wmmx_usb_dma_configs[phys_ep].dma_channel] = &wmmx_usb_dma_configs[phys_ep]; wmmx_usb_dma_configs[phys_ep].dma_enabled = 1; } else if (ep_maps[phys_ep].eptype == ep_bulk_out) { wmmx_usb_dma_configs[phys_ep].dma_channel = pxa_request_dma("WMMX DMA OUT", 0, wmmx_usb_dma_rx_irq, &wmmx_usb_dma_configs[phys_ep]); if (wmmx_usb_dma_configs[phys_ep].dma_channel < 0) { printk(KERN_ERR"pxa_request_dma(WMMX_DMA_OUT) failed %d\n", wmmx_usb_dma_configs[phys_ep].dma_channel); return 1; } wmmx_usb_dma_configs[phys_ep].dma_buffer = wmmx_usb_dma_next; wmmx_usb_dma_configs[phys_ep].dma_phys_buffer = wmmx_usb_dma_phys_buffer + (wmmx_usb_dma_next - wmmx_usb_dma_buffer); wmmx_usb_dma_next = (void *)(((u32)wmmx_usb_dma_next + endpoint->tx_packetSize + 3) & ~3); wmmx_dmach_to_configs[wmmx_usb_dma_configs[phys_ep].dma_channel] = &wmmx_usb_dma_configs[phys_ep]; wmmx_usb_dma_configs[phys_ep].dma_enabled = 1; } else { printk(KERN_ERR"wmmx_usb_dma_init(): invalid endpoint type.\n"); wmmx_usb_dma_configs[phys_ep].dma_enabled = 0; return 1; } return 0;}/* * udc_set_ep - setup endpoint * @ep: * @endpoint: * * Associate a physical endpoint with endpoint_instance */void udc_setup_ep (struct usb_device_instance *device, unsigned int phys_ep, struct usb_endpoint_instance *endpoint){ if (phys_ep < UDC_MAX_ENDPOINTS) { phys_ep_to_endpoints[phys_ep] = endpoint; if (phys_ep == 0) { printk(KERN_DEBUG "udc_setup_ep: 0 do nothing\n"); wmmx_enable_ep_interrupt(0, (UDC_INT_FIFOERROR | UDC_INT_PACKETCMP)); } else if (endpoint->endpoint_address & 0x80) { /* IN */ /* only support bulk in DMA mode now */ /* When you implement your function driver, you should decide whether the endpoint will use DMA mode or not */#ifdef CONFIG_USBD_WMMX_DMA_IN if ((ep_maps[phys_ep].eptype == ep_bulk_in) && (!wmmx_usb_dma_configs[phys_ep].dma_enabled)) { if (!wmmx_usb_dma_init(phys_ep, endpoint)) { UDCCSN(phys_ep) |= UDCCSR_DME; } }#endif /* if dma can't be initialized successfully, we enable the interrupt. */ if (!wmmx_usb_dma_configs[phys_ep].dma_enabled) { wmmx_enable_ep_interrupt(phys_ep, (UDC_INT_FIFOERROR | UDC_INT_PACKETCMP)); } } else if (endpoint->endpoint_address) { /* OUT */ usbd_fill_rcv (device, endpoint, 5); endpoint->rcv_urb = first_urb_detached(&endpoint->rdy); /* When you implement your function driver, you should decide whether the endpoint will use DMA mode or not */#ifdef CONFIG_USBD_WMMX_DMA_OUT if ((ep_maps[phys_ep].eptype == ep_bulk_out) && (!wmmx_usb_dma_configs[phys_ep].dma_enabled)) { if (!wmmx_usb_dma_init(phys_ep, endpoint)) { int channel;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -