📄 usb_pdc.c
字号:
if(pipe->ep_state == PDC_PIPE_OPEN) {
pipe->pipe_desc = NULL;
pipe->ep_state = PDC_PIPE_CONFIG;
}
/*
* Get the endpoint and if it is control ep then close
* the control IN pipe also
*/
ep = pdc_pipe_to_epreg(pipe_handle);
if(ep == 0) {
pdc_close_pipe(pipe_handle + 1);
}
}
} /* End of pdc_close_pipe() */
int pdc_submit_control_urb(struct pdc_dev *pdc, struct pdc_urb *urb_req)
{
struct pdc_pipe *pipe;
struct pdc_urb *urb;
unsigned long length;
pdc_pipe_handle_t handle = urb_req->pipe;
func_debug(("pdc_submit_control_urb(urb=%p)\n",urb_req))
if(urb_req->operation == PDC_OPR_WRITE) handle += 1; /* Control IN pipe */
pipe = pdc->ep_pipes + handle;
urb = pipe->urb;
/* Insert the URB in to the pipe URB queue (FIFO) */
if(!urb) {
pipe->urb = urb_req;
} else {
while(urb) {
if(urb->next != NULL) urb = urb->next;
else urb->next = urb_req;
}
}
/* set the output parameters */
urb_req->actual_length = 0;
urb_req->next = NULL;
if(urb_req->operation == PDC_OPR_WRITE) {
if(pipe->urb == urb_req) {
length = urb_req->transfer_buffer_length;
if(urb_req->transfer_buffer_length > pipe->ep_desc->max_pkt_size) {
length = pipe->ep_desc->max_pkt_size;
}
writeendpoint(handle,urb_req->transfer_buffer,length);
urb_req->actual_length += length;
}
if(urb_req->actual_length == urb_req->transfer_buffer_length) {
urb_req->status = PDC_URB_COMPLETE;
pipe->urb = urb_req->next;
if(urb_req->complete) urb_req->complete(urb);
}
} else if(urb_req->operation == PDC_OPR_READ) {
/* TODO */
}
return 0;
}
/*
* Submit an urb for data transfer
* @urb: urb request block
*/
int pdc_submit_urb(struct pdc_urb *urb_req)
{
struct pdc_pipe *pipe;
struct pdc_urb *urb;
unsigned long flags;
struct pdc_dev *pdc=usb_devices;
func_debug(("pdc_submit_urb(urb=%p)\n",urb_req))
if(urb_req->pipe > PDC_MAX_PIPES) return -EINVAL;
if(urb_req->pipe < 2) return pdc_submit_control_urb(pdc, urb_req);
pipe = pdc->ep_pipes + urb_req->pipe;
spin_lock_irqsave(&pdc_rdwr_lock, flags);
urb = pipe->urb;
/* Insert the URB in to the pipe URB queue (FIFO) */
if(!urb) {
pipe->urb = urb_req;
} else {
while(urb) {
if(urb->next != NULL) urb = urb->next;
else urb->next = urb_req;
}
}
/* set the output parameters */
urb_req->actual_length = 0;
urb_req->next = NULL;
if(urb_req->operation == PDC_OPR_READ) {
/*
* handle the read request, if there are no URB's,
* call the rx_data function
*/
if(pipe->urb == urb_req) {
rx_data(pdc, urb_req->pipe);
}
} else if(urb_req->operation == PDC_OPR_WRITE) {
/*
* Handle the write request.
* If the Pipe is not stalled and the transmission is idle
* start the transmission
*/
pipe->ep_status = (pdc_read16(CMD_CHECKEPSTATUS+(urb_req->pipe)) & STATUS_EPSTAL) ? PDC_PIPE_STALL : PDC_PIPE_UNSTALL ;
if(pipe->txrx_idle && pipe->ep_status != PDC_PIPE_STALL) {
tx_data(pdc, urb_req->pipe, 1); /* Kick the transfer */
}
}
spin_unlock_irqrestore(&pdc_rdwr_lock, flags);
return 0;
} /* End of pdc_submit_urb */
/*
* Cancel an urb for data transfer
* @urb: urb request block
*/
int pdc_cancel_urb(struct pdc_urb *urb_req)
{
struct pdc_pipe *pipe;
struct pdc_urb *urb, *prev_urb;
unsigned long flags;
struct pdc_dev *pdc=usb_devices;
func_debug(("pdc_cancel_urb(%p)\n",urb_req))
/* Check the pipe value */
if(urb_req->pipe > PDC_MAX_PIPES) return -EINVAL;
pipe = pdc->ep_pipes + urb_req->pipe;
if((urb_req->pipe == 0) && (urb_req->operation == PDC_OPR_WRITE)) {
/* Special case of control IN pipe */
pipe++;
}
spin_lock_irqsave(&pdc_rdwr_lock, flags);
prev_urb = NULL;
urb = pipe->urb;
/*
* search for the URB , The pipe could be either IN or OUT so there is
* only one URB list
*/
while((urb!=NULL) && (urb_req != urb)) {
prev_urb = urb;
urb = urb->next;
}
/*
* found URB, then Un link it from the list
*/
if(urb) {
urb->status = PDC_URB_COMPLETE;
if(prev_urb) prev_urb->next = urb->next;
else pipe->urb = urb->next;
}
spin_unlock_irqrestore(&pdc_rdwr_lock, flags);
return 0;
} /* End of pdc_cancel_urb */
/*
* Pipe operations
* @pipe_opr:
*/
int pdc_pipe_operation(struct pdc_pipe_opr *pipe_opr)
{
struct pdc_pipe *pipe;
__u16 status;
struct pdc_dev *pdc=usb_devices;
pdc_pipe_handle_t handle = pipe_opr->handle;
func_debug(("pdc_pipe_control(pipe_opr=%p)\n",pipe_opr))
if(handle < PDC_MAX_PIPES) {
pipe = pdc->ep_pipes + handle;
switch(pipe_opr->opr) {
case PDC_PIPE_STALL:
pdc_command(CMD_STALLEP+handle);
if(handle == EP0OUT) pdc_command(CMD_STALLEP+handle+1); /* Stall control in also */
break;
case PDC_PIPE_UNSTALL:
pdc_command(CMD_UNSTALLEP+handle);
if(handle == EP0OUT) pdc_command(CMD_UNSTALLEP+handle+1); /* untall control in also */
if(handle > EP0IN) {
if(pipe->ep_desc->ep_dir & PDC_EP_DIR_IN)
tx_data(pdc, handle, 2);
else
rx_data(pdc, handle);
}
break;
case PDC_GET_PIPE_STATUS:
status = pdc_read16(CMD_READEPSTATUS+handle);
pipe_opr->pipe_status = (status&STATUS_EPSTAL) ? PDC_PIPE_STALL :PDC_PIPE_UNSTALL;
break;
}
return 0;
}
return -1;
} /* End of pdc_pipe_operation() */
/*--------------------------------------------------------------*
* Device Controller intialization functions
*--------------------------------------------------------------*/
/* Initialisation of the Peripheral Controller */
void pdc_init(struct isp1362_dev *dev)
{
func_debug(("pdc_init(dev=%p)\n",dev))
/* set the ISP1362 Device controller Hardware Configuration */
isp1362_set_hw_config(dev);
/* Set DMA mode (no dma) */
pdc_write16(CMD_WRITEDMACONFIG,0);
/*bledia Disable all interrupts */
pdc_write32(CMD_WRITEIRQENABLE,0);
/* Set default address */
pdc_write16(CMD_WRITEADDRESS,0);
return;
} /* End of pdc_init */
/* Actually connect to the bus */
void pdc_connect(void)
{
/* Set device address & enable */
pdc_write16(CMD_WRITEADDRESS,ADDRESS_DEVEN|0);
/* Enable interrupts */
pdc_write32(CMD_WRITEIRQENABLE,IE_EP0OUT|IE_EP0IN|IE_RST|IE_SUSP);
/* Connect to the bus */
pdc_write16(CMD_WRITEMODE,MODE_SOFTCT|MODE_INTENA);
return;
} /* End of pdc_connect */
/*---------------------------------------------------------------------*
* ISP1362 HOSAL interface functions *
*---------------------------------------------------------------------*/
struct isp1362_driver pdc_driver = {
name: "usb-pdc",
index: ISP1362_DC,
probe: pdc_probe,
remove: pdc_remove,
};
/* Device initialisation */
int pdc_probe (struct isp1362_dev *dev)
{
struct pdc_dev *pdc=usb_devices;
int result, i;
struct pdc_pipe *pipe;
func_debug(("pdc_probe(dev=%p)\n",dev))
/* Grab the IO resources */
result = isp1362_check_io_region(dev);
if(result < 0) {
detail_debug(("%s IO resources are not free\n","isp1362-pdc"))
return result;
}
isp1362_request_io_region(dev);
pdc->dev = dev;
isp1362_dc_dev = dev;
for(i=0; i< PDC_MAX_PIPES;i++) {
pipe = pdc->ep_pipes + i;
pipe->urb = NULL;
pipe->txrx_idle = 1;
pipe->ep_state = PDC_PIPE_UNCONFIG;
pipe->ep_desc = NULL;
}
/* Configure the default end points */
/* Configure the control OUT pipe */
pipe = pdc->ep_pipes;
pipe->ep_desc = &pdc_ctrl_ep_desc[0];
pipe->ep_desc->ep_num = 0;
pipe->ep_desc->ep_dir = PDC_EP_DIR_OUT;
pipe->ep_desc->attributes = PDC_EP_CONTROL;
pipe->ep_desc->max_pkt_size = 64;
pipe->ep_state = PDC_PIPE_CONFIG;
/* configure the control IN pipe */
pipe = pdc->ep_pipes + 1;
pipe->ep_desc = &pdc_ctrl_ep_desc[1];
pipe->ep_desc->ep_num = 0;
pipe->ep_desc->ep_dir = PDC_EP_DIR_IN;
pipe->ep_desc->attributes = PDC_EP_CONTROL;
pipe->ep_desc->max_pkt_size = 64;
pipe->ep_state = PDC_PIPE_CONFIG;
pdc_bus_init(pdc);
/* Do chip setup */
pdc_init(dev);
/* Claim USB IRQ */
result=isp1362_request_irq(pdc_isr,dev,pdc);
/* Got it ok? */
if (result < 0) {
detail_debug((KERN_ERR "usb-pdc:Can't get USB device IRQ %d.\n", dev->irq))
return result;
}
detail_debug(("usb-pdc:device IRQ is initialised, Irq is %04x\n",dev->irq))
/* If there are pending IRQs, process them as we can only
detect edges */
#ifndef CONFIG_USB_OTG
/* All ready! */
pdc_connect();
#endif /* CONFIG_USB_OTG */
dev->driver_data = pdc;
detail_debug(("pdc:Philips USB device driver in INIT.\n"))
return 0;
} /* End of pdc_probe */
void pdc_remove (struct isp1362_dev *dev)
{
struct pdc_dev *pdc=(struct pdc_dev*)dev->driver_data;
func_debug(("pdc_remove(dev=%p)\n",dev))
pdc_bus_deinit();
/* Go off bus */
pdc_write16(CMD_WRITEADDRESS,0);
/* Turn off IRQs */
pdc_write32(CMD_WRITEIRQENABLE,0);
/* Global IRQ disable & turn off softconnect */
pdc_write16(CMD_WRITEMODE,0);
/* Free IRQ */
isp1362_free_irq(dev,pdc);
isp1362_release_io_region(dev); /* release IO space */
pdc->dev = NULL;
isp1362_dc_dev = NULL;
pdc->ep_pipes = pdc_eps;
} /* End of pdc_remove */
/*
* This is module init function
* This function registers the PDC driver to ISP1362 HOSAL driver
* which in turn calls the probe function when the dev is found
*/
static int __init pdc_module_init (void)
{
struct pdc_dev *pdc = usb_devices;
int result;
func_debug(("pdc_module_init(void)\n"))
pdc->dev = NULL;
pdc->ep_pipes = pdc_eps;
isp1362_dc_dev = NULL;
result = isp1362_register_driver(&pdc_driver);
if(result == 0) {
isp1362_printk(KERN_INFO __FILE__ ": %s Initialization Success \n",pdc_driver.name);
} else {
isp1362_printk(KERN_INFO __FILE__ ": %s Iinitialization Failed (error = %d)\n",pdc_driver.name,result);
}
return result;
} /* End of pdc_module_init */
/*
* This is module cleanup function
* Unregister from isp1362 HOSAL layer which in turn calls
* Close function
*/
static void __exit pdc_module_cleanup (void)
{
func_debug(("pdc_module_cleanup (void)\n"))
return isp1362_unregister_driver(&pdc_driver);
} /* End of pdc_module_cleanup */
module_init (pdc_module_init);
module_exit (pdc_module_cleanup);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -