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

📄 edb7312-usb.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * EDB7312 support for PDIUSBD12 / mass-storage. * *	(c) Copyright 2003 Petko Manolov <petkan@nucleusys.com> *	(c) Copyright 2003 Vladimir Ivanov <vladitx@nucleusys.com> * * TODO: * 	 - more SCSI commands for various OS needs *       - make this endian-independent with respect to USB structs, * as it is currently LE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include <asm/arch/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/delay.h>#include <asm/semaphore.h>#include <asm/signal.h>#include <asm/system.h>#include <asm/types.h>#include <linux/completion.h>#include <linux/config.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/blkdev.h>#include <linux/fs.h>#include <linux/kdev_t.h>#include <linux/locks.h>/* * XXX: Here's a good thing to think about * *   According to USB 1.1, "Set Address" device request is the only one which * should be processed differently and must be completed _after_ successfull * status state ... do you really believe specs? We usually don't, but it * takes some time to find exactly what we won't believe. *//* ------------------------------------------------------------------------- *//* * debug mode */#undef DBG#define ID "usbd12"/* * hardware description */#define IRQ_D12		IRQ_EINT1#define REG_D12_DAT	(EDB7312_VIRT_PDIUSBD12 + 0)#define REG_D12_CMD	(EDB7312_VIRT_PDIUSBD12 + 1)/*  * XXX: * * It seems that different EDB7312 revisions have the SUSPEND signal of * PDIUSBD12 routed to different locations. This is specific to P7 revision. */#define GPIO_D12_SUSP	((__raw_readb(EP7312_VIRT_CS3 + 0x0004) & 0x04) ? 1 : 0)#define __delay()	{			\	__raw_readb(EP7312_VIRT_CS3 + 0x0004);	\	__raw_readb(EP7312_VIRT_CS3 + 0x0004);	\}/* * atomic operations */#define d12_lock(p)	disable_irq((p)->irq)#define	d12_unlock(p)	enable_irq((p)->irq)/* * PDIUSBD12 commands and data *//* --- "Select endpoint" --- */#define CMD_SELECT_ENDP		0x00#define D_SELECT_ENDP_FULL	0x01#define D_SELECT_ENDP_STALL	0x02/* --- "Set endpoint status" --- */#define CMD_SET_ENDP_STATUS	0x40/* --- "Read last transaction status" --- */#define CMD_READ_LTRNS		0x40#define D_READ_LTRNS_SUCCESS	0x01#define D_READ_LTRNS_ERR_M	0x1E#define D_READ_LTRNS_SETUP	0x20#define D_READ_LTRNS_DATA1	0x40#define D_READ_LTRNS_PREV	0x80#define D_READ_LTRNS_ERR_NO		(0 << 1)#define D_READ_LTRNS_ERR_PID_ENC	(1 << 1)#define D_READ_LTRNS_ERR_PID_UNK	(2 << 1)#define D_READ_LTRNS_ERR_UNEXP_PK	(3 << 1)#define D_READ_LTRNS_ERR_TOKCRC		(4 << 1)#define D_READ_LTRNS_ERR_DATACRC	(5 << 1)#define D_READ_LTRNS_ERR_TIMEOUT	(6 << 1)#define D_READ_LTRNS_ERR_NEVER		(7 << 1)#define D_READ_LTRNS_ERR_UNEXP_EOP	(8 << 1)#define D_READ_LTRNS_ERR_NAK		(9 << 1)#define D_READ_LTRNS_ERR_STALL		(10 << 1)#define D_READ_LTRNS_ERR_OVF		(11 << 1)#define D_READ_LTRNS_ERR_BITSTUFF	(13 << 1)#define D_READ_LTRNS_ERR_WRONG_DPID	(15 << 1)/* --- "Read endpoint status" --- */#define CMD_READ_ENDP_STATUS	0x80#define D_READ_ENDP_STAT_BUF0	0x20#define D_READ_ENDP_STAT_BUF1	0x40/* --- "Set address / enable" --- */#define CMD_SET_ADDR_EN		0xD0/* --- "Set endpoint enable" --- */#define CMD_SET_ENDP_EN		0xD8/* --- "Read buffer" --- */#define CMD_READ_BUFFER		0xF0/* --- "Write buffer" --- */#define CMD_WRITE_BUFFER	0xF0/* --- "Acknowledge setup" --- */#define CMD_ACKNOWLEDGE_SETUP	0xF1/* --- "Clear buffer" --- */#define CMD_CLEAR_BUFFER	0xF2/* --- "Set mode" --- */#define CMD_MODE		0xF3#define	D_MODE0_NOLAZYCLK	0x02#define	D_MODE0_CLKRUNNING	0x04#define D_MODE0_INTMODE		0x08#define D_MODE0_SOFTCONNECT	0x10#define D_MODE0_EP_NONISO	(0 << 6)#define D_MODE1_CLK4M		0x0B#define D_MODE1_SETTOONE	0x40#define D_MODE1_SOFONLY		0x80/* * default CLKOUT mode is: *	- lazy clock during standby *	- no clock running during standby *	- 4 MHz */#define D_MODE0_DEFAULT		D_MODE0_EP_NONISO#define D_MODE1_DEFAULT		(D_MODE1_SETTOONE | D_MODE1_CLK4M)/* --- "Read interrupt register" --- */#define CMD_READ_INT		0xF4#define D_READ_INT_EP0_O	0x0001#define D_READ_INT_EP0_I	0x0002#define D_READ_INT_EP1_O	0x0004#define D_READ_INT_EP1_I	0x0008#define D_READ_INT_EP2_O	0x0010#define D_READ_INT_EP2_I	0x0020#define D_READ_INT_BUSRESET	0x0040#define D_READ_INT_SUSPENDCHG	0x0080#define D_READ_INT_DMAEOT	0x0100/* --- "Read current frame number" --- */#define CMD_READ_FRAMENUM	0xF5/* --- "Validate buffer" --- */#define CMD_VALIDATE_BUFFER	0xFA/* --- "Set DMA" --- */#define CMD_DMA			0xFB#define D_DMA_NODMA		0x00#define D_DMA_INTMODE		0x20#define D_DMA_EPX4IE		0x40#define D_DMA_EPX5IE		0x80#define D_DMA_DEFAULT		D_DMA_NODMA/* * general constants */#define TIME_OUT	(HZ * 5)#define EP_CTRL		0#define EP_FREE		1#define EP_BULK		2#define EPX_CTRL_O	0#define EPX_CTRL_I	1#define EPX_FREE_O	2#define EPX_FREE_I	3#define EPX_BULK_O	4#define EPX_BULK_I	5#define EP_CTRL_SIZE	16#define EP_FREE_SIZE	16#define EP_BULK_SIZE	64/* --- */#define CONFIG_VAL	1#define DEF_LANG	0x0409/* ------------------------------------------------------------------------- *//* USB 1.1 */#define REQTYPE_DIR_M		0x80#define REQTYPE_DIR_OUT		(0 << 7)#define REQTYPE_DIR_IN		(1 << 7)#define REQTYPE_TYPE_M		0x60#define REQTYPE_TYPE_STANDARD	(0 << 5)#define REQTYPE_TYPE_CLASS	(1 << 5)#define REQTYPE_TYPE_VENDOR	(2 << 5)#define REQTYPE_RECP_M		0x1F#define REQTYPE_RECP_DEVICE	(0 << 0)#define REQTYPE_RECP_INTERFACE	(1 << 0)#define REQTYPE_RECP_ENDPOINT	(2 << 0)struct devreq {	__u8 bmRequestType;	__u8 bRequest;	__u16 wValue;	__u16 wIndex;	__u16 wLength;} __attribute__ ((packed));#define DESC_TYPE_DEVICE	1#define DESC_TYPE_CONFIGURATION	2#define DESC_TYPE_STRING	3#define DESC_TYPE_INTERFACE	4#define DESC_TYPE_ENDPOINT	5#define CLASS_MASS_STORAGE	0x08#define SUBCLASS_SCSI		0x06#define PROTOCOL_BULK		0x50#define STATUS_DEVICE_SELF_POWERED	0x01#define STATUS_DEVICE_REMOTE_WAKEUP	0x02#define STATUS_ENDPOINT_HALT		0x01#define FEATURE_ENDPOINT_HALT		0#define FEATURE_DEVICE_REMOTE_WAKEUP	1/* mass-storage, bulk-only */#define CBW_SIGNATURE		0x43425355#define CBW_FLAGS_DIR_M		0x80#define CBW_FLAGS_DIR_OUT	(0 << 7)#define CBW_FLAGS_DIR_IN	(1 << 7)struct cbw {	__u32 dCBWSignature;	__u32 dCBWTag;	__u32 dCBWDataTransferLength;	__u8 bmCBWFlags;	__u8 bCBWLUN;	__u8 bCBWCBLength;	__u8 CBWCB[16];} __attribute__ ((packed));#define CSW_SIGNATURE		0x53425355#define CSW_STAT_OK		0#define CSW_STAT_FAILED		1#define CSW_STAT_PHASE_ERROR	2struct csw {	__u32 dCSWSignature;	__u32 dCSWTag;	__u32 dCSWDataResidue;	__u8 bCSWStatus;} __attribute__ ((packed));/* ------------------------------------------------------------------------- *//* SCSI SPC-2 */#define SCSI_SKEY_NO_SENSE		0#define SCSI_SKEY_NOT_READY		2#define SCSI_SKEY_MEDIUM_ERROR		3#define SCSI_SKEY_ILLEGAL_REQUEST	5#define SCSI_ASC_NO				0x0000#define SCSI_ASC_LOGICAL_UNIT_NOT_READY		0x0400#define SCSI_ASC_WRITE_ERROR			0x0C02#define SCSI_ASC_UNRECOVERED_READ_ERROR		0x1100#define SCSI_ASC_INVALID_CMD			0x2000#define SCSI_ASC_LBA_OUT_OF_RANGE		0x2100#define SCSI_ASC_INVALID_FIELD_IN_CDB		0x2400#define SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED	0x2500#define MAX_SCSI_DATA_SENSE		18#define MAX_SCSI_DATA_INQUIRY		36#define MAX_SCSI_DATA_CAPACITY10	8#define MAX_SCSI_DATA_CAPACITY16	12/* ------------------------------------------------------------------------- *//* device I/O request */struct dioreq {	int cmd;				/* device i/o command */	int lun;	__u32 lba;	__u32 blks;	__u32 nblks;	void *buf;};/* device context */#define FSM_DEV_POWERED		0#define FSM_DEV_DEFAULT		1#define FSM_DEV_ADDRESS		2#define FSM_DEV_CONFIGURED	3#define FSM_CTL_IDLE		0#define FSM_CTL_DATA_IN		1#define FSM_CTL_STATUS_OUT	2#define FSM_CTL_STATUS_IN	3#define FSM_BULK_IDLE		0#define FSM_BULK_DATA_OUT	1#define FSM_BULK_DATA_OUT_WAIT	2#define FSM_BULK_DATA_IN	3#define FSM_BULK_DATA_IN_WAIT	4#define FSM_BULK_STALL_TO_CSW	5#define MAX_DBUF		256#define MAX_CHUNKBUF		65536#define ATD_STAT_READY		(1 << 0)#define ATD_STAT_RO		(1 << 1)#define DIO_CMD_EXIT		1#define DIO_CMD_READ		2#define DIO_CMD_WRITE		3#define DIO_CMD_VERIFY		4struct d12 {	unsigned int reg_cmd;	unsigned int reg_dat;	unsigned int irq;	const void *desc_dev;	int desc_dev_len;	const void *desc_cfg;	int desc_cfg_len;	int desc_str_max;	const void * const *desc_str;	const int *desc_str_len;	/* --- */	int max_lun;	const void *scsi_str_vendor[16];	const void *scsi_str_product[16];	const void *scsi_str_revision[16];	kdev_t atd_dev[16];			/* attached device */	int atd_blk[16];			/* block size */	int atd_chunkblk[16];			/* blocks per chunk */	__u32 atd_lba_capacity[16];		/* capacity in blocks */	int atd_stat[16];			/* status */	struct block_device *bdev[16];	/* --- */	int suspend;				/* 1- in suspend mode */	int feat_wakeup;			/* remote wakeup */	int fsm_dev;				/* device state */	int fsm_ctl;				/* control endpoint state */	int fsm_ctl_lastpkt;			/* last packet sent */	struct devreq drq;			/* device requests */	unsigned char dbuf[MAX_DBUF];		/* data buffer */	int dlen, dptr;	int fsm_bulk;				/* bulk endpoint state */	unsigned char *bbuf;			/* bulk buffer chunk */	int blen, bptr;	void (*bhd)(struct d12 *, int, int);	/* chunk handler */	int bxferlen, bxferptr;			/* total transfer length */	struct cbw cbw;				/* CBW request */	struct csw csw;				/* CSW answer */	int cswdelay;				/* postpone CSW sending */	int cswearly;				/* early CSW sending on error */	unsigned char scsi_sense[MAX_SCSI_DATA_SENSE];	/* should this be per LUN ? */	__u32 scsi_lba;	__u32 scsi_blks;	struct completion cpl_dio_sync;		/* enter / exit sync */	struct semaphore wait_dio_cmd;	volatile struct dioreq dio;	unsigned char tmp[256];			/* template */	unsigned char chunkbuf[MAX_CHUNKBUF];};struct d12 d12;/* ------------------------------------------------------------------------- */static __u16 get_u16be(const void *p){	const unsigned char *b;	__u16 r;	b = (const unsigned char *)p;	r = (b[0] << 8) |	    (b[1] << 0);	return r;}#if 0static void put_16be(void *p, __u16 d){	unsigned char *b;	b = (unsigned char *)p;	b[0] = (d >> 8) & 0xFF;	b[1] = (d >> 0) & 0xFF;}#endifstatic __u32 get_u32be(const void *p){	const unsigned char *b;	__u32 r;	b = (const unsigned char *)p;	r = (b[0] << 24) |	    (b[1] << 16) |	    (b[2] <<  8) |	    (b[3] <<  0);	return r;}static void put_32be(void *p, __u32 d){	unsigned char *b;	b = (unsigned char *)p;	b[0] = (d >> 24) & 0xFF;	b[1] = (d >> 16) & 0xFF;	b[2] = (d >>  8) & 0xFF;	b[3] = (d >>  0) & 0xFF;}static __u64 get_u64be(const void *p){	const unsigned char *b;	__u64 r;	b = (const unsigned char *)p;	r = get_u32be(b + 0);	r <<= 32;	r |= get_u32be(b + 4);	return r;}static void put_64be(void *p, __u64 d){	unsigned char *b;	b = (unsigned char *)p;	put_32be(b + 0, d >> 32);	put_32be(b + 4, d >>  0);}/* ------------------------------------------------------------------------- *//* * low-level PDIUSBD12 */static inline void d12_outc(struct d12 *p, int cmd){	__delay();	__raw_writeb(cmd, p->reg_cmd);}static inline void d12_outd(struct d12 *p, int dat){	__delay();	__raw_writeb(dat, p->reg_dat);}static inline int d12_ind(struct d12 *p){	__delay();	return __raw_readb(p->reg_dat);}/* --- */static inline void d12_out1(struct d12 *p, int cmd, int d0){	d12_outc(p, cmd);	d12_outd(p, d0);}static inline void d12_out2(struct d12 *p, int cmd, int d0, int d1){	d12_outc(p, cmd);	d12_outd(p, d0);	d12_outd(p, d1);}static inline int d12_in1(struct d12 *p, int cmd){	d12_outc(p, cmd);	return d12_ind(p);}static inline int d12_in2(struct d12 *p, int cmd){	int d0, d1;	d12_outc(p, cmd);	d0 = d12_ind(p);	d1 = d12_ind(p);	return (d1 << 8) | d0;}/* --- *//* clear buffer */static void d12_buf_clear(struct d12 *p){	d12_outc(p, CMD_CLEAR_BUFFER);}/* validate buffer */static void d12_buf_validate(struct d12 *p){	d12_outc(p, CMD_VALIDATE_BUFFER);}/* get frame number */#if 0static int d12_frame(struct d12 *p){	return d12_in2(p, CMD_READ_FRAMENUM) & 0x7FF;}#endif/* read last transaction status and ack interrupt */static int d12_read_last_trans(struct d12 *p, int epx){	return d12_in1(p, CMD_READ_LTRNS + epx);}/* set data pointer to start of internal buffer */static int d12_select_endpoint(struct d12 *p, int epx){	return d12_in1(p, CMD_SELECT_ENDP + epx);}/* set USB address (0x00 .. 0x7F) and enable */static void d12_set_address_enable(struct d12 *p, int adr, int en){	d12_out1(p, CMD_SET_ADDR_EN, adr | (en ? 0x80 : 0x00));}/* enable generic/isochronous endpoints */static void d12_set_endpoint_enable(struct d12 *p, int en){	d12_out1(p, CMD_SET_ENDP_EN, en ? 0x01 : 0x00);}/* get endpoint status */static int d12_status_get(struct d12 *p, int epx){	return d12_in1(p, CMD_READ_ENDP_STATUS + epx);}/* unconditionally initialize / stall endpoint */static void d12_status_set(struct d12 *p, int epx, int stall){	d12_out1(p, CMD_SET_ENDP_STATUS + epx, stall);}/* --- *//* stall / unstall */static void d12_stall_ctrl(struct d12 *p, int stall){	d12_status_set(p, EPX_CTRL_O, stall);	d12_status_set(p, EPX_CTRL_I, stall);}static void d12_stall_free(struct d12 *p, int stall){	d12_status_set(p, EPX_FREE_O, stall);	d12_status_set(p, EPX_FREE_I, stall);}static void d12_stall_bulk(struct d12 *p, int stall){	d12_status_set(p, EPX_BULK_O, stall);	d12_status_set(p, EPX_BULK_I, stall);}/* connect / disconnect */static void d12_connect(struct d12 *p, int on){	d12_out2(p, CMD_MODE, D_MODE0_DEFAULT | (on ? D_MODE0_SOFTCONNECT : 0), D_MODE1_DEFAULT);}/* after bus-reset */static void d12_reset(struct d12 *p){	d12_set_address_enable(p, 0, 1);	d12_set_endpoint_enable(p, 0);	d12_stall_ctrl(p, 1);	d12_stall_free(p, 1);	d12_stall_bulk(p, 1);}/* initialize */static void d12_init(struct d12 *p){	d12_connect(p, 0);	d12_out1(p, CMD_DMA, D_DMA_DEFAULT | D_DMA_EPX4IE | D_DMA_EPX5IE);	d12_reset(p);	d12_connect(p, 1);}/* acknowledge setup on endpoint #0 */static void d12_acknowledge_setup(struct d12 *p){	d12_select_endpoint(p, EPX_CTRL_O);	d12_outc(p, CMD_ACKNOWLEDGE_SETUP);	d12_select_endpoint(p, EPX_CTRL_I);	d12_outc(p, CMD_ACKNOWLEDGE_SETUP);}/* read buffer */static int d12_buf_read(struct d12 *p, int epx, void *buf, int max){	int i, l, len, stat;	unsigned char *b;	b = (unsigned char *)buf;	if (epx == EPX_BULK_O) {		stat = d12_status_get(p, epx);		i = len = 0;		if (stat & D_READ_ENDP_STAT_BUF0)			i++;		if (stat & D_READ_ENDP_STAT_BUF1)			i++;		while (i-- && (max - len)) {			d12_select_endpoint(p, epx);			d12_in1(p, CMD_READ_BUFFER);			l = d12_ind(p);			if (len + l > max)				l = max - len;			len += l;			while (l--)				*b++ = d12_ind(p);			d12_buf_clear(p);		}	} else {		d12_select_endpoint(p, epx);		d12_in1(p, CMD_READ_BUFFER);		l = d12_ind(p);		if (l > max)			l = max;		len = l;

⌨️ 快捷键说明

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