/* * This function is called when the SRP timer expires. The SRP should * complete within 6 seconds. */ static void s3c_udc_srp_timeout(unsigned long _ptr ) { struct s3c_udc *dev = the_controller; struct timer_list *srp_timer = &dev->srp_timer; u32 usb_otgctl; DEBUG_SETUP("[%s] SRP Timeout \n", __func__); /* Currently (2009.6.22) OTG not supported Originally GOTGINT.SesReqSucStsChng interrupt handler should read GOTGCTL.SesReqScs ref. Synopsis Spec. 5.3.2.2 OTG Interrupt Register(GOTGINT) */ usb_otgctl = readl(S3C_UDC_OTG_GOTGCTL); if (usb_otgctl & B_SESSION_VALID && usb_otgctl & SESSION_REQ_SUCCESS) { DEBUG_SETUP("[%s] SRP Success \n", __func__); spin_unlock(&dev->lock); dev->driver->resume(&dev->gadget); spin_lock(&dev->lock); del_timer(srp_timer); } else { DEBUG_SETUP("[%s] Device not connected/responding \n", __func__); } usb_otgctl &= ~SESSION_REQ; writel(usb_otgctl, S3C_UDC_OTG_GOTGCTL); }
/* * until it becomes enabled, this UDC should be completely invisible * to any USB host. */ static int udc_enable(struct s3c_udc *dev) { u32 uTemp; DEBUG_SETUP("%s: %p\n", __FUNCTION__, dev); uTemp = readl(S3C_OTHERS); uTemp |= (1<<16); // USB_SIG_MASK writel(uTemp, S3C_OTHERS); // 1. Initializes OTG Phy. writel(0x0, S3C_USBOTG_PHYPWR); // writel(0x20, S3C_USBOTG_PHYCLK); writel(0x02, S3C_USBOTG_PHYCLK); /* 2010-0208, modified by CVKK(JC) */ writel(0x1, S3C_USBOTG_RSTCON); udelay(50); writel(0x0, S3C_USBOTG_RSTCON); udelay(50); dev->udc_state = USB_STATE_POWERED; dev->gadget.speed = USB_SPEED_UNKNOWN; reconfig_usbd(dev); DEBUG_SETUP("S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n", readl(S3C_UDC_OTG_GINTMSK)); return 0; }
/* until it's enabled, this UDC should be completely invisible * to any USB host. */ static int udc_enable(struct s3c_udc *dev) { DEBUG_SETUP("%s: %p\n", __FUNCTION__, dev); /* if reset by sleep wakeup, control the retention I/O cell */ if (__raw_readl(S3C_RSTSTAT) & 0x8) __raw_writel(__raw_readl(S3C_RSTCON)|(1<<16), S3C_RSTCON); /* USB Port is Normal mode */ __raw_writel(__raw_readl(S3C2410_MISCCR)&~(1<<12), S3C2410_MISCCR); /* PHY power enable */ __raw_writel(__raw_readl(S3C_PWRCFG)|(1<<4), S3C_PWRCFG); /* USB device 2.0 must reset like bellow, * 1st phy reset and after at least 10us, func_reset & host reset * phy reset can reset bellow registers. */ /* PHY 2.0 S/W reset */ __raw_writel((0<<2)|(0<<1)|(1<<0), S3C_URSTCON); udelay(20); /* phy reset must be asserted for at 10us */ /*Function 2.0, Host 1.1 S/W reset*/ __raw_writel((1<<2)|(1<<1)|(0<<0), S3C_URSTCON); __raw_writel((0<<2)|(0<<1)|(0<<0), S3C_URSTCON); /* 48Mhz,Crystal,External X-tal,device */ __raw_writel((0<<3)|(0<<2)|(1<<1)|(0<<0), S3C_PHYCTRL); /* 48Mhz clock on ,PHY2.0 analog block power on * XO block power on,XO block power in suspend mode, * PHY 2.0 Pll power on ,suspend signal for save mode disable */ __raw_writel((1<<31)|(0<<4)|(0<<3)|(0<<2)|(0<<1)|(0<<0), S3C_PHYPWR); /* D+ pull up disable(VBUS detect), USB2.0 Function clock Enable, * USB1.1 HOST disable, USB2.0 PHY test enable */ __raw_writel((0<<31)|(1<<2)|(0<<1)|(1<<0), S3C_UCLKCON); __raw_writel(IRQ_USBD, S3C2410_INTPND); __raw_writel(IRQ_USBD, S3C2410_SRCPND); reconfig_usbd(); __raw_writel(__raw_readl(S3C2410_INTMSK)&~(IRQ_USBD), S3C2410_INTMSK); /* D+ pull up , USB2.0 Function clock Enable, * USB1.1 HOST disable,USB2.0 PHY test enable */ __raw_writel((1<<31)|(1<<2)|(0<<1)|(1<<0), S3C_UCLKCON); DEBUG_SETUP("S3C2443 USB Controller Core Initialized\n"); dev->gadget.speed = USB_SPEED_UNKNOWN; return 0; }
/* * Unregister entry point for the peripheral controller driver. */ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { struct s3c_udc *dev = the_controller; unsigned long flags; if (!dev) return -ENODEV; if (!driver || driver != dev->driver) return -EINVAL; disable_irq(IRQ_OTG); spin_lock_irqsave(&dev->lock, flags); s3c_udc_stop_activity(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); driver->unbind(&dev->gadget); device_del(&dev->gadget.dev); DEBUG_SETUP("Unregistered gadget driver '%s'\n", driver->driver.name); #ifndef CONFIG_PM s3c_udc_disable(dev); #endif dev->gadget.dev.driver = NULL; dev->driver = NULL; dev->config_gadget_driver = NO_GADGET_DRIVER; return 0; }
/* * s3c_ep_list_reinit - initialize software state */ static void s3c_ep_list_reinit(struct s3c_udc *dev) { u8 i; DEBUG_SETUP("%s: %p\n", __func__, dev); /* device/ep0 records init */ INIT_LIST_HEAD(&dev->gadget.ep_list); INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); dev->ep0state = WAIT_FOR_SETUP; /* basic endpoint records init */ for (i = 0; i < S3C_MAX_ENDPOINTS; i++) { struct s3c_ep *ep = &dev->ep[i]; if (i != 0) list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); ep->desc = 0; ep->stopped = 0; ep->pio_irqs = 0; INIT_LIST_HEAD(&ep->queue); } /* the rest was statically initialized, and is read-only */ }
/* * udc_disable - disable USB device controller */ static void udc_disable(struct s3c_udc *dev) { DEBUG_SETUP("%s: %p\n", __FUNCTION__, dev); udc_set_address(dev, 0); dev->ep0state = WAIT_FOR_SETUP; dev->gadget.speed = USB_SPEED_UNKNOWN; dev->usb_address = 0; /* usb power disable */ #if defined(CONFIG_CPU_S3C2450) || defined(CONFIG_CPU_S3C2416) s3c2410_gpio_pullup(S3C2443_GPH14, 1); /* pull-down enable */ s3c2410_gpio_pullup(S3C2410_GPF2, 1); /* pull-down enable */ #else s3c2410_gpio_pullup(S3C2443_GPH14, 2); /* pull-down enable */ #endif s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP); s3c2410_gpio_setpin(S3C2443_GPH14, 0); /* usb clock disable */ __raw_writel(0, S3C_UCLKCON); /* USB Port is Suspend mode */ __raw_writel(__raw_readl(S3C2410_MISCCR)|(1<<12), S3C2410_MISCCR); /* PHY power disable */ __raw_writel(__raw_readl(S3C_PWRCFG)&~(1<<4), S3C_PWRCFG); }
/* * udc_disable - disable USB device controller */ static void udc_disable(struct s3c_udc *dev) { DEBUG_SETUP("%s: %p\n", __FUNCTION__, dev); udc_set_address(dev, 0); dev->ep0state = WAIT_FOR_SETUP; dev->gadget.speed = USB_SPEED_UNKNOWN; dev->usb_address = 0; __raw_writel(__raw_readl(S3C_PWRCFG)&~(1<<4), S3C_PWRCFG); }
/* * udc_disable - disable USB device controller */ static void udc_disable(struct s3c_udc *dev) { DEBUG_SETUP("%s: %p\n", __FUNCTION__, dev); udc_set_address(dev, 0); dev->ep0state = WAIT_FOR_SETUP; dev->gadget.speed = USB_SPEED_UNKNOWN; dev->usb_address = 0; //writel(readl(S3C_USBOTG_PHYPWR)|(0x7<<1), S3C_USBOTG_PHYPWR); otg_phy_init(0x42); /* 2010-0208, added by CVKK(JC) */ dev->udc_state = USB_STATE_NOTATTACHED; }
/* * until it becomes enabled, this UDC should be completely invisible * to any USB host. */ static int s3c_udc_enable(struct s3c_udc *dev) { u32 reg_val; DEBUG_SETUP("%s: %p\n", __func__, dev); #if USING_MACH_OTG_PHY otg_phy_init(); #else writel(1, S5P_USB_PHY_CONTROL); writel(0xa0, S3C_USBOTG_PHYPWR); /* Power up */ writel(OTGH_PHY_CLK_VALUE, S3C_USBOTG_PHYCLK); writel(0x1, S3C_USBOTG_RSTCON); udelay(50); writel(0x0, S3C_USBOTG_RSTCON); udelay(50); #endif dev->udc_state = USB_STATE_POWERED; dev->gadget.speed = USB_SPEED_UNKNOWN; /* 14. Initialize OTG Link Core. */ writel(GAHBCFG_INIT, S3C_UDC_OTG_GAHBCFG); writel( 0<<15 // PHY Low Power Clock sel |1<<14 // Non-Periodic TxFIFO Rewind Enable |0x5<<10 // Turnaround time |0<<9|0<<8 // [0:HNP disable, 1:HNP enable][ 0:SRP disable, 1:SRP enable] H1= 1,1 |0<<7 // Ulpi DDR sel |0<<6 // 0: high speed utmi+, 1: full speed serial |0<<4 // 0: utmi+, 1:ulpi |1<<3 // phy i/f 0:8bit, 1:16bit |0x7<<0, // HS/FS Timeout* S3C_UDC_OTG_GUSBCFG); s3c_udc_initialize(dev); //change proper register instead of S3C_UDC_OTG_GINTMSK reg_val = readl(S3C_UDC_OTG_GINTMSK); if(!reg_val) { DEBUG_ERROR("[%s] Fail to set GINTMSK 0x%x\n", __func__, reg_val); return -1; } return 0; }
/* * until it becomes enabled, this UDC should be completely invisible * to any USB host. */ static int s3c_udc_enable(struct s3c_udc *dev) { u32 reg_val; DEBUG_SETUP("%s: %p\n", __func__, dev); reg_val = readl(S3C_OTHERS); reg_val |= (1<<16); // USB_SIG_MASK writel(reg_val, S3C_OTHERS); // 1. Initializes OTG Phy. writel(0x0, S3C_USBOTG_PHYPWR); writel(0x20, S3C_USBOTG_PHYCLK); writel(0x1, S3C_USBOTG_RSTCON); // confirm delay time with thinking pm logic udelay(50); writel(0x0, S3C_USBOTG_RSTCON); udelay(50); dev->udc_state = USB_STATE_POWERED; dev->gadget.speed = USB_SPEED_UNKNOWN; /* 14. Initialize OTG Link Core. */ writel(GAHBCFG_INIT, S3C_UDC_OTG_GAHBCFG); writel( 0<<15 // PHY Low Power Clock sel |1<<14 // Non-Periodic TxFIFO Rewind Enable |0x5<<10 // Turnaround time |0<<9|0<<8 // [0:HNP disable, 1:HNP enable][ 0:SRP disable, 1:SRP enable] H1= 1,1 |0<<7 // Ulpi DDR sel |0<<6 // 0: high speed utmi+, 1: full speed serial |0<<4 // 0: utmi+, 1:ulpi |1<<3 // phy i/f 0:8bit, 1:16bit |0x7<<0, // HS/FS Timeout* S3C_UDC_OTG_GUSBCFG); s3c_udc_initialize(dev); //change proper register instead of S3C_UDC_OTG_GINTMSK reg_val = readl(S3C_UDC_OTG_GINTMSK); if(!reg_val) { DEBUG_ERROR("[%s] Fail to set GINTMSK 0x%x\n", __func__, reg_val); return -1; } return 0; }
/* Register entry point for the peripheral controller driver. */ int usb_gadget_register_driver(struct usb_gadget_driver *driver) { struct s3c_udc *dev = the_controller; int retval; DEBUG_SETUP("%s: %s\n", __FUNCTION__, driver->driver.name); if (!driver || (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH) || !driver->bind || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; if (!dev) return -ENODEV; if (dev->driver) return -EBUSY; /* first hook up the driver ... */ dev->driver = driver; dev->gadget.dev.driver = &driver->driver; retval = device_add(&dev->gadget.dev); if(retval) { /* TODO */ printk("target device_add failed, error %d\n", retval); return retval; } retval = driver->bind(&dev->gadget); if (retval) { printk("%s: bind to driver %s --> error %d\n", dev->gadget.name, driver->driver.name, retval); device_del(&dev->gadget.dev); dev->driver = 0; dev->gadget.dev.driver = 0; return retval; } enable_irq(IRQ_USBD); printk("Registered gadget driver '%s'\n", driver->driver.name); udc_enable(dev); return 0; }
/* * elfin usb client interrupt handler. */ static irqreturn_t s3c_udc_irq(int irq, void *_dev) { struct s3c_udc *dev = _dev; u32 intr_status; u32 usb_status, ep_ctrl, gintmsk; spin_lock(&dev->lock); intr_status = readl(S3C_UDC_OTG_GINTSTS); gintmsk = readl(S3C_UDC_OTG_GINTMSK); DEBUG_ISR("\n**** %s : GINTSTS=0x%x(on state %s), GINTMSK : 0x%x\n", __FUNCTION__, intr_status, state_names[dev->ep0state], gintmsk); if (!intr_status) { spin_unlock(&dev->lock); return IRQ_HANDLED; } if (intr_status & INT_ENUMDONE) { DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s: Speed Detection interrupt\n", __FUNCTION__); writel(INT_ENUMDONE, S3C_UDC_OTG_GINTSTS); usb_status = (readl(S3C_UDC_OTG_DSTS) & 0x6); if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) { DEBUG_SETUP(" %s: Full Speed Detection\n",__FUNCTION__); set_max_pktsize(dev, USB_SPEED_FULL); } else { DEBUG_SETUP(" %s: High Speed Detection : 0x%x\n", __FUNCTION__, usb_status); set_max_pktsize(dev, USB_SPEED_HIGH); } } if (intr_status & INT_EARLY_SUSPEND) { DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s:Early suspend interrupt\n", __FUNCTION__); writel(INT_EARLY_SUSPEND, S3C_UDC_OTG_GINTSTS); } if (intr_status & INT_SUSPEND) { usb_status = readl(S3C_UDC_OTG_DSTS); DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s:Suspend interrupt :(DSTS):0x%x\n", __FUNCTION__, usb_status); writel(INT_SUSPEND, S3C_UDC_OTG_GINTSTS); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->suspend) { dev->driver->suspend(&dev->gadget); } } if (intr_status & INT_RESUME) { DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s: Resume interrupt\n", __FUNCTION__); writel(INT_RESUME, S3C_UDC_OTG_GINTSTS); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->resume) { dev->driver->resume(&dev->gadget); } } if (intr_status & INT_RESET) { usb_status = readl(S3C_UDC_OTG_GOTGCTL); DEBUG_SETUP("####################################\n"); DEBUG_SETUP(" %s: Reset interrupt - (GOTGCTL):0x%x\n", __FUNCTION__, usb_status); writel(INT_RESET, S3C_UDC_OTG_GINTSTS); if((usb_status & 0xc0000) == (0x3 << 18)) { if(reset_available) { DEBUG_SETUP(" ===> OTG core got reset (%d)!! \n", reset_available); reconfig_usbd(); dev->ep0state = WAIT_FOR_SETUP; reset_available = 0; } } else { reset_available = 1; DEBUG_SETUP(" RESET handling skipped : reset_available : %d\n", reset_available); } } if (intr_status & INT_RX_FIFO_NOT_EMPTY) { u32 grx_status, packet_status, ep_num, fifoCntByte = 0; /* Mask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ gintmsk &= ~INT_RX_FIFO_NOT_EMPTY; writel(gintmsk, S3C_UDC_OTG_GINTMSK); grx_status = readl(S3C_UDC_OTG_GRXSTSR); DEBUG_ISR(" INT_RX_FIFO_NOT_EMPTY(GRXSTSR):0x%x, GINTMSK:0x%x\n", grx_status, gintmsk); packet_status = grx_status & 0x1E0000; fifoCntByte = (grx_status & 0x7ff0)>>4; ep_num = grx_status & EP_MASK; if (fifoCntByte) { if (packet_status == SETUP_PKT_RECEIVED) { DEBUG_EP0(" => A SETUP data packet received : %d bytes\n", fifoCntByte); s3c_handle_ep0(dev); /* Unmask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ gintmsk |= INT_RX_FIFO_NOT_EMPTY; } else if (packet_status == OUT_PKT_RECEIVED) { if(ep_num == EP1_OUT) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL1); DEBUG_ISR(" => A Bulk OUT data packet received : %d bytes, (DOEPCTL1):0x%x\n", fifoCntByte, ep_ctrl); s3c_out_epn(dev, 1); gintmsk = readl(S3C_UDC_OTG_GINTMSK); writel(ep_ctrl | DEPCTL_CNAK, S3C_UDC_OTG_DOEPCTL1); } else if (ep_num == EP0_CON) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL0); DEBUG_EP0(" => A CONTROL OUT data packet received : %d bytes, (DOEPCTL0):0x%x\n", fifoCntByte, ep_ctrl); dev->ep0state = DATA_STATE_RECV; s3c_ep0_read(dev); gintmsk |= INT_RX_FIFO_NOT_EMPTY; } else { DEBUG_ISR(" => Unused EP: %d bytes, (GRXSTSR):0x%x\n", fifoCntByte, grx_status); } } else { grx_status = readl(S3C_UDC_OTG_GRXSTSP); /* Unmask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ gintmsk |= INT_RX_FIFO_NOT_EMPTY; DEBUG_ISR(" => A reserved packet received : %d bytes\n", fifoCntByte); } } else { if (dev->ep0state == DATA_STATE_XMIT) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL0); DEBUG_EP0(" => Write ep0 continue... (DOEPCTL0):0x%x\n", ep_ctrl); s3c_ep0_write(dev); } if (packet_status == SETUP_TRANSACTION_COMPLETED) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL0); DEBUG_EP0(" => A SETUP transaction completed (DOEPCTL0):0x%x\n", ep_ctrl); writel(ep_ctrl | DEPCTL_CNAK, S3C_UDC_OTG_DOEPCTL0); } else if (packet_status == OUT_TRANSFER_COMPLELTED) { if (ep_num == EP1_OUT) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL1); DEBUG_ISR(" => An OUT transaction completed (DOEPCTL1):0x%x\n", ep_ctrl); writel(ep_ctrl | DEPCTL_CNAK, S3C_UDC_OTG_DOEPCTL1); } else if (ep_num == EP0_CON) { ep_ctrl = readl(S3C_UDC_OTG_DOEPCTL0); DEBUG_ISR(" => An OUT transaction completed (DOEPCTL0):0x%x\n", ep_ctrl); writel(ep_ctrl | DEPCTL_CNAK, S3C_UDC_OTG_DOEPCTL0); } else { DEBUG_ISR(" => Unused EP: %d bytes, (GRXSTSR):0x%x\n", fifoCntByte, grx_status); } } else if (packet_status == OUT_PKT_RECEIVED) { DEBUG_ISR(" => A OUT PACKET RECEIVED (NO FIFO CNT BYTE)...(GRXSTSR):0x%x\n", grx_status); } else { DEBUG_ISR(" => A RESERVED PACKET RECEIVED (NO FIFO CNT BYTE)...(GRXSTSR):0x%x\n", grx_status); } grx_status = readl(S3C_UDC_OTG_GRXSTSP); /* Unmask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ gintmsk |= INT_RX_FIFO_NOT_EMPTY; } /* Un/Mask USB OTG 2.0 interrupt sources */ writel(gintmsk, S3C_UDC_OTG_GINTMSK); spin_unlock(&dev->lock); return IRQ_HANDLED; }
/* * usb_gadget_ops wake-up * This function starts the Protocol if no session is in progress. If * a session is already in progress, but the device is suspended, * remote wakeup signaling is started. */ static int s3c_udc_wakeup(struct usb_gadget *_gadget) { struct s3c_udc *dev = the_controller; struct timer_list *srp_timer = &dev->srp_timer; u32 usb_otgctl, usb_dctl, usb_status; unsigned long flags; int ret = -EINVAL; if (!_gadget) { return -ENODEV; } DEBUG("[%s]: %s\n", __func__, _gadget->name); spin_lock_irqsave(&dev->lock, flags); if (!(dev->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))) { DEBUG_ERROR("[%s]Not set USB_DEVICE_REMOTE_WAKEUP \n", __func__); goto s3c_udc_wakeup_exit; } /* Check if valid session */ usb_otgctl = readl(S3C_UDC_OTG_GOTGCTL); if (usb_otgctl & B_SESSION_VALID) { /* Check if suspend state */ usb_status = readl(S3C_UDC_OTG_DSTS); if (usb_status & (1<<SUSPEND_STS)) { //sending remote wake up signaling DEBUG("[%s]Set Remote Wakeup \n", __func__); usb_dctl = readl(S3C_UDC_OTG_DCTL); usb_dctl |= REMOTE_WAKEUP_SIG; writel(usb_dctl, S3C_UDC_OTG_DCTL); mdelay(1); DEBUG_SETUP("[%s]Clear Remote Wakeup \n", __func__); usb_dctl = readl(S3C_UDC_OTG_DCTL); usb_dctl = usb_dctl & ~REMOTE_WAKEUP_SIG; writel(usb_dctl, S3C_UDC_OTG_DCTL); } else DEBUG_SETUP("[%s] Already woked up \n", __func__); } else if (usb_otgctl & SESSION_REQ) { DEBUG_SETUP("[%s] Session Request Already active! \n", __func__); goto s3c_udc_wakeup_exit; } else { DEBUG_SETUP("[%s] Initiate Session Request \n", __func__); //The core clears this bit when the HstNegSucStsChng bit is cleared. usb_otgctl |= SESSION_REQ; writel(usb_otgctl, S3C_UDC_OTG_GOTGCTL); /* Start the SRP timer */ init_timer(srp_timer); srp_timer->function = (void*)s3c_udc_srp_timeout; srp_timer->expires = jiffies + (HZ*6); add_timer(srp_timer); } ret = 0; s3c_udc_wakeup_exit: spin_unlock_irqrestore(&dev->lock, flags); return ret; }
/* * usb_gadget_register_driver * Register entry point for the peripheral controller driver. */ int usb_gadget_register_driver(struct usb_gadget_driver *driver) { struct s3c_udc *dev = the_controller; int retval; DEBUG_SETUP("%s: %s\n", __func__, driver->driver.name); #if 1 /* adb composite fail to !driver->unbind in composite.c as below static struct usb_gadget_driver composite_driver = { .speed = USB_SPEED_HIGH, .bind = composite_bind, .unbind = __exit_p(composite_unbind), */ if (!driver || (driver->speed < USB_SPEED_FULL) || !driver->bind || !driver->disconnect || !driver->setup) return -EINVAL; #else if (!driver || (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH) || !driver->bind || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; #endif if (!dev) return -ENODEV; if (dev->driver) return -EBUSY; /* first hook up the driver ... */ dev->devstatus = 1 << USB_DEVICE_SELF_POWERED; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; retval = device_add(&dev->gadget.dev); if(retval) { /* TODO */ DEBUG_ERROR("target device_add failed, error %d\n", retval); return retval; } retval = driver->bind(&dev->gadget); if (retval) { DEBUG_ERROR("%s: bind to driver %s --> error %d\n", dev->gadget.name, driver->driver.name, retval); device_del(&dev->gadget.dev); dev->driver = 0; dev->gadget.dev.driver = 0; return retval; } enable_irq(IRQ_OTG); DEBUG_SETUP("Registered gadget driver '%s'\n", driver->driver.name); #ifndef CONFIG_PM s3c_udc_enable(dev); #endif /* in case of rndis, will be chaned at the time of SET_CONFIGURATION */ if (strcmp(driver->driver.name, "g_ether") == 0) dev->config_gadget_driver = ETHER_CDC; else if (strcmp(driver->driver.name, "android_adb") == 0) dev->config_gadget_driver = ANDROID_ADB; else if (strcmp(driver->driver.name, "android_usb") == 0) dev->config_gadget_driver = ANDROID_ADB_UMS; else if (strcmp(driver->driver.name, "android_adb_ums_acm") == 0) dev->config_gadget_driver = ANDROID_ADB_UMS_ACM; else if (strcmp(driver->driver.name, "g_serial") == 0) dev->config_gadget_driver = SERIAL; else if (strcmp(driver->driver.name, "g_cdc") == 0) dev->config_gadget_driver = CDC2; else if (strcmp(driver->driver.name, "g_file_storage") == 0) dev->config_gadget_driver = FILE_STORAGE; else DEBUG_ERROR("Not recognized driver's name '%s'\n", driver->driver.name); return 0; }