📄 s3c2410_udc.c
字号:
struct s3c2410_ep *ep = &dev->ep [0];
struct s3c2410_request *req;
struct usb_ctrlrequest crq;
if (list_empty(&ep->queue))
req = NULL;
else
req = list_entry(ep->queue.next, struct s3c2410_request, queue);
udc_writel(0, S3C2410_UDC_INDEX_REG);
ep0csr = udc_readl(S3C2410_UDC_IN_CSR1_REG);
dprintk(DEBUG_NORMAL,"ep0csr %x ep0state %s\n",ep0csr,ep0states[dev->ep0state]);
/* clear stall status */
if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
/* FIXME */
nuke(dev, ep);
dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");
clear_ep0_sst(base_addr);
dev->ep0state = EP0_IDLE;
return;
}
/* clear setup end */
if (ep0csr & S3C2410_UDC_EP0_CSR_SE
/* && dev->ep0state != EP0_IDLE */) {
dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n");
nuke(dev, ep);
clear_ep0_se(base_addr);
dev->ep0state = EP0_IDLE;
}
switch (dev->ep0state) {
case EP0_IDLE:
/* start control request? */
if (ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) {
int len, ret, tmp;
nuke (dev, ep);
len = read_fifo_crq(&crq);
if (len != sizeof(crq)) {
dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR"
" wanted %d bytes got %d. Stalling out...\n",
sizeof(crq), len);
set_ep0_ss(base_addr);
return;
}
dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n", crq.bRequest,crq.bRequestType, crq.wLength);
/* cope with automagic for some standard requests. */
dev->req_std = (crq.bRequestType & USB_TYPE_MASK)
== USB_TYPE_STANDARD;
dev->req_config = 0;
dev->req_pending = 1;
switch (crq.bRequest) {
case USB_REQ_SET_CONFIGURATION: // 9
dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n");
if (crq.bRequestType == USB_RECIP_DEVICE) {
config_change:
dev->req_config = 1;
clear_ep_state(dev);
set_ep0_de_out(base_addr);
}
break;
case USB_REQ_SET_INTERFACE: // b
dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");
if (crq.bRequestType == USB_RECIP_INTERFACE) {
goto config_change;
}
break;
case USB_REQ_SET_ADDRESS: // 5
dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n");
if (crq.bRequestType == USB_RECIP_DEVICE) {
tmp = crq.wValue & 0x7F;
dev->address = tmp;
udc_writel((tmp | 0x80), S3C2410_UDC_FUNC_ADDR_REG);
set_ep0_de_out(base_addr);
return;
}
break;
case USB_REQ_GET_STATUS: // 0
dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n");
clear_ep0_opr(base_addr);
if (!s3c2410_get_status(dev, &crq)) {
return;
}
break;
default:
clear_ep0_opr(base_addr);
break;
}
if (crq.bRequestType & USB_DIR_IN)
dev->ep0state = EP0_IN_DATA_PHASE;
else
dev->ep0state = EP0_OUT_DATA_PHASE;
spin_unlock(&dev->lock);
ret = dev->driver->setup(&dev->gadget, &crq);
spin_lock(&dev->lock);
if (ret < 0) {
if (dev->req_config) {
dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n",
crq.bRequest, ret);
return;
}
if (ret == -EOPNOTSUPP)
dprintk(DEBUG_NORMAL, "Operation not supported\n");
else
dprintk(DEBUG_NORMAL, "dev->driver->setup failed. (%d)\n",ret);
set_ep0_ss(base_addr);
set_ep0_de_out(base_addr);
dev->ep0state = EP0_IDLE;
/* deferred i/o == no response yet */
} else if (dev->req_pending) {
dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n");
dev->req_pending=0;
}
dprintk(DEBUG_VERBOSE, "ep0state %s\n",ep0states[dev->ep0state]);
}
break;
case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */
dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");
if (!(ep0csr & 2) && req)
{
write_fifo(ep, req);
}
break;
case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */
dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");
if ((ep0csr & 1) && req ) {
read_fifo(ep,req);
}
break;
case EP0_END_XFER:
dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n");
dev->ep0state=EP0_IDLE;
break;
case EP0_STALL:
dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n");
dev->ep0state=EP0_IDLE;
break;
}
}
/*
* handle_ep - Manage I/O endpoints
*/
static void handle_ep(struct s3c2410_ep *ep)
{
struct s3c2410_request *req;
int is_in = ep->bEndpointAddress & USB_DIR_IN;
u32 ep_csr1;
u32 idx;
if (likely (!list_empty(&ep->queue)))
req = list_entry(ep->queue.next,
struct s3c2410_request, queue);
else
req = NULL;
idx = (u32)(ep->bEndpointAddress&0x7F);
if (is_in) {
udc_writel(idx, S3C2410_UDC_INDEX_REG);
ep_csr1 = udc_readl(S3C2410_UDC_IN_CSR1_REG);
dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n",idx,ep_csr1,req ? 1 : 0);
if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL)
{
dprintk(DEBUG_VERBOSE, "st\n");
udc_writel(idx, S3C2410_UDC_INDEX_REG);
udc_writel(0x00,S3C2410_UDC_IN_CSR1_REG);
return;
}
if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req)
{
write_fifo(ep,req);
}
}
else {
udc_writel(idx, S3C2410_UDC_INDEX_REG);
ep_csr1 = udc_readl(S3C2410_UDC_OUT_CSR1_REG);
dprintk(DEBUG_VERBOSE, "ep%01d read csr:%02x\n",idx,ep_csr1);
if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL)
{
udc_writel(idx, S3C2410_UDC_INDEX_REG);
udc_writel(0x00,S3C2410_UDC_OUT_CSR1_REG);
return;
}
if( (ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req)
{
read_fifo(ep,req);
}
}
}
#include <asm/arch/regs-irq.h>
/*
* s3c2410_udc_irq - interrupt handler
*/
static irqreturn_t
s3c2410_udc_irq(int irq, void *_dev, struct pt_regs *r)
{
struct s3c2410_udc *dev = _dev;
int usb_status;
int usbd_status;
int pwr_reg;
int ep0csr;
int i;
u32 idx;
unsigned long flags;
/* Driver connected ? */
if (!dev->driver) {
/* Clear interrupts */
udc_writel( \
udc_readl(S3C2410_UDC_USB_INT_REG), \
S3C2410_UDC_USB_INT_REG \
);
udc_writel( \
udc_readl(S3C2410_UDC_EP_INT_REG), \
S3C2410_UDC_EP_INT_REG \
);
}
spin_lock_irqsave(&dev->lock,flags);
/* Save index */
idx = udc_readl(S3C2410_UDC_INDEX_REG);
/* Read status registers */
usb_status = udc_readl(S3C2410_UDC_USB_INT_REG);
usbd_status = udc_readl(S3C2410_UDC_EP_INT_REG);
pwr_reg = udc_readl(S3C2410_UDC_PWR_REG);
S3C2410_UDC_SETIX(base_addr,EP0);
ep0csr = udc_readl(S3C2410_UDC_IN_CSR1_REG);
// dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n", usb_status, usbd_status, pwr_reg,ep0csr);
/*
* Now, handle interrupts. There's two types :
* - Reset, Resume, Suspend coming -> usb_int_reg
* - EP -> ep_int_reg
*/
/* RESET */
if (usb_status & S3C2410_UDC_USBINT_RESET )
{
dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n",ep0csr,pwr_reg);
udc_writel(0x00, S3C2410_UDC_INDEX_REG);
udc_writel((dev->ep[0].ep.maxpacket&0x7ff)>>3,S3C2410_UDC_MAXP_REG);
dev->gadget.speed = USB_SPEED_FULL;
dev->ep0state = EP0_IDLE;
nuke(dev,&dev->ep[0]);
/* clear interrupt */
udc_writel(S3C2410_UDC_USBINT_RESET,
S3C2410_UDC_USB_INT_REG);
udc_writel(idx,S3C2410_UDC_INDEX_REG);
spin_unlock_irqrestore(&dev->lock,flags);
return IRQ_HANDLED;
}
/* RESUME */
if (usb_status & S3C2410_UDC_USBINT_RESUME)
{
dprintk(DEBUG_NORMAL, "USB resume\n");
/* clear interrupt */
udc_writel(S3C2410_UDC_USBINT_RESUME,
S3C2410_UDC_USB_INT_REG);
if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->resume)
dev->driver->resume(&dev->gadget);
}
/* SUSPEND */
if (usb_status & S3C2410_UDC_USBINT_SUSPEND)
{
dprintk(DEBUG_NORMAL, "USB suspend\n");
/* clear interrupt */
udc_writel(S3C2410_UDC_USBINT_SUSPEND,
S3C2410_UDC_USB_INT_REG);
if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->suspend)
dev->driver->suspend(&dev->gadget);
dev->ep0state = EP0_IDLE;
}
/* EP */
/* control traffic */
/* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready
* generate an interrupt
*/
if (usbd_status & S3C2410_UDC_INT_EP0)
{
dprintk(DEBUG_VERBOSE, "USB ep0 irq\n");
/* Clear the interrupt bit by setting it to 1 */
udc_writel(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
handle_ep0(dev);
}
/* endpoint data transfers */
for (i = 1; i < S3C2410_ENDPOINTS; i++) {
u32 tmp = 1 << i;
if (usbd_status & tmp) {
dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i);
/* Clear the interrupt bit by setting it to 1 */
udc_writel(tmp, S3C2410_UDC_EP_INT_REG);
handle_ep(&dev->ep[i]);
}
}
dprintk(DEBUG_VERBOSE,"irq: %d done.\n", irq);
/* Restore old index */
udc_writel(idx,S3C2410_UDC_INDEX_REG);
spin_unlock_irqrestore(&dev->lock,flags);
return IRQ_HANDLED;
}
/*------------------------- s3c2410_ep_ops ----------------------------------*/
/*
* s3c2410_ep_enable
*/
static int
s3c2410_ep_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
{
struct s3c2410_udc *dev;
struct s3c2410_ep *ep;
u32 max, tmp;
unsigned long flags;
u32 csr1,csr2;
u32 int_en_reg;
ep = container_of (_ep, struct s3c2410_ep, ep);
if (!_ep || !desc || ep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL;
dev = ep->dev;
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff;
spin_lock_irqsave (&dev->lock, flags);
_ep->maxpacket = max & 0x7ff;
ep->desc = desc;
ep->bEndpointAddress = desc->bEndpointAddress;
/* set max packet */
udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
udc_writel(max>>3,S3C2410_UDC_MAXP_REG);
/* set type, direction, address; reset fifo counters */
if (desc->bEndpointAddress & USB_DIR_IN)
{
csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT;
csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN;
udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
udc_writel(csr1,S3C2410_UDC_IN_CSR1_REG);
udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
udc_writel(csr2,S3C2410_UDC_IN_CSR2_REG);
}
else
{
/* don't flush he in fifo or there will be an interrupt for that
* endpoint */
csr1 = S3C2410_UDC_ICSR1_CLRDT;
csr2 = S3C2410_UDC_ICSR2_DMAIEN;
udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
udc_writel(csr1,S3C2410_UDC_IN_CSR1_REG);
udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
udc_writel(csr2,S3C2410_UDC_IN_CSR2_REG);
csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT;
csr2 = S3C2410_UDC_OCSR2_DMAIEN;
udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
udc_writel(csr1,S3C2410_UDC_OUT_CSR1_REG);
udc_writel(ep->num, S3C2410_UDC_INDEX_REG);
udc_writel(csr2,S3C2410_UDC_OUT_CSR2_REG);
}
/* enable irqs */
int_en_reg = udc_readl(S3C2410_UDC_EP_INT_EN_REG);
udc_writel(int_en_reg | (1<<ep->num),S3C2410_UDC_EP_INT_EN_REG);
/* print some debug message */
tmp = desc->bEndpointAddress;
dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",
_ep->name,ep->num, tmp, desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max);
spin_unlock_irqrestore (&dev->lock, flags);
return 0;
}
/*
* s3c2410_ep_disable
*/
static int s3c2410_ep_disable (struct usb_ep *_ep)
{
struct s3c2410_ep *ep = container_of(_ep, struct s3c2410_ep, ep);
unsigned long flags;
u32 int_en_reg;
if (!_ep || !ep->desc) {
dprintk(DEBUG_NORMAL, "%s not enabled\n",
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
spin_lock_irqsave(&ep->dev->lock, flags);
ep->desc = NULL;
nuke (ep->dev, ep);
/* disable irqs */
int_en_reg = udc_readl(S3C2410_UDC_EP_INT_EN_REG);
udc_writel(int_en_reg & ~(1<<ep->num),S3C2410_UDC_EP_INT_EN_REG);
spin_unlock_irqrestore(&ep->dev->lock, flags);
dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name);
return 0;
}
/*
* s3c2410_alloc_request
*/
static struct usb_request *
s3c2410_alloc_request (struct usb_ep *_ep, unsigned int mem_flags)
{
struct s3c2410_ep *ep;
struct s3c2410_request *req;
dprintk(DEBUG_VERBOSE,"s3c2410_alloc_request(ep=%p,flags=%d)\n", _ep, mem_flags);
ep = container_of (_ep, struct s3c2410_ep, ep);
if (!_ep)
return NULL;
req = kmalloc (sizeof *req, mem_flags);
if (!req)
return NULL;
memset (req, 0, sizeof *req);
INIT_LIST_HEAD (&req->queue);
return &req->req;
}
/*
* s3c2410_free_request
*/
static void
s3c2410_free_request (struct usb_ep *_ep, struct usb_request *_req)
{
struct s3c2410_ep *ep;
struct s3c2410_request *req;
dprintk(DEBUG_VERBOSE, "s3c2410_free_request(ep=%p,req=%p)\n", _ep, _req);
ep = container_of (_ep, struct s3c2410_ep, ep);
if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
return;
req = container_of (_req, struct s3c2410_request, req);
WARN_ON (!list_empty (&req->queue));
kfree (req);
}
/*
* s3c2410_alloc_buffer
*/
static void *
s3c2410_alloc_buffer (
struct usb_ep *_ep,
unsigned bytes,
dma_addr_t *dma,
unsigned int mem_flags)
{
char *retval;
dprintk(DEBUG_VERBOSE,"s3c2410_alloc_buffer()\n");
if (!the_controller->driver)
return NULL;
retval = kmalloc (bytes, mem_flags);
*dma = (dma_addr_t) retval;
return retval;
}
/*
* s3c2410_free_buffer
*/
static void
s3c2410_free_buffer (
struct usb_ep *_ep,
void *buf,
dma_addr_t dma,
unsigned bytes)
{
dprintk(DEBUG_VERBOSE, "s3c2410_free_buffer()\n");
if (bytes)
kfree (buf);
}
/*
* s3c2410_queue
*/
static int
s3c2410_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned int gfp_flags)
{
struct s3c2410_request *req;
struct s3c2410_ep *ep;
struct s3c2410_udc *dev;
u32 ep_csr=0;
int fifo_count=0;
unsigned long flags;
ep = container_of(_ep, struct s3c2410_ep, ep);
if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
dprintk(DEBUG_NORMAL, "s3c2410_queue: inval 2\n");
return -EINVAL;
}
dev = ep->dev;
if (unlikely (!dev->driver
|| dev->gadget.speed == USB_SPEED_UNKNOWN)) {
return -ESHUTDOWN;
}
spin_lock_irqsave (&dev->lock, flags);
req = container_of(_req, struct s3c2410_request, req);
if (unlikely (!_req || !_req->complete || !_req->buf
|| !list_empty(&req->queue))) {
if (!_req)
dprintk(DEBUG_NORMAL, "s3c2410_queue: 1 X X X\n");
else
{
dprintk(DEBUG_NORMAL, "s3c2410_queue: 0 %01d %01d %01d\n",!_req->complete,!_req->buf, !list_empty(&req->queue));
}
spin_unlock_irqrestore(&dev->lock,flags);
return -EINVAL;
}
#if 0
/* iso is always one packet per request, that's the only way
* we can report per-packet status. that also helps with dma.
*/
if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
&& req->req.length > le16_to_cpu
(ep->desc->wMaxPacketSize)))
return -EMSGSIZE;
#endif
_req->status = -EINPROGRESS;
_req->actual = 0;
dprintk(DEBUG_NORMAL,"s3c2410_queue: ep%x len %d\n",ep->bEndpointAddress,_req->length);
if (ep->bEndpointAddress)
{
udc_writel(ep->bEndpointAddress&0x7F,S3C2410_UDC_INDEX_REG);
ep_csr = udc_readl(ep->bEndpointAddress&USB_DIR_IN ? S3C2410_UDC_IN_CSR1_REG : S3C2410_UDC_OUT_CSR1_REG);
fifo_count=fifo_count_out();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -