⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c2410_udc.c

📁 S3C2410 USBD驱动程序 s3c2410_udc
💻 C
📖 第 1 页 / 共 4 页
字号:
   .pullup         = s3c2410_udc_pullup,
   .vbus_session      = s3c2410_udc_vbus_session,
   .vbus_draw      = s3c2410_vbus_draw,
};

/*------------------------- gadget driver handling---------------------------*/
/*
 * s3c2410_udc_disable
 */
static void s3c2410_udc_disable(struct s3c2410_udc *dev)
{
   dprintk(DEBUG_NORMAL, "%s()\n", __func__);

   /* Disable all interrupts */
   udc_write(0x00, S3C2410_UDC_USB_INT_EN_REG);
  udc_write(0x00, S3C2410_UDC_EP_INT_EN_REG);

   /* Clear the interrupt registers */
   udc_write(S3C2410_UDC_USBINT_RESET
           | S3C2410_UDC_USBINT_RESUME
            | S3C2410_UDC_USBINT_SUSPEND,
         S3C2410_UDC_USB_INT_REG);

  udc_write(0x1F, S3C2410_UDC_EP_INT_REG);

   /* Good bye, cruel world */
  if (udc_info && udc_info->udc_command)
      udc_info->udc_command(S3C2410_UDC_P_DISABLE);

   /* Set speed to unknown */
   dev->gadget.speed = USB_SPEED_UNKNOWN;
}

/*
 * s3c2410_udc_reinit
 */
static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
{
   u32 i;

  /* device/ep0 records init */
   INIT_LIST_HEAD (&dev->gadget.ep_list);
   INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
   dev->ep0state = EP0_IDLE;
   for (i = 0; i < S3C2410_ENDPOINTS; i++) {
      struct s3c2410_ep *ep = &dev->ep[i];

      if (i != 0)
        list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);

     ep->dev = dev;
      ep->desc = NULL;
      ep->halted = 0;
      INIT_LIST_HEAD (&ep->queue);
   }
}

/*
 * s3c2410_udc_enable
 */
static void s3c2410_udc_enable(struct s3c2410_udc *dev)
{
   int i;
   dprintk(DEBUG_NORMAL, "s3c2410_udc_enable called\n");

   /* dev->gadget.speed = USB_SPEED_UNKNOWN; */
   dev->gadget.speed = USB_SPEED_FULL;
   /* Set MAXP for all endpoints */
   for (i = 0; i < S3C2410_ENDPOINTS; i++) {
      udc_write(i, S3C2410_UDC_INDEX_REG);
     udc_write((dev->ep[i].ep.maxpacket & 0x7ff) >> 3,
            S3C2410_UDC_MAXP_REG);
   }

  /* Set default power state */
   udc_write(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG);

   /* Enable reset and suspend interrupt interrupts */
   udc_write(S3C2410_UDC_USBINT_RESET | S3C2410_UDC_USBINT_SUSPEND,
        S3C2410_UDC_USB_INT_EN_REG);

   /* Enable ep0 interrupt */
   udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG);

  /* time to say "hello, world" */
   if (udc_info && udc_info->udc_command)
      udc_info->udc_command(S3C2410_UDC_P_ENABLE);
}

/*
 *   usb_gadget_register_driver
 */
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
   struct s3c2410_udc *udc = the_controller;
   int      retval;

   dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n",
      driver->driver.name);
   /* Sanity checks */
   if (!udc)
      return -ENODEV;

  if (udc->driver)
      return -EBUSY;

   if (!driver->bind || !driver->setup
         || driver->speed != USB_SPEED_FULL) {
      printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
         driver->bind, driver->setup, driver->speed);
      return -EINVAL;
   }
#if defined(MODULE)
   if (!driver->unbind) {
      printk(KERN_ERR "Invalid driver: no unbind method\n");
      return -EINVAL;
   }
#endif

   /* Hook the driver */
   udc->driver = driver;
   udc->gadget.dev.driver = &driver->driver;

   /* Bind the driver */
   if ((retval = device_add(&udc->gadget.dev)) != 0) {
      printk(KERN_ERR "Error in device_add() : %d\n",retval);
      goto register_error;
   }

   dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n",
      driver->driver.name);

   if ((retval = driver->bind (&udc->gadget)) != 0) {
      device_del(&udc->gadget.dev);
      goto register_error;
  }

   /* Enable udc */
   s3c2410_udc_enable(udc);
   return 0;

register_error:
   udc->driver = NULL;
   udc->gadget.dev.driver = NULL;
   return retval;
}

/*
 *   usb_gadget_unregister_driver
 */
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
   struct s3c2410_udc *udc = the_controller;

   if (!udc)
     return -ENODEV;

   if (!driver || driver != udc->driver || !driver->unbind)
      return -EINVAL;

   dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n",
      driver->driver.name);

   if (driver->disconnect)
     driver->disconnect(&udc->gadget);

   device_del(&udc->gadget.dev);
   udc->driver = NULL;

   /* Disable udc */
   s3c2410_udc_disable(udc);
   return 0;
}

/*---------------------------------------------------------------------------*/
static struct s3c2410_udc memory = {
   .gadget = {
      .ops      = &s3c2410_ops,
      .ep0      = &memory.ep[0].ep,
      .name      = gadget_name,
      .dev = {
        .bus_id      = "gadget",
      },
   },
   /* control endpoint */
   .ep[0] = {
      .num      = 0,
      .ep = {
         .name      = ep0name,
        .ops      = &s3c2410_ep_ops,
         .maxpacket   = EP0_FIFO_SIZE,
      },
     .dev      = &memory,
   },

  /* first group of endpoints */
   .ep[1] = {
     .num      = 1,
      .ep = {
         .name      = "ep1-bulk",
         .ops      = &s3c2410_ep_ops,
        .maxpacket   = EP_FIFO_SIZE,
      },
      .dev      = &memory,
     .fifo_size   = EP_FIFO_SIZE,
      .bEndpointAddress = 1,
      .bmAttributes   = USB_ENDPOINT_XFER_BULK,
   },
   .ep[2] = {
      .num      = 2,
     .ep = {
         .name      = "ep2-bulk",
         .ops      = &s3c2410_ep_ops,
        .maxpacket   = EP_FIFO_SIZE,
      },
      .dev      = &memory,
     .fifo_size   = EP_FIFO_SIZE,
      .bEndpointAddress = 2,
      .bmAttributes   = USB_ENDPOINT_XFER_BULK,
   },
  .ep[3] = {
      .num      = 3,
      .ep = {
         .name      = "ep3-bulk",
        .ops      = &s3c2410_ep_ops,
         .maxpacket   = EP_FIFO_SIZE,
      },
      .dev      = &memory,
     .fifo_size   = EP_FIFO_SIZE,
      .bEndpointAddress = 3,
      .bmAttributes   = USB_ENDPOINT_XFER_BULK,
  },
   .ep[4] = {
      .num      = 4,
      .ep = {
        .name      = "ep4-bulk",
         .ops      = &s3c2410_ep_ops,
        .maxpacket   = EP_FIFO_SIZE,
      },
      .dev      = &memory,
      .fifo_size   = EP_FIFO_SIZE,
     .bEndpointAddress = 4,
      .bmAttributes   = USB_ENDPOINT_XFER_BULK,
  }

};

/*
 *   probe - binds to the platform device
 */
static int s3c2410_udc_probe(struct platform_device *pdev)
{
   struct s3c2410_udc *udc = &memory;
   struct device *dev = &pdev->dev;
   int retval;
   unsigned int irq;

   dev_dbg(dev, "%s()\n", __func__);

   usb_bus_clock = clk_get(NULL, "usb-bus-gadget");
   if (IS_ERR(usb_bus_clock)) {
      dev_err(dev, "failed to get usb bus clock source\n");
      return PTR_ERR(usb_bus_clock);
   }

   clk_enable(usb_bus_clock);
   udc_clock = clk_get(NULL, "usb-device");
   if (IS_ERR(udc_clock)) {
      dev_err(dev, "failed to get udc clock source\n");
      return PTR_ERR(udc_clock);
   }

   clk_enable(udc_clock);
   mdelay(10);

   dev_dbg(dev, "got and enabled clocks\n");

  if (strncmp(pdev->name, "s3c2440", 7) == 0) {
      dev_info(dev, "S3C2440: increasing FIFO to 128 bytes\n");
      memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE;
      memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE;
     memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE;
      memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE;
   }
   spin_lock_init (&udc->lock);
   udc_info = pdev->dev.platform_data;

   rsrc_start = S3C2410_PA_USBDEV;
   rsrc_len   = S3C24XX_SZ_USBDEV;

   if (!request_mem_region(rsrc_start, rsrc_len, gadget_name))
     return -EBUSY;

   base_addr = ioremap(rsrc_start, rsrc_len);
   if (!base_addr) {
      retval = -ENOMEM;
     goto err_mem;
   }

   device_initialize(&udc->gadget.dev);
   udc->gadget.dev.parent = &pdev->dev;
   udc->gadget.dev.dma_mask = pdev->dev.dma_mask;

   the_controller = udc;
   platform_set_drvdata(pdev, udc);

   s3c2410_udc_disable(udc);
   s3c2410_udc_reinit(udc);

   /* irq setup after old hardware state is cleaned up */
   retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
         IRQF_DISABLED, gadget_name, udc);

   if (retval != 0) {
     dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval);
      retval = -EBUSY;
      goto err_map;
   }
   dev_dbg(dev, "got irq %i\n", IRQ_USBD);

   if (udc_info && udc_info->vbus_pin > 0) {
      irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
      retval = request_irq(irq, s3c2410_udc_vbus_irq,
           IRQF_DISABLED | IRQF_TRIGGER_RISING
            | IRQF_TRIGGER_FALLING,
            gadget_name, udc);

     if (retval != 0) {
         dev_err(dev, "can't get vbus irq %i, err %d\n",
            irq, retval);
         retval = -EBUSY;
        goto err_int;
      }

      dev_dbg(dev, "got irq %i\n", irq);
   } else {
     udc->vbus = 1;
   }

  if (s3c2410_udc_debugfs_root) {
      udc->regs_info = debugfs_create_file("registers", S_IRUGO,
            s3c2410_udc_debugfs_root,
           udc, &s3c2410_udc_debugfs_fops);
      if (IS_ERR(udc->regs_info)) {
        dev_warn(dev, "debugfs file creation failed %ld\n",
             PTR_ERR(udc->regs_info));
        udc->regs_info = NULL;
     }
   }
   dev_dbg(dev, "probe ok\n");

  return 0;
err_int:
   free_irq(IRQ_USBD, udc);
err_map:
   iounmap(base_addr);
err_mem:
   release_mem_region(rsrc_start, rsrc_len);

   return retval;
}

/*
 *   s3c2410_udc_remove
 */
static int s3c2410_udc_remove(struct platform_device *pdev)
{
   struct s3c2410_udc *udc = platform_get_drvdata(pdev);
   unsigned int irq;

   dev_dbg(&pdev->dev, "%s()\n", __func__);
   if (udc->driver)
      return -EBUSY;

   debugfs_remove(udc->regs_info);

   if (udc_info && udc_info->vbus_pin > 0) {
      irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
      free_irq(irq, udc);
   }

   free_irq(IRQ_USBD, udc);

   iounmap(base_addr);
   release_mem_region(rsrc_start, rsrc_len);

   platform_set_drvdata(pdev, NULL);

   if (!IS_ERR(udc_clock) && udc_clock != NULL) {
      clk_disable(udc_clock);
      clk_put(udc_clock);
      udc_clock = NULL;
    }

   if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) {
      clk_disable(usb_bus_clock);
      clk_put(usb_bus_clock);
      usb_bus_clock = NULL;
   }

   dev_dbg(&pdev->dev, "%s: remove ok\n", __func__);
   return 0;
}

#ifdef CONFIG_PM
static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
{
   if (udc_info && udc_info->udc_command)
      udc_info->udc_command(S3C2410_UDC_P_DISABLE);

   return 0;
}

static int s3c2410_udc_resume(struct platform_device *pdev)
{
   if (udc_info && udc_info->udc_command)
      udc_info->udc_command(S3C2410_UDC_P_ENABLE);

   return 0;
}
#else
#define s3c2410_udc_suspend   NULL
#define s3c2410_udc_resume   NULL
#endif

static struct platform_driver udc_driver_2410 = {
   .driver      = {
      .name   = "s3c2410-usbgadget",
      .owner   = THIS_MODULE,
   },
   .probe      = s3c2410_udc_probe,
   .remove      = s3c2410_udc_remove,
   .suspend   = s3c2410_udc_suspend,
   .resume      = s3c2410_udc_resume,
};

static struct platform_driver udc_driver_2440 = {
   .driver      = {
      .name   = "s3c2440-usbgadget",
      .owner   = THIS_MODULE,
   },
   .probe      = s3c2410_udc_probe,
   .remove      = s3c2410_udc_remove,
   .suspend   = s3c2410_udc_suspend,
   .resume      = s3c2410_udc_resume,
};

static int __init udc_init(void)
{
   int retval;

   dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);

   s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
   if (IS_ERR(s3c2410_udc_debugfs_root)) {
      printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
         gadget_name, PTR_ERR(s3c2410_udc_debugfs_root));
      s3c2410_udc_debugfs_root = NULL;
   }

   retval = platform_driver_register(&udc_driver_2410);
   if (retval)
      goto err;

   retval = platform_driver_register(&udc_driver_2440);
   if (retval)
      goto err;

   return 0;

err:
   debugfs_remove(s3c2410_udc_debugfs_root);
   return retval;
}

static void __exit udc_exit(void)
{
   platform_driver_unregister(&udc_driver_2410);
   platform_driver_unregister(&udc_driver_2440);
   debugfs_remove(s3c2410_udc_debugfs_root);
}

EXPORT_SYMBOL(usb_gadget_unregister_driver);
EXPORT_SYMBOL(usb_gadget_register_driver);

module_init(udc_init);
module_exit(udc_exit);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -