📄 usb_pdc.c
字号:
if (kick == 2) {
/* BUG: sending NULL data packet after stall is not valid .....*/
/* Send NULL packet if DATA PID is not cleared by the HW
* This case assumed that tx_data(2) is used only for endpoint EP2 */
if((pdc_read16(CMD_READEPSTATUS+handle)) & 0x10) {
writeendpoint(handle,0,0);
}
pipe->txrx_idle = 1;
if(ep_urb) {
ep_urb->actual_length = 0;
if(ep_urb->next) ep_urb->next->actual_length = 0;
kick = 1;
}
else return;
}
if (!kick) {
/* Get status/clear IRQ */
txstat=pdc_read16(CMD_READEPSTATUS+handle);
/* Successfully sent some stuff: bump counts & reset buffer */
ep_urb = pipe->urb;
/* If last packet was short, and there's nothing in the buffer
to send, then just stop here with TX disabled */
/* XXX: when the data transfer is over, go to silent mode */
if(ep_urb && (ep_urb->actual_length == ep_urb->transfer_buffer_length) && !(txstat & (STATUS_EPFULL))) {
/* URB Complete */
pipe->urb = ep_urb->next;
ep_urb->actual_length = ep_urb->transfer_buffer_length;
ep_urb->status = PDC_URB_COMPLETE;
if(ep_urb->complete) ep_urb->complete(ep_urb);
ep_urb = pipe->urb;
}
if(!ep_urb) {
pipe->txrx_idle = 1;
return;
}
}
ep_urb = pipe->urb;
/* Work out how many FIFOs we can fill */
tofill = 2;
txstat = pdc_read16(CMD_READEPSTATUS+handle);
if(txstat & STATUS_EPFULL0) tofill--;
if(txstat & STATUS_EPFULL1) tofill--;
/* XXX The problem with this for BOT protocol is in the IN data stage
* after sending the data, host expects status (IN) data and we are
* sending a NULL packet which is causing whole device to re-enumerate
* In this case the data is multiple of MaxPacketSize
* So only if tx_used is there then send the data */
/* While we can send stuff... (this will fill both FIFOs) */
while( (ep_urb) && (tofill>0) &&
ep_urb->actual_length != ep_urb->transfer_buffer_length)
{
/* Fill local packet buffer from TX buffer: if there's nothing
to send (there might be: we need to be able to send zero
length packets to terminate a transfer of an exact multiple
of the buffer size), then we'll be sending a 0 byte
packet */
usb_txsize = ep_urb->transfer_buffer_length - ep_urb->actual_length;
if ((usb_txsize)> pipe->ep_desc->max_pkt_size) usb_txsize=pipe->ep_desc->max_pkt_size;
writeendpoint(handle, (((__u8*)ep_urb->transfer_buffer)+ep_urb->actual_length), usb_txsize);
ep_urb->actual_length += usb_txsize;
/* Not idle anymore */
pipe->txrx_idle=0;
/* Filled another buffer */
tofill--;
}
} /* End of tx_data() */
/* Deal with incoming packet on the control endpoint */
void rx_command(struct pdc_dev *pdc)
{
/* Get receiver status */
unsigned char command[8];
int eplast;
unsigned long bytes, rcvd_bytes;
struct pdc_pipe *pipe;
struct pdc_urb *urb;
/* Get last transaction status (clears IRQ) */
eplast=pdc_read16(CMD_READEPSTATUS+EP0OUT);
/* Is this a setup packet? */
if(eplast&STATUS_SETUPT) {
int i;
/* Read the packet into our buffer */
if ((i=readendpoint(EP0OUT,command,sizeof(command)))!=sizeof(command)) {
pdc_command(CMD_STALLEP+EP0IN);
pdc_command(CMD_STALLEP+EP0OUT);
detail_debug(("pdc:Short USB control read (%d bytes)!\n",i))
return;
}
/* Acknowledge out endpoints, then clear; the
arrival of the setup packet disables the clear command
which is issued in readendpoint() */
pdc_command(CMD_ACKSETUP);
pdc_command(CMD_CLEAREP+EP0OUT);
/* Clear all the previous data transfers on the IN endpoint */
pipe = pdc->ep_pipes + EP0OUT ;
urb = pipe->urb;
/* For each URB complete the URB */
while(urb) {
urb->status = PDC_SETUP_OVERRITE;
pipe->urb = urb->next;
if(urb->complete) urb->complete(urb);
urb = pipe->urb;
}
/* Call the notification function of Configuration driver */
pipe = pdc->ep_pipes + EP0OUT;
if((pipe->pipe_desc) && (pipe->pipe_desc->notify)) {
pipe->pipe_desc->notify(PDC_SETUP_COMMAND,
pipe->pipe_desc->priv,
command);
}
} else {
/* If not a setup packet, it must be an OUT packet */
pipe = pdc->ep_pipes + EP0OUT ;
urb = pipe->urb;
if(urb) {
/* How many bytes do we need? */
bytes = urb->transfer_buffer_length - urb->actual_length;
rcvd_bytes = readendpoint(EP0OUT,&(((__u8*)urb->transfer_buffer)[urb->actual_length]),bytes);
urb->actual_length += rcvd_bytes;
/* Did we receive a short packet?? */
if(rcvd_bytes < bytes) urb->status = PDC_SHORT_PACKET;
/* Complete the urb if all the bytes are received from host or terminated
* because of short packet
*/
if(urb->transfer_buffer_length == urb->actual_length|| urb->status == PDC_SHORT_PACKET) {
pipe->urb = urb->next;
if(urb->status == PDC_URB_PENDING) {
urb->status = PDC_URB_COMPLETE;
}
if(urb->complete) urb->complete(urb);
urb = pipe->urb;
}
} else {
/* Clear the buffer, Do we need to wait for the appl?? let us see */
readendpoint(EP0OUT,NULL,0);
}
}
} /* End of rx_command */
/* TX command */
void tx_command(struct pdc_dev *pdc)
{
struct pdc_pipe *pipe = pdc->ep_pipes + EP0IN;
int txstatus;
struct pdc_urb *pipe_urb;
__u16 len;
func_debug(("tx_command(void)\n"))
/* Read last status & discard */
txstatus=pdc_read16(CMD_READEPSTATUS+EP0IN);
pipe_urb = pipe->urb;
if(pipe_urb) {
len = pipe_urb->transfer_buffer_length - pipe_urb->actual_length;
if(len > pipe->ep_desc->max_pkt_size) len = pipe->ep_desc->max_pkt_size;
writeendpoint(EP0IN, &(((__u8*)pipe_urb->transfer_buffer)[pipe_urb->actual_length]), len);
pipe_urb->actual_length += len;
if(pipe_urb->actual_length == pipe_urb->transfer_buffer_length) {
pipe_urb->status = PDC_URB_COMPLETE;
pipe->urb = pipe_urb->next;
if(pipe_urb->complete) pipe_urb->complete(pipe_urb);
}
}
if(!pipe->urb) pipe->txrx_idle = 1;
} /* End of tx_command */
/* Interrupt Service Routine */
void pdc_isr(struct isp1362_dev *dev, void *isr_data)
{
struct pdc_dev *pdc = (struct pdc_dev*)isr_data;
unsigned int evnt, non_ctrl_ep_event, ep_event;
struct pdc_config_dev *bus = pdc->pdc_bus;
pdc_pipe_handle_t handle;
struct pdc_pipe *pipe;
while(1) {
/* Read IRQ status, masking with possible valid IRQs */
evnt= dev->int_reg&
(IE_EP0OUT|IE_EP0IN|IE_NON_CTRL_EP_MASK|IE_RST|IE_SUSP);
/* No irq? */
if (evnt==0) {
return;
}
non_ctrl_ep_event = evnt & IE_NON_CTRL_EP_MASK;
handle = EP1;
while(non_ctrl_ep_event) {
ep_event = IE_EP0OUT << handle;
if( non_ctrl_ep_event & ep_event) {
pipe = pdc->ep_pipes + handle;
if(pipe->ep_desc && pipe->pipe_desc) {
if(pipe->ep_desc->ep_dir) {
/* In pipe */
tx_data(pdc, handle, 0); /* Data trasmission on In pipe */
} else {
/* Out pipe */
rx_data(pdc, handle); /* Data reception on OUT pipe */
}
} else {
/* What to do?? received interrupt on an unconfigured, unopen pipe */
}
non_ctrl_ep_event &= ~ep_event;
}
handle++;
}
if (evnt&IE_EP0OUT) {
rx_command(pdc); /* Control Out, SETUP */
}
if (evnt&IE_EP0IN) {
tx_command(pdc); /* COntrol IN */
}
if (evnt&IE_RST) {
/*
* Inform the configuration driver
* initialize the controller and connect to the bus
*/
if(bus && bus->notif) bus->notif(bus->context, PDC_RESET);
/* notify the application */
pdc_init(dev);
pdc_connect();
}
if (evnt&IE_RESM) {
/* Inform the configuration driver */
if(bus && bus->notif) bus->notif(bus->context, PDC_RESUME);
}
if (evnt&IE_SUSP) {
/* Inform the configuration driver */
if(bus && bus->notif) bus->notif(bus->context, PDC_SUSPEND);
}
dev->int_reg =pdc_read32(CMD_READIRQ);
}
} /* End of pdc_isr */
/*------------------------------------------------------------------------*
* External Interface functions *
*------------------------------------------------------------------------*/
/*
* Get the current frame number on the USB bus
* @cd class driver identifier
*/
unsigned long pdc_get_frame_number(struct pdc_class_drv *cd)
{
unsigned long flags;
unsigned long frame_number;
func_debug(("pdc_get_frame_number(cd=%p)\n",cd))
spin_lock_irqsave(&pdc_rdwr_lock, flags);
frame_number = pdc_read16(CMD_READFRAME);
frame_number &= 0x7FF;
spin_unlock_irqrestore(&pdc_rdwr_lock, flags);
return frame_number;
} /* End of pdc_get_frame_number() */
/*
* Set the address of the device
* @context is the device context
* @address is the device address on the bus
*/
int pdc_set_device_address(unsigned long context,unsigned short address)
{
func_debug(("pdc_set_device_address(context=%x,address=%x\n",context, address))
pdc_write16(CMD_WRITEADDRESS, (ADDRESS_DEVEN|address));
return 0;
} /* End of pdc_set_device_address() */
/*
* Configure the device endpoints and Notification function
*/
int pdc_configure_device(struct pdc_config_dev *config)
{
struct pdc_ep_desc *ep_desc = config->ep_desc;
struct pdc_pipe *pipe;
struct pdc_dev *pdc = usb_devices;
pdc_pipe_handle_t handle;
__u8 index;
func_debug(("pdc_configure_device(config=%p)\n",config))
/* Initialize all pipe varaiables except the control ones */
for(handle=2; handle < PDC_MAX_PIPES; handle++) {
pipe = pdc->ep_pipes + handle;
pipe->ep_desc = NULL;
pipe->pipe_desc = NULL;
pipe->ep_state = PDC_PIPE_UNCONFIG;
}
/* Go through all the end points in the list */
for(index = 0; index < config->num_eps; index++) {
if(ep_desc->ep_num != 0 && ep_desc->ep_num < PDC_MAX_EPS) {
/* Get the pipe handle for the Endpoint */
handle = pdc_usb_to_epreg((ep_desc->ep_num),(ep_desc->ep_dir));
pipe = pdc->ep_pipes + handle; /* Get the pipe descriptor */
pipe->ep_desc = ep_desc;
pipe->ep_state = PDC_PIPE_CONFIG;
}
ep_desc++;
}
/* Copy the configuration driver information */
pdc->pdc_bus = config;
/* Configure the endpoints in the Hardware */
pdc_configure_eps(pdc);
return 0;
} /* End of pdc_configure_device() */
/*
* Open a data transfer pipe
* @pipe_desc: pipe information
*/
pdc_pipe_handle_t pdc_open_pipe(struct pdc_pipe_desc *pipe_desc)
{
struct pdc_pipe *pipe;
pdc_pipe_handle_t handle = PDC_INV_PIPE_HANDLE;
struct pdc_dev *pdc=usb_devices;
func_debug(("pdc_open_pipe(pipe_desc=%p)\n",pipe_desc))
if(pipe_desc->ep < PDC_MAX_EPS) {
handle = pdc_usb_to_epreg((pipe_desc->ep),(pipe_desc->ep_dir));
pipe = pdc->ep_pipes + handle;
/* If pipe is configured before, then open the pipe */
if(pipe->ep_state == PDC_PIPE_CONFIG) {
/* Only configured pipes can be opened */
pipe->ep_state = PDC_PIPE_OPEN;
pipe->pipe_desc = pipe_desc;
} else {
/* else return invalid handle */
handle = PDC_INV_PIPE_HANDLE;
}
if(pipe_desc->ep == 0) {
/*
* This is a control end point to the user and control out pipe for us,
* so open a control in pipe also
*/
pipe = pdc->ep_pipes + handle + 1;
pipe->ep_state = PDC_PIPE_OPEN;
pipe->pipe_desc = pipe_desc;
}
}
return handle;
} /* End of pdc_open_pipe() */
/*
* Close an already opened pipe
* @pipe_handle: pipe handle
*/
void pdc_close_pipe(pdc_pipe_handle_t pipe_handle)
{
__u8 ep;
struct pdc_pipe *pipe;
struct pdc_dev *pdc=usb_devices;
func_debug(("pdc_close_pipe(pipe_handle=%x)\n",pipe_handle))
if(pipe_handle < PDC_MAX_PIPES) {
pipe = pdc->ep_pipes + pipe_handle;
/* If the pipe is opened then cleanup the stuff */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -