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

📄 usb_pdc.c

📁 linux下的usb开发
💻 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){	isp1362_command(reg,isp1362_dc_dev);	return isp1362_read16(isp1362_dc_dev);}static __inline__ void pdc_write16(__u16	reg, __u16	data){	isp1362_command(reg,isp1362_dc_dev);	isp1362_write16(data,isp1362_dc_dev);}static __inline__ __u32	pdc_read32(__u16	reg){	__u32	data;	__u16	w_data;	isp1362_command(reg, isp1362_dc_dev);	w_data = isp1362_read16(isp1362_dc_dev);	data = w_data & 0x0000FFFF;	w_data = isp1362_read16(isp1362_dc_dev);	data |= (w_data & 0x0000FFFF) << 16;	return data;}static __inline__ void pdc_write32(__u16 reg, __u32	data){	__u16		w_data;	isp1362_command(reg, isp1362_dc_dev);	w_data = data & 0x0000FFFF;	isp1362_write16(w_data,isp1362_dc_dev);	w_data = (data & 0xFFFF0000) >> 16;	isp1362_write16(w_data,isp1362_dc_dev);}#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){	int a,c;	/* Any data? */	if (!checkendpoint(endpoint)) return(0);	/* Read it from the fifo */	pdc_command(CMD_READEP+endpoint);		/* Fetch length */	c=pdc_cread();	/* Trim length & read packet */	if (c>length) c=length;	a=c;	while(a>0) {		unsigned short w=pdc_cread();		*buffer++=w;		if (a!=1) *buffer++=(w>>8);		a-=2;	}	/* Now we've read it, clear the buffer */	pdc_command(CMD_CLEAREP+endpoint);			/* Return bytes read */	return(c);}/* Write a packet into the fifo */static void writeendpoint(int endpoint, unsigned char *buffer, int length){	int a;	/* Select the endpoint */	pdc_command(CMD_WRITEEP+endpoint);	/* Write the data */	pdc_cwrite(length);	a=length;	while(a>0) {		unsigned short w=*buffer++;		if (a!=1) w|=(*buffer++)<<8;		pdc_cwrite(w);		a-=2;	}	/* 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;	switch(opr) {		case PDC_ENABLE:			/* Set device address & enable */			pdc_write16(CMD_WRITEADDRESS,ADDRESS_DEVEN|0);			data = pdc_read32(CMD_READIRQ);			/* 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 */			pdc_write16(CMD_WRITEMODE,0);			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() *//* 

⌨️ 快捷键说明

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