📄 n9604.c
字号:
if (&req->req == _req) break; } if (&req->req != _req) { spin_unlock_irqrestore (&dev->lock, flags); return -EINVAL; } spin_unlock_irqrestore(&dev->lock, flags); return req ? 0 : -EOPNOTSUPP;}static int n9604_clear_halt(struct usb_ep *_ep) { struct n9604_ep *ep; ep = container_of (_ep, struct n9604_ep, ep); write_9604(read_9604(ep->control) & ~EPC_STALL, ep->control); pio_advance(ep); return 0;}static int n9604_set_halt(struct usb_ep *_ep, int value) { struct n9604_ep *ep; unsigned long flags; int retval = 0; if (!_ep) { retval = -ENODEV; goto exit; } ep = container_of (_ep, struct n9604_ep, ep); if (ep->num == 0) {//is this valid? if (!value) { retval = -EINVAL; goto exit; } /* don't change EPxSTATUS_EP_INVALID to READY */ } else if (!ep->desc) { retval = -EINVAL; goto exit; } spin_lock_irqsave(&ep->dev->lock, flags); if (!list_empty(&ep->queue)) retval = -EAGAIN; else if (!value) n9604_clear_halt(_ep); else { write_9604(read_9604(ep->control) | EPC_STALL, ep->control); } spin_unlock_irqrestore(&ep->dev->lock, flags);exit: return retval;}static int n9604_fifo_status(struct usb_ep *_ep) {//not implemented return -1;}static void n9604_fifo_flush(struct usb_ep *_ep) {//not implemented struct n9604_ep *ep; ep = container_of (_ep, struct n9604_ep, ep);}/*-------------------------------------------------------------------------*/static struct usb_ep_ops n9604_ep_ops = { .enable = n9604_ep_enable, .disable = n9604_ep_disable, .alloc_request = n9604_alloc_request,//io request objects called struct usb_request .free_request = n9604_free_request, .alloc_buffer = n9604_alloc_buffer, .free_buffer = n9604_free_buffer, .queue = n9604_queue,//submit a struct usb_request object to an endpoint .dequeue = n9604_dequeue, .set_halt = n9604_set_halt,//halts an endpoint .fifo_status = n9604_fifo_status,//bytes in FIFO + data ready to go in FIFO .fifo_flush = n9604_fifo_flush,//flush all the data, endpoint is probably been reconfigured};/*-------------------------------------------------------------------------*/static int n9604_get_frame(struct usb_gadget *_gadget){ return -EOPNOTSUPP;}static const struct usb_gadget_ops n9604_ops = { .get_frame = n9604_get_frame,};/*-------------------------------------------------------------------------*/static void udc_reinit (struct n9604_udc *dev){ static char *names [] = { "ep0", "ep1in", "ep2out", "ep3in", "ep4out", "ep5in", "ep6out" }; unsigned i; INIT_LIST_HEAD (&dev->gadget.ep_list); dev->gadget.ep0 = &dev->ep [0].ep; dev->gadget.speed = USB_SPEED_UNKNOWN; dev->irqs = 0; dev->configured = 0; //for (i = 0; i < 7; i++) { for (i = 0; i < ARRAY_SIZE(names); i++) { struct n9604_ep *ep = &dev->ep[i]; ep->num = i; ep->numActual = i; ep->ep.name = names[i]; ep->irqs = 0; if (i) { ep->fifo = (i * 4) + RXD0; //each FIFO address is 4 bytes away. TXD0 is the first ep->control = ep->fifo - 1; ep->status = ep->fifo + 1; ep->command = ep->fifo + 2; Flush(ep->command);//flush any data in the fifo//we don't care about the previous state read_9604(ep->status); ep->ep.maxpacket = MAX_FIFO_SIZE; } else {//were are endpoint 0 ep->fifo = ep->control = ep->status = ep->command = 0xff;//this should force an error //we need to do this since we don't know if //this is tx or rx read_9604(TXS0); Flush(TXC0); Flush(RXC0);//we could potentially (probably) overwriting a pending setup packet if (ep->stage)//if we get a setup packet before we have a chance to finish the reset we have a problem read_9604(RXS0);//fix this by sending stalls or something ep->stage = 0; ep->ep.maxpacket = MAX_EP0_SIZE; } ep->is_in = i % 2; ep->fifoNum = (i + ep->is_in) / 2;//ignored for endpoint 0 ep->ep.ops = &n9604_ep_ops; list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); ep->dev = dev; INIT_LIST_HEAD (&ep->queue); ep->nuking=0; ep->queue_reqs = 0; ep->queue_active = 0; ep->packets = 0; ep->desc = 0; ep->irqs = 0; } list_del_init (&dev->ep[0].ep.ep_list); write_9604(~WKUP_PNDUSB & ~WKUP_PNDUC & read_9604(WKUP), WKUP);//clear the bits, we've done a reset write_9604(FAR_AD_EN, FAR);//enable the chip to answer requests//address 0 dev->address = 0; write_9604(0, EPC0);//clear the control register write_9604(NFSR_NodeOperational, NFSR);//we're going for gold}static void udc_reset(struct n9604_udc *dev){ //USBD_DISABLE_IRQ; This disables all interrupts sharing that line write_9604(MCNTRL_SRST,MCNTRL);//software reset -- this also prevents pullup write_9604(0x00, MAMSK); //disable interrupts}static void udc_enable(struct n9604_udc *dev){ udc_reset(dev); //this is to prevent a pullup resistor udc_reinit (dev); dev->gadget.speed = USB_SPEED_FULL; // enable ep0 interrupts dev->ep[0].is_in = 0; write_9604(MAMSK_WARN | MAMSK_ALT | MAMSK_TX_EV | MAMSK_RX_EV | MAMSK_INTR, MAMSK);//for now we turn it all on, except frames & ULD & NAK write_9604(ALTMSK_RESET, ALTMSK);//just turn on reset write_9604(0x11, TXMSK); write_9604(0x11, RXMSK); write_9604(0x0, NAKMSK); write_9604(0x0, FWMSK); write_9604(MCNTRL_NAT | MCNTRL_INTOC_ActHigh, MCNTRL);//this activates the pull-up and turns on interrupts USBD_ENABLE_IRQ;}/*-------------------------------------------------------------------------*//* keeping it simple: * - one bus driver, initted first; * - one function driver, initted second */static struct n9604_udc *the_controller;/* when a driver is successfully registered, it will receive * control requests including set_configuration(), which enables * non-control requests. then usb traffic follows until a * disconnect is reported. then a host may connect again, or * the driver might get unbound. */int usb_gadget_register_driver(struct usb_gadget_driver *driver){ struct n9604_udc *dev = the_controller; int retval; if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; if (!dev) return -ENODEV; if (dev->driver) return -EBUSY; /* hook up the driver */ dev->driver = driver; retval = driver->bind(&dev->gadget); if (retval) { dev->driver = 0; return retval; } /* then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. */ udc_enable(dev); return 0;}EXPORT_SYMBOL(usb_gadget_register_driver);int usb_gadget_unregister_driver(struct usb_gadget_driver *driver){ struct n9604_udc *dev = the_controller; unsigned long flags; int i; if (!dev) return -ENODEV; if (!driver || driver != dev->driver) return -EINVAL; spin_lock_irqsave(&dev->lock, flags); dev->driver = 0; udc_reset(dev);//reset & diable irqs for (i = 0; i < ARRAY_SIZE(dev->ep); i++) nuke(&dev->ep [i], -ESHUTDOWN); spin_unlock_irqrestore(&dev->lock, flags); if (dev->gadget.speed != USB_SPEED_UNKNOWN) driver->disconnect(&dev->gadget); driver->unbind(&dev->gadget); return 0;}EXPORT_SYMBOL(usb_gadget_unregister_driver);/*-------------------------------------------------------------------------*/inline u8 tx_ev_irq(struct n9604_udc *dev) { u8 mask; mask = read_9604(TXEV) & read_9604(TXMSK); if (mask & TXEV_FIFO0) { write_9604(0, EPC0);//make sure we are not stalled, & not using the default address read_9604(TXS0);//should really check for error conditions dev->ep[0].irqs++; pio_advance(&dev->ep[0]); } if (mask & TXEV_FIFO1) { read_9604(TXS1); dev->ep[1].irqs++; pio_advance(&dev->ep[1]); } if (mask & TXEV_FIFO2) { read_9604(TXS2); dev->ep[3].irqs++; pio_advance(&dev->ep[3]); } if (mask & TXEV_FIFO3) { read_9604(TXS3); dev->ep[5].irqs++; pio_advance(&dev->ep[5]); } return mask;}static void my_req_complete(struct usb_ep *_ep, struct usb_request *req) {//this was for the setup packet, but I guess I could use it for anything n9604_free_buffer(_ep, req->buf, req->dma, req->length); n9604_free_request(_ep, req);}inline void send_dummy_packet(int endpoint, struct n9604_udc *dev, int length) { struct usb_request *my_req; my_req = n9604_alloc_request(&dev->ep[endpoint].ep, GFP_ATOMIC); my_req->length = length; my_req->buf = n9604_alloc_buffer(&dev->ep[endpoint].ep, length, &my_req->dma, GFP_ATOMIC); my_req->complete = my_req_complete; n9604_queue(&dev->ep[endpoint].ep, my_req, GFP_ATOMIC);}inline void send_zero_length(int endpoint, struct n9604_udc *dev) { send_dummy_packet(endpoint, dev, 0);}inline void rx_ev_irq(struct n9604_udc *dev) { u8 mask; struct n9604_ep *ep; mask = read_9604(RXEV) & read_9604(RXMSK); if (mask & RXEV_FIFO0) { static int read_mode = 0; u8 rxs_mask = read_9604(RXS0); ep = &dev->ep[0]; ep->irqs++; if (rxs_mask & RXS_SETUP) { struct usb_ctrlrequest ctrl; ep->packets++; write_9604(0x40, ALTMSK);//someone is talking to us. Make sure we can be reset if we lose this communication ep->stage = 1; rxs_mask = read_9604(RXS0);//2nd read (1st one is for zero length packet) ctrl.bRequestType = read_9604(RXD0); ctrl.bRequest = read_9604(RXD0); ctrl.wValue = read_9604(RXD0) + (read_9604(RXD0) << 8); ctrl.wIndex = read_9604(RXD0) + (read_9604(RXD0) << 8); ctrl.wLength = read_9604(RXD0) + (read_9604(RXD0) << 8); ep->toggle = 1; request_voodoo = ctrl.wLength; if (ctrl.bRequestType & 0x80) {//This is an IN transaction ep->is_in = 1;//David: is this correct for both cases//check with n9604_queue read_mode = 0; if (ctrl.wLength) {//should be followed by ZLP out packet } else {//host expects ZLP out packet ep->stage = 2; } } else {//This is an out transaction if (ctrl.wLength) { ep->is_in = 0; read_mode = 1; } else {//host expects ZLP in packet read_mode = 0; ep->stage = 2; ep->is_in = 1; } } switch (ctrl.bRequest) { case USB_REQ_SET_ADDRESS: write_9604(EPC_DEF, EPC0);//we still want to respond to the default address write_9604(((dev->address = (ctrl.wValue & FAR_AD_MASK))) | FAR_AD_EN, FAR); send_zero_length(0, dev); dev->configured = 1;//we can send longer packets now :) read_9604(ALTEV); write_9604(ALTMSK_RESET, ALTMSK);//we also listen to reset requests too break; case USB_REQ_CLEAR_FEATURE: if (ctrl.wValue == 0 && ctrl.bRequestType == 2) {//endpoint halt int i; for (i = 0; i < ARRAY_SIZE(dev->ep); i++) if ((ctrl.wIndex & 0xF) == dev->ep[i].numActual) n9604_clear_halt(&dev->ep[i].ep); send_zero_length(0, dev); break; } case USB_REQ_SET_DESCRIPTOR: case USB_REQ_SYNCH_FRAME: case USB_REQ_GET_STATUS: case USB_REQ_SET_FEATURE: case USB_REQ_SET_CONFIGURATION: case USB_REQ_GET_DESCRIPTOR: case USB_REQ_GET_CONFIGURATION: case USB_REQ_SET_INTERFACE: case USB_REQ_GET_INTERFACE: default: if (dev->driver->setup(&dev->gadget, &ctrl) < 0)//there was an error if (((ctrl.bRequestType & 0x80) && ctrl.wLength) || (!(ctrl.bRequestType & 0x80) && !ctrl.wLength)) send_zero_length(0, dev); }//crtl.bRequest }//setup else if (read_mode) pio_advance(ep); else { ep->stage = 0; ep->packets++; } }//fifo 0 if (mask & RXEV_FIFO1) { ep = &dev->ep[2]; pio_advance(ep); ep->irqs++; } if (mask & RXEV_FIFO2) { ep = &dev->ep[4]; pio_advance(ep); ep->irqs++; } if (mask & RXEV_FIFO3) { ep = &dev->ep[6]; pio_advance(ep); ep->irqs++; }}inline void alt_ev_irq(struct n9604_udc *dev) { u8 mask; mask = read_9604(ALTEV) & read_9604(ALTMSK); if (mask & ALTEV_EOP); if (mask & ALTEV_SD3); if (mask & ALTEV_SD5); if (mask & ALTEV_RESET) { int i; udelay(1200);//no idea why this is needed, but it makes things work write_9604(0x0, FAR);//lets not respond to any packets until we are ready write_9604(NFSR_NodeReset, NFSR); dev->driver->disconnect(&dev->gadget); for (i = 0; i < ARRAY_SIZE(dev->ep); i++) nuke(&dev->ep [i], -ESHUTDOWN);//this should be handled above by disconnect write_9604(0x00, ALTMSK);//make sure reset is turned off, or we will constantly be interrupted write_9604(0x11, TXMSK); write_9604(0x11, RXMSK); udc_reinit(dev); dev->gadget.speed = USB_SPEED_FULL; dev->ep[0].is_in = 0; } if (mask & ALTEV_RESUME); //write_9604(NFSR_NodeOperational, NFSR); if (mask & ALTEV_WKUP);//we don't really sleep if (mask & ALTEV_DMA);}static void n9604_irq(int irq, void *_dev, struct pt_regs *r) { struct n9604_udc *dev = _dev; u8 mask; mask = read_9604(MAEV) & read_9604(MAMSK); if (!mask) return; if (mask & MAEV_ALT) { alt_ev_irq(dev); mask = read_9604(MAEV) & read_9604(MAMSK);//force a re-read of the current pending interrupts } if (mask & MAEV_TX_EV) tx_ev_irq(dev); if (mask & MAEV_RX_EV) rx_ev_irq(dev); dev->irqs++; return;}/*-------------------------------------------------------------------------*/static int __init init (void){ struct n9604_udc *dev; int ret; u8 * addr; if (the_controller) return -EBUSY; addr = ioremap(USBN9604_PHYS, 0x2);//ioremap will bump this to 1 page size if (!addr) { ERROR(dev, KERN_ERR "Unable to remap address\n"); return -EINVAL; } USBN9604_Offset = addr; if ((read_9604(RID) & 0xF) != 0x2) { //0x2 is the identifier for 9603/4 iounmap(addr); return -ENODEV; } /* alloc, and start init */ dev = kmalloc(sizeof *dev, SLAB_KERNEL); if (dev == NULL){ WARN(dev, "No memory"); iounmap(addr); return -ENOMEM; } memset(dev, 0, sizeof *dev); spin_lock_init(&dev->lock); dev->gadget.ops = &n9604_ops; dev->gadget.is_dualspeed = 0; /* the "gadget" abstracts/virtualizes the controller */ dev->gadget.dev.bus_id = "gadget"; dev->gadget.name = driver_name; /* initialize the hardware */ udc_reset(dev); write_9604(CCONF_CODIS | 11, CCONF); udc_reinit(dev);//this is necessary as it sets up the epx functions the_controller = dev; if ((ret=request_irq(IRQ_GPIOC, n9604_irq, SA_SHIRQ, driver_name,dev))) { WARN(dev, "Can't get IRQ\n"); iounmap(addr); return ret; } return 0;}module_init (init);static void __exit cleanup (void){ struct n9604_udc *dev = the_controller; //first kill the interrupts udc_reset(dev); free_irq(IRQ_GPIOC, dev); /* start with the driver above us */ if (dev->driver) { /* should have been done already by driver model core */ WARN(dev, "Warning: Driver '%s' is still registered\n", dev->driver->driver.name); usb_gadget_unregister_driver(dev->driver); } kfree(dev); iounmap(USBN9604_Offset); the_controller = 0;}module_exit (cleanup);MODULE_PARM_DESC (delayTime, "Delays after reads and writes to the USB chip");MODULE_PARM (delayTime, "i");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -