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

📄 usb_pdc.c

📁 philips公司ISP1362 USB OTG控制芯片的驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/*************************************************************
 * Philips USB peripheral controller driver
 *
 * (c) 2002 Koninklijke Philips Electronics N.V., All rights reserved
 * 
 * This  source code and any compilation or derivative thereof is the
 * proprietary information of Koninklijke Philips Electronics N.V.
 * and is confidential in nature.
 * Under no circumstances is this software to be exposed to or placed
 * under an Open Source License of any type without the expressed
 * written permission of Koninklijke Philips Electronics N.V.
 *
 * File Name:	usb_pdc.c
 *
 * History:	
 *
 *	Version	Date		Author		Comments
 * -------------------------------------------------
 * 	1.0		09/23/02	SBANSAL		Initial Creation
 *
 * Note: use tab space 4
 *************************************************************/

/* Philips Peripheral Controller Driver
 *
 * The mapping of the endpoint is simple: it basically behaves as a device,
 * which can be opened, closed, and have reads and writes performed
 * on it. Due to the high bandwidth of the USB (12Mbit) we maintain local
 * buffers to ensure that we don't get starved of data during transmissions -
 * and have a receive buffer to allow the process dealing with USB to read in
 * bigger blocks than the packet size.
 *
 * The implementation is designed to be pretty transparent: this is for a
 * number of reasons, this is same protocol over both the USB and the serial 
 * ports on the customers unit.Implementing the endpoint as a simple 'open/close' device
 * as opposed to a more complex network-style interface also means that we can
 * do froody stuff like run PPP over a 12Mbit usb link (host permitting, of
 * course...). To this end, there is limited control over the way the USB
 * device works - endpoint 0 is handled totally under software control, and
 * only a limited number of events are passed though for the user-side task
 * to worry about (like connection/disconnection of the USB cable).
 *
 */

#include <linux/config.h>
#define	MODULE
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/tqueue.h>

#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>

#include "pdc_intf.h"
#include "usb_pdc.h"



#define DRIVER_AUTHOR 		"Philips Semiconductors"
#define	DRIVER_DESC			"ISP1362 Peripheral Controller Driver"
#define PDC_DRIVER_VERSION 	"1.0"
#define	DRIVER_NAME			"usb-pdc"



/*--------------------------------------------------------------*
 *               external functions
 *--------------------------------------------------------------*/
extern	int	pdc_bus_init(struct pdc_dev	*pdc);
extern	void 	pdc_bus_deinit(void);


/*--------------------------------------------------------------*
 *          Device Controller endpoint related functions
 *--------------------------------------------------------------*/
static void writeendpoint(int endpoint, unsigned char *buffer, int length);
static __inline__ int checkendpoint(int endpoint);
static void pdc_configure_eps(struct pdc_dev	*pdc);
static	int pdc_submit_control_urb(struct pdc_dev	*pdc, struct pdc_urb *urb_req);

/*--------------------------------------------------------------*
 *         Interrupt Service Routine related functions
 *--------------------------------------------------------------*/
void pdc_isr(struct isp1362_dev *dev, void *isr_data);
static void tx_data(struct pdc_dev *pdc, __u8 ep, int kick);
static void rx_data(struct pdc_dev *pdc, __u8 ep);
static void rx_command(struct pdc_dev *pdc);
static void tx_command(struct pdc_dev *pdc);


/*--------------------------------------------------------------*
 *               initialization function declerations
 *--------------------------------------------------------------*/
static int __init pdc_module_init (void);
static void __exit pdc_module_cleanup (void);
static int 	pdc_probe (struct isp1362_dev	*dev);
static void pdc_remove (struct isp1362_dev	*dev);
static void pdc_init(struct isp1362_dev	*dev);
static void pdc_connect(void);

/*--------------------------------------------------------------*
 *               local variable definitions
 *--------------------------------------------------------------*/

struct 	pdc_dev 			usb_devices[1];		/* local interface */
static 	struct isp1362_dev	*isp1362_dc_dev;	/* HOSAL interface */
static 	spinlock_t 			pdc_rdwr_lock = SPIN_LOCK_UNLOCKED;
struct 	pdc_pipe			pdc_eps[PDC_MAX_PIPES];
struct 	pdc_ep_desc			pdc_ctrl_ep_desc[2];		/* Control IN and Control OUT */

/*--------------------------------------------------------------*
 *          Device Controller register access functions
 *--------------------------------------------------------------*/
static __inline__ void pdc_command(__u16	cmd)
{
	isp1362_command(cmd,isp1362_dc_dev);
	isp1362_udelay(1);
}

static __inline__ __u16	pdc_cread(void)
{
	return isp1362_read16(isp1362_dc_dev);
}

static __inline__ void pdc_cwrite(__u16	data)  
{
	isp1362_write16(data,isp1362_dc_dev);
	return;
}

static __inline__ __u16	pdc_read16(__u16 reg)
{
	__u16	data;

	isp1362_reg_read16(isp1362_dc_dev, reg, data);

	return data;
}

static __inline__ void pdc_write16(__u16	reg, __u16	data)
{
	isp1362_reg_write16(isp1362_dc_dev, reg, data);
}

static __inline__ __u32	pdc_read32(__u16	reg)
{
	__u32	data;

	isp1362_reg_read32(isp1362_dc_dev, reg, data);

	return data;
}

static __inline__ void pdc_write32(__u16 reg, __u32	data)
{
	isp1362_reg_write32(isp1362_dc_dev, reg, data);

	return;
}



#define	pdc_set_mps_reg_value(mps,reg_mps,iso)							\
	if(iso){															\
		if(mps <= 16)	{reg_mps = EPCONFIG_ISO_FIFO16; mps =16;}		\
		else if(mps <= 32)	{reg_mps = EPCONFIG_ISO_FIFO32;	mps = 32;}	\
		else if(mps <= 48)	{reg_mps = EPCONFIG_ISO_FIFO48; mps = 48;}	\
		else if(mps <= 64)	{reg_mps = EPCONFIG_ISO_FIFO64;	mps = 64;}	\
		else if(mps <= 96)	{reg_mps = EPCONFIG_ISO_FIFO96;	mps = 96;}	\
		else if(mps <= 128)	{reg_mps = EPCONFIG_ISO_FIFO128; mps = 128;}\
		else if(mps <= 160)	{reg_mps = EPCONFIG_ISO_FIFO160; mps = 160;}\
		else if(mps <= 192)	{reg_mps = EPCONFIG_ISO_FIFO192; mps = 192;}\
		else if(mps <= 256)	{reg_mps = EPCONFIG_ISO_FIFO256; mps = 256;}\
		else if(mps <= 320)	{reg_mps = EPCONFIG_ISO_FIFO320; mps = 320;}\
		else if(mps <= 384)	{reg_mps = EPCONFIG_ISO_FIFO384; mps = 384;}\
		else if(mps <= 512)	{reg_mps = EPCONFIG_ISO_FIFO512; mps = 512;}\
		else if(mps <= 640)	{reg_mps = EPCONFIG_ISO_FIFO640; mps = 640;}\
		else if(mps <= 768)	{reg_mps = EPCONFIG_ISO_FIFO768; mps = 768;}\
		else if(mps <= 896)	{reg_mps = EPCONFIG_ISO_FIFO896; mps = 896;}\
		else {reg_mps = EPCONFIG_ISO_FIFO1023; mps = 1023;}				\
	} else {															\
		if(mps <= 8)	{reg_mps = EPCONFIG_FIFO8; mps = 8;}			\
		else if(mps <= 16)	{reg_mps = EPCONFIG_FIFO16;	mps = 16;}		\
		else if(mps <= 32)	{reg_mps = EPCONFIG_FIFO32;	mps = 32;}		\
		else {reg_mps = EPCONFIG_FIFO64; mps = 64;}						\
	}



/*--------------------------------------------------------------*
 *          Device Controller endpoint related functions
 *--------------------------------------------------------------*/
/* Check to see if endpoint is full */
static __inline__ int checkendpoint(int endpoint)
{
	/* Possible CMD_CHECKEPSTATUS? */
	return(pdc_read16(CMD_READEPSTATUS+endpoint)&
	       (STATUS_EPFULL0|STATUS_EPFULL1));
}


/* Read a packet out of a FIFO */
static int readendpoint(int endpoint, unsigned char *buffer, int length)
{
	/* Any data? */
	if (!checkendpoint(endpoint)) return(0);

	isp1362_buff_read(isp1362_dc_dev, (CMD_READEP+endpoint), buffer, length);

	/* Now we've read it, clear the buffer */
	pdc_command(CMD_CLEAREP+endpoint);
		
	/* Return bytes read */
	return length;
}

/* Write a packet into the fifo */
static void writeendpoint(int endpoint, unsigned char *buffer, int length)
{
	isp1362_buff_write(isp1362_dc_dev, (CMD_WRITEEP+endpoint), buffer, length);
	/* Validate the buffer so the chip will send it */
	pdc_command(CMD_VALIDATEEP+endpoint);
}

/* 
 * Configure the Endpoints in the Hardware for those
 * pipes that are configured. For others Just diables
 * them. This function also adjusts the Endpoint max packet size to the
 * neareds available max packet size of the hardware.
 */
void pdc_configure_eps(struct pdc_dev	*pdc)
{
	__u16	ep_config = 0;
	__u8	handle;
	struct pdc_pipe	*pipe;
	__u8	mps;
	__u32	int_en;


	func_debug(("pdc_configure_eps(pdc=%p)\n",pdc))

	int_en = pdc_read32(CMD_READIRQENABLE);

	/* Configure all the Pipes (endpoint registers) in the device */
	for(handle=0;handle<PDC_MAX_PIPES;handle++) {

		pipe = pdc->ep_pipes+handle;		/* Get the pipe data structure */

		ep_config = 0;

		if(pipe->ep_state != PDC_PIPE_UNCONFIG) {
			/* pipe is configured */
			/* MPS, DBL BUFF, DIR, enable,disable */
			/* Use double buffering for non control pipes */

			ep_config |= EPCONFIG_FIFOEN;
			if(pipe->ep_desc->ep_dir) ep_config |= EPCONFIG_EPDIR;
			if(handle > EP0IN) ep_config |= EPCONFIG_DBLBUF;	

			/* 
			 * Set the maximum pkt size and get the device configuration
			 * maximum packet size 
			 */
			if(pipe->ep_desc->attributes != PDC_EP_ISOCHRONOUS) {
				pdc_set_mps_reg_value((pipe->ep_desc->max_pkt_size), mps, 0);
			} else {
				pdc_set_mps_reg_value((pipe->ep_desc->max_pkt_size), mps, 1);
			}

			ep_config |= mps;
			int_en |= (IE_EP0OUT << handle);
		}

		/* Configure the end point register */
		pdc_write16(CMD_WRITEEPCONFIG+handle, ep_config);
	}

	pdc_write32(CMD_WRITEIRQENABLE,int_en);
	
} /* End of pdc_configure_eps() */

void pdc_dev_control(unsigned long	opr) 
{

	__u32		data;
	__u16		data_u16;
    	struct pdc_dev 		*pdc = usb_devices;

	switch(opr) {

		case PDC_ENABLE:

			data = pdc_read32(CMD_READIRQ);

			/* Bus is already in suspend state before enabling the DC
			 * If the interrupt is already cleared, then we never get any
			 * suspend interrupt later. So inform upper layers that the 
			 * bus is suspended */
			if((data & BUSTATUS) && pdc->pdc_bus && pdc->pdc_bus->notif)	
				pdc->pdc_bus->notif(pdc->pdc_bus->context, PDC_BUSTATUS);


			/* Set device address & enable */
			pdc_write16(CMD_WRITEADDRESS,ADDRESS_DEVEN|0);


			/* Enable interrupts */
			pdc_write32(CMD_WRITEIRQENABLE,IE_EP0OUT|IE_EP0IN|IE_SUSP|IE_RST|IE_RESM);

			/* Connect to the bus */
			pdc_write16(CMD_WRITEMODE,MODE_SOFTCT|MODE_INTENA);
			break;

		case PDC_DISABLE:

			/* Go off bus */
			pdc_write16(CMD_WRITEADDRESS,0);

			/* Turn off IRQs */
			pdc_write32(CMD_WRITEIRQENABLE,0);

			/* Global IRQ disable & turn off softconnect */
#if 0
			data_u16 = pdc_read16(CMD_READMODE);
			data_u16 &= (~MODE_INTENA);
			pdc_write16(CMD_WRITEMODE,data_u16);
#else
			pdc_write16(CMD_WRITEMODE,0);
#endif

			break;

		case PDC_CONNECT:

			/* Connect it to the USB bus */
			data_u16 = pdc_read16(CMD_READMODE);
			data_u16 |= MODE_SOFTCT;
			pdc_write16(CMD_WRITEMODE, data_u16);

			break;

		case PDC_DISCONNECT:

			/* Disconnect it from the USB bus */
			data_u16 = pdc_read16(CMD_READMODE);
			data_u16 &= (~MODE_SOFTCT);
			pdc_write16(CMD_WRITEMODE, data_u16);

			break;
	}

	return;
} /* End of pdc_dev_control()  */



/* 
 * Deal with the received data on the USB pipe
 *  @pdc: pdc device data structure
 * @handle: USB pipe handle
 */
void rx_data(struct pdc_dev *pdc, pdc_pipe_handle_t	handle)
{
	struct pdc_pipe	*pipe = pdc->ep_pipes + handle;
	struct pdc_urb	*urb = pipe->urb;
	__u16			status;
	__u8			fifos = 0;
	__u32			bytes, rcvd_bytes;

	func_debug(("rx_data(pdc=%p,handle=%x)\n",pdc,handle))

	if(in_interrupt()) {
		status = pdc_read16(CMD_READEPSTATUS+handle);
		pipe->ep_status = status;
	} else {
		status = pipe->ep_status;
	}

	if((status & STATUS_EPFULL) == STATUS_EPFULL) {
			fifos = 2;
	} else if(status&STATUS_EPFULL) {
			fifos = 1;
	}


	if (!(status & STATUS_EPFULL) || (status & STATUS_EPSTAL)) {
		return ;
	}

	while((fifos--) && urb) {

		/* How many bytes do we need? */
		bytes = urb->transfer_buffer_length - urb->actual_length;

		if(bytes > pipe->ep_desc->max_pkt_size) bytes = pipe->ep_desc->max_pkt_size;

		rcvd_bytes = readendpoint(handle,&(((__u8*)urb->transfer_buffer)[urb->actual_length]),bytes);

		urb->actual_length += rcvd_bytes;

		/* Clear the full bits */
		if(pipe->ep_status & STATUS_EPFULL0) {
			pipe->ep_status &= ~(STATUS_EPFULL0);
		} else if(pipe->ep_status & STATUS_EPFULL1) {
			pipe->ep_status &= ~(STATUS_EPFULL1);
		}

		/* Did we receive a short packet?? */
		if(rcvd_bytes < bytes) {
			urb->status = PDC_SHORT_PACKET;
			detail_debug(("Short packet\n"))
		}


		/* 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;
		}
		
	} //while(fifo--)
} /* End of rx_data() */




/* 
 * Deal with the transmit data on a USB pipe
 * @pdc : pdc device data structure
 * @pipe :  USB pipe
 */
void tx_data(struct pdc_dev *pdc, pdc_pipe_handle_t	handle, int kick)
{
	int txstat,tofill=1;
	struct pdc_pipe *pipe = pdc->ep_pipes + handle;
	struct pdc_urb	*ep_urb = pipe->urb;
	int 			usb_txsize;
	
	func_debug(("tx_data(handle=%x, kick=%x)\n", handle, kick))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -