////
/* USB High Spped 2.0 Device (Gadget) */
#ifdef CONFIG_PLAT_S3C24XX
static struct resource s3c_hsudc_resource[] = {
[0] = DEFINE_RES_MEM(S3C2416_PA_HSUDC, S3C2416_SZ_HSUDC),
[1] = DEFINE_RES_IRQ(IRQ_USBD),
};
struct platform_device s3c_device_usb_hsudc = {
.name = "s3c-hsudc",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_hsudc_resource),
.resource = s3c_hsudc_resource,
.dev = {
.dma_mask = &samsung_device_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd)
{
s3c_set_platdata(pd, sizeof(*pd), &s3c_device_usb_hsudc);
}
#endif /* CONFIG_PLAT_S3C24XX */
/////////
static void __init smdk2416_machine_init(void)---->
s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata);
platform_add_devices(smdk2416_devices, ARRAY_SIZE(smdk2416_devices));
static struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
.epnum = 9,
.gpio_init = smdk2416_hsudc_gpio_init,
.gpio_uninit = smdk2416_hsudc_gpio_uninit,
};
static void smdk2416_hsudc_gpio_init(void)
{
s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE);
s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1));
s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0);
}
static struct platform_device *smdk2416_devices[] __initdata = {
&s3c_device_fb,
&s3c_device_wdt,
&s3c_device_ohci,
&s3c_device_i2c0,
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
&s3c_device_usb_hsudc,
&s3c2443_device_dma,
};
/////////////////////////////////////////////////////////////////////////////////
MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver");
static struct platform_driver s3c_hsudc_driver = {
.driver = {
.name = "s3c-hsudc",
},
.probe = s3c_hsudc_probe,
};
module_platform_driver(s3c_hsudc_driver);
//////////////////////////
/**
* struct s3c_hsudc - Driver's abstraction of the device controller.
* @gadget: Instance of usb_gadget which is referenced by gadget driver.
* @driver: Reference to currenty active gadget driver.
* @dev: The device reference used by probe function.
* @lock: Lock to synchronize the usage of Endpoints (EP's are indexed).
* @regs: Remapped base address of controller's register space.
* irq: IRQ number used by the controller.
* uclk: Reference to the controller clock.
* ep0state: Current state of EP0.
* ep: List of endpoints supported by the controller.
*/
struct s3c_hsudc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct device *dev;
struct s3c24xx_hsudc_platdata *pd;
struct usb_phy *transceiver;
struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
spinlock_t lock;
void __iomem *regs;
int irq;
struct clk *uclk;
int ep0state;
struct s3c_hsudc_ep ep[]; //端点
};
///////////////////////////////////////////////
//很重要
static int s3c_hsudc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct s3c_hsudc *hsudc;
struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev);
int ret, i;
hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
sizeof(struct s3c_hsudc_ep) * pd->epnum,
GFP_KERNEL);
if (!hsudc)
return -ENOMEM;
platform_set_drvdata(pdev, dev);
hsudc->dev = dev;
hsudc->pd = dev_get_platdata(&pdev->dev);
hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
hsudc->supplies);
if (ret != 0) {
dev_err(dev, "failed to request supplies: %d\n", ret);
goto err_supplies;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hsudc->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hsudc->regs)) {
ret = PTR_ERR(hsudc->regs);
goto err_res;
}
spin_lock_init(&hsudc->lock);
hsudc->gadget.max_speed = USB_SPEED_HIGH;
//OPS操作集合
hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
hsudc->gadget.name = dev_name(dev);
hsudc->gadget.ep0 = &hsudc->ep[0].ep;
hsudc->gadget.is_otg = 0;
hsudc->gadget.is_a_peripheral = 0;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
s3c_hsudc_setup_ep(hsudc);
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(dev, "unable to obtain IRQ number\n");
goto err_res;
}
hsudc->irq = ret;
//很重要
//这个申请的中断函数是用来接收数据的。
//这里申请的中断处理函数是 s3c_hsudc_irq,这是这个驱动的核心,该USB device驱动的正常工作都围绕它展开。
ret = devm_request_irq(&pdev->dev, hsudc->irq, s3c_hsudc_irq, 0,
driver_name, hsudc);
if (ret < 0) {
dev_err(dev, "irq request failed\n");
goto err_res;
}
hsudc->uclk = devm_clk_get(&pdev->dev, "usb-device");
if (IS_ERR(hsudc->uclk)) {
dev_err(dev, "failed to find usb-device clock source\n");
ret = PTR_ERR(hsudc->uclk);
goto err_res;
}
clk_enable(hsudc->uclk);
local_irq_disable();
disable_irq(hsudc->irq);
local_irq_enable();
//usb_add_gadget_udc - adds a new gadget to the udc class driver list
//hsudc->gadget可以认为是USB设备控制器
ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
if (ret)
goto err_add_udc;
pm_runtime_enable(dev);
return 0;
err_add_udc:
clk_disable(hsudc->uclk);
err_res:
if (!IS_ERR_OR_NULL(hsudc->transceiver))
usb_put_phy(hsudc->transceiver);
err_supplies:
return ret;
}
///////////////////////////////////////////////////////
物理层的核心
/**
* s3c_hsudc_irq - Interrupt handler for device controller.
* @irq: Not used.
* @_dev: Reference to the device controller.
*
* Interrupt handler for the device controller. This handler handles controller
* interrupts and endpoint interrupts.
*/
//接收到数据处理的函数
//次函数即为 linux板子作为usb从设备时的irq中断接收usb数据的开始函数
static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
{
struct s3c_hsudc *hsudc = _dev;
struct s3c_hsudc_ep *hsep;
u32 ep_intr;
u32 sys_status;
u32 ep_idx;
spin_lock(&hsudc->lock);
//读System Status寄存器
sys_status = readl(hsudc->regs + S3C_SSR);
//读EP Intr Status寄存器
ep_intr = readl(hsudc->regs + S3C_EIR) & 0x3FF;
if (!ep_intr && !(sys_status & S3C_SSR_DTZIEN_EN)) {
spin_unlock(&hsudc->lock);
return IRQ_HANDLED;
}
if (sys_status) {
if (sys_status & S3C_SSR_VBUSON)
writel(S3C_SSR_VBUSON, hsudc->regs + S3C_SSR);
if (sys_status & S3C_SSR_ERR)
writel(S3C_SSR_ERR, hsudc->regs + S3C_SSR);
if (sys_status & S3C_SSR_SDE) {
writel(S3C_SSR_SDE, hsudc->regs + S3C_SSR);
hsudc->gadget.speed = (sys_status & S3C_SSR_HSP) ?
USB_SPEED_HIGH : USB_SPEED_FULL;
}
if (sys_status & S3C_SSR_SUSPEND) {
writel(S3C_SSR_SUSPEND, hsudc->regs + S3C_SSR);
if (hsudc->gadget.speed != USB_SPEED_UNKNOWN
&& hsudc->driver && hsudc->driver->suspend)
hsudc->driver->suspend(&hsudc->gadget);
}
if (sys_status & S3C_SSR_RESUME) {
writel(S3C_SSR_RESUME, hsudc->regs + S3C_SSR);
if (hsudc->gadget.speed != USB_SPEED_UNKNOWN
&& hsudc->driver && hsudc->driver->resume)
hsudc->driver->resume(&hsudc->gadget);
}
if (sys_status & S3C_SSR_RESET) {
writel(S3C_SSR_RESET, hsudc->regs + S3C_SSR);
for (ep_idx = 0; ep_idx < hsudc->pd->epnum; ep_idx++) {
hsep = &hsudc->ep[ep_idx];
hsep->stopped = 1;
s3c_hsudc_nuke_ep(hsep, -ECONNRESET);
}
s3c_hsudc_reconfig(hsudc);
hsudc->ep0state = WAIT_FOR_SETUP;
}
}
if (ep_intr & S3C_EIR_EP0) {
writel(S3C_EIR_EP0, hsudc->regs + S3C_EIR);
set_index(hsudc, 0);
//此处应该是端点0有数据 Handle endpoint 0 interrupt
//EP0 interrupt could occur when a stall handshake is sent to host
//or data is sent/received on endpoint 0
s3c_hsudc_handle_ep0_intr(hsudc);
}
ep_intr >>= 1;
ep_idx = 1;
while (ep_intr) {
if (ep_intr & 1) {
hsep = &hsudc->ep[ep_idx];
set_index(hsudc, ep_idx);
writel(1 << ep_idx, hsudc->regs + S3C_EIR);
if (ep_is_in(hsep))
s3c_hsudc_epin_intr(hsudc, ep_idx);
else
s3c_hsudc_epout_intr(hsudc, ep_idx);
}
ep_intr >>= 1;
ep_idx++;
}
spin_unlock(&hsudc->lock);
return IRQ_HANDLED;
}
//////////////////////////////////
/** s3c_hsudc_handle_ep0_intr - Handle endpoint 0 interrupt.
* @hsudc: Device controller on which endpoint 0 interrupt has occured.
*
* Handle endpoint 0 interrupt when it occurs. EP0 interrupt could occur
* when a stall handshake is sent to host or data is sent/received on
* endpoint 0.
*/
static void s3c_hsudc_handle_ep0_intr(struct s3c_hsudc *hsudc)
{
struct s3c_hsudc_ep *hsep = &hsudc->ep[0];
struct s3c_hsudc_req *hsreq;
//读EP0 Status寄存器
u32 csr = readl(hsudc->regs + S3C_EP0SR);
u32 ecr;
if (csr & S3C_EP0SR_STALL) {
ecr = readl(hsudc->regs + S3C_EP0CR);
ecr &= ~(S3C_ECR_STALL | S3C_ECR_FLUSH);
writel(ecr, hsudc->regs + S3C_EP0CR);
writel(S3C_EP0SR_STALL, hsudc->regs + S3C_EP0SR);
hsep->stopped = 0;
s3c_hsudc_nuke_ep(hsep, -ECONNABORTED);
hsudc->ep0state = WAIT_FOR_SETUP;
hsep->bEndpointAddress &= ~USB_DIR_IN;
return;
}
if (csr & S3C_EP0SR_TX_SUCCESS) {
writel(S3C_EP0SR_TX_SUCCESS, hsudc->regs + S3C_EP0SR);
if (ep_is_in(hsep)) {
if (list_empty(&hsep->queue))
return;
hsreq = list_entry(hsep->queue.next,
struct s3c_hsudc_req, queue);
s3c_hsudc_write_fifo(hsep, hsreq);
}
}
//端点0接收到数据
if (csr & S3C_EP0SR_RX_SUCCESS) {
//属于SETUP建立令牌包,SETUP令牌包只用在控制传输中,USB设备的枚举过程都使用控制传输模式,保证数据正确性。
if (hsudc->ep0state == WAIT_FOR_SETUP)
s3c_hsudc_process_setup(hsudc);
else {
if (!ep_is_in(hsep)) {
if (list_empty(&hsep->queue))
return;
hsreq = list_entry(hsep->queue.next,
struct s3c_hsudc_req, queue);
s3c_hsudc_read_fifo(hsep, hsreq);
}
}
}
}
////////////////////////////////////////
/**
* s3c_hsudc_process_setup - Process control request received on endpoint 0.
* @hsudc: Device controller on which control request has been received.
*
* Read the control request received on endpoint 0, decode it and handle
* the request.
*/
//USB建立令牌包,枚举过程,可以细看,按照USB协议来看是如何握手
static void s3c_hsudc_process_setup(struct s3c_hsudc *hsudc)
{
struct s3c_hsudc_ep *hsep = &hsudc->ep[0];
struct usb_ctrlrequest ctrl = {0};
int ret;
s3c_hsudc_nuke_ep(hsep, -EPROTO);
s3c_hsudc_read_setup_pkt(hsudc, (u16 *)&ctrl);
if (ctrl.bRequestType & USB_DIR_IN) {
hsep->bEndpointAddress |= USB_DIR_IN;
hsudc->ep0state = DATA_STATE_XMIT;
} else {
hsep->bEndpointAddress &= ~USB_DIR_IN;
hsudc->ep0state = DATA_STATE_RECV;
}
switch (ctrl.bRequest) {
case USB_REQ_SET_ADDRESS:
if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
break;
hsudc->ep0state = WAIT_FOR_SETUP;
return;
case USB_REQ_GET_STATUS:
if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
break;
s3c_hsudc_process_req_status(hsudc, &ctrl);
return;
case USB_REQ_SET_FEATURE:
case USB_REQ_CLEAR_FEATURE:
if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
break;
s3c_hsudc_handle_reqfeat(hsudc, &ctrl);
hsudc->ep0state = WAIT_FOR_SETUP;
return;
}
if (hsudc->driver) {
spin_unlock(&hsudc->lock);
ret = hsudc->driver->setup(&hsudc->gadget, &ctrl);
spin_lock(&hsudc->lock);
if (ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
hsep->bEndpointAddress &= ~USB_DIR_IN;
hsudc->ep0state = WAIT_FOR_SETUP;
}
if (ret < 0) {
dev_err(hsudc->dev, "setup failed, returned %d\n",
ret);
s3c_hsudc_set_halt(&hsep->ep, 1);
hsudc->ep0state = WAIT_FOR_SETUP;
hsep->bEndpointAddress &= ~USB_DIR_IN;
}
}
}
///////////////////////////////////////////////////////////////////
//usb操作
static const struct usb_gadget_ops s3c_hsudc_gadget_ops = {
.get_frame = s3c_hsudc_gadget_getframe,
.udc_start = s3c_hsudc_start,
.udc_stop = s3c_hsudc_stop,
.vbus_draw = s3c_hsudc_vbus_draw,
};
///////////////////////////////////////////////////////////////////
阅读(1369) | 评论(0) | 转发(0) |