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

📄 usb_pdc.c

📁 philips公司ISP1362 USB OTG控制芯片的驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 + -