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

📄 edb7312-usb.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		return;	if (p->fsm_dev < FSM_DEV_DEFAULT)		goto err;	drq = &p->drq;	if (stat & D_READ_LTRNS_SETUP) {	/* new transfer */		len = d12_buf_read(p, EPX_CTRL_O, drq, sizeof(struct devreq));		if (len != sizeof(struct devreq))			goto err;		d12_acknowledge_setup(p);		d12_select_endpoint(p, EPX_CTRL_O);		d12_buf_clear(p);		req = drq->bRequest;		switch (drq->bmRequestType & REQTYPE_TYPE_M) {		case REQTYPE_TYPE_STANDARD:			if (req >= MAX_REQ_STANDARD)				goto err;			if ((T_STD_SETUP[req])(p))				goto err;			break;		case REQTYPE_TYPE_CLASS:			if (p->fsm_dev != FSM_DEV_CONFIGURED)				goto err;			req = 255 - req;			if (req >= MAX_REQ_CLASS)				goto err;			if ((T_CLS_SETUP[req])(p))				goto err;			break;		default:			goto err;		}	} else {				/* host -> d12 data */		switch (p->fsm_ctl) {		case FSM_CTL_STATUS_OUT:			d12_stall_ctrl(p, 1);			p->fsm_ctl = FSM_CTL_IDLE;			break;		default:			goto err;		}	}	return;err:	d12_stall_ctrl(p, 1);			/* stall EP0 */	p->fsm_ctl = FSM_CTL_IDLE;}static void ep0_tx(struct d12 *p){	struct devreq *drq;	int stat, len;	stat = d12_read_last_trans(p, EPX_CTRL_I);	if (!(stat & D_READ_LTRNS_SUCCESS))		return;	if (p->fsm_dev < FSM_DEV_DEFAULT)		goto err;	drq = &p->drq;	switch (p->fsm_ctl) {	case FSM_CTL_DATA_IN:		len = p->dlen - p->dptr;		if (len > EP_CTRL_SIZE)			len = EP_CTRL_SIZE;		d12_buf_write(p, EPX_CTRL_I, p->dbuf + p->dptr, len);		p->dptr += len;		if (p->dptr == p->dlen)			p->fsm_ctl = FSM_CTL_STATUS_OUT;		p->fsm_ctl_lastpkt = len;		break;	case FSM_CTL_STATUS_OUT:		if (p->fsm_ctl_lastpkt == EP_CTRL_SIZE) {			d12_buf_write(p, EPX_CTRL_I, 0, 0);			p->fsm_ctl_lastpkt = 0;		}		break;	case FSM_CTL_STATUS_IN:		d12_stall_ctrl(p, 1);		p->fsm_ctl = FSM_CTL_IDLE;		break;	default:		goto err;	}	return;err:	d12_stall_ctrl(p, 1);			/* stall EP0 */	p->fsm_ctl = FSM_CTL_IDLE;}static void ep1_rx(struct d12 *p)		/* free endpoint */{	d12_read_last_trans(p, EPX_FREE_O);	d12_stall_free(p, 1);			/* stall EP1 */}static void ep1_tx(struct d12 *p)		/* free endpoint */{	d12_read_last_trans(p, EPX_FREE_I);	d12_stall_free(p, 1);			/* stall EP1 */}static void ep2_rx(struct d12 *p){	struct cbw *cbw;	struct csw *csw;	int stat, len, lun, clen, cmd, r;	stat = d12_read_last_trans(p, EPX_BULK_O);	if (!(stat & D_READ_LTRNS_SUCCESS))		return;	if (p->fsm_dev != FSM_DEV_CONFIGURED)		goto err;	cbw = &p->cbw;	csw = &p->csw;	switch (p->fsm_bulk) {	case FSM_BULK_IDLE:		len = d12_buf_read(p, EPX_BULK_O, cbw, sizeof(struct cbw));		if (len != sizeof(struct cbw))			goto err;		lun = cbw->bCBWLUN;		clen = cbw->bCBWCBLength;		cmd = cbw->CBWCB[0];		if ((cbw->dCBWSignature != CBW_SIGNATURE) || !clen || (clen > sizeof(cbw->CBWCB)))			goto err;		p->bhd = 0;		p->bxferlen = p->bxferptr = 0;		p->cswdelay = p->cswearly = 0;		csw->dCSWSignature = CSW_SIGNATURE;		csw->dCSWTag = cbw->dCBWTag;		csw->dCSWDataResidue = 0;		csw->bCSWStatus = CSW_STAT_OK;		if (lun >= p->max_lun) {			csw->bCSWStatus = CSW_STAT_FAILED;			scsi_sense_set(p, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED);			bulk_xfer(p, BULK_NONE, 0, 0);		} else if ((!T_SCSI_HD[cmd].len || (T_SCSI_HD[cmd].len == clen)) && T_SCSI_HD[cmd].hd) {			r = T_SCSI_HD[cmd].hd(p, lun);			if (r && (r != SCHD_ERR_PHASE)) {				csw->bCSWStatus = CSW_STAT_FAILED;				if (r == SCHD_ERR_INVALID_CDB)					scsi_sense_set(p, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASC_INVALID_FIELD_IN_CDB);				else if (r == SCHD_ERR_INVALID_LBA)					scsi_sense_set(p, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASC_LBA_OUT_OF_RANGE);				bulk_xfer(p, BULK_NONE, 0, 0);			}		} else {			csw->bCSWStatus = CSW_STAT_FAILED;			scsi_sense_set(p, SCSI_SKEY_ILLEGAL_REQUEST, SCSI_ASC_INVALID_CMD);			bulk_xfer(p, BULK_NONE, 0, 0);		}		if (!p->bxferlen && !p->cswdelay)			csw_write(p);		break;	case FSM_BULK_DATA_OUT:		len = p->blen - p->bptr;		len = d12_buf_read(p, EPX_BULK_O, p->bbuf + p->bptr, len);		p->bptr += len;		p->bxferptr += len;		if (p->bptr == p->blen) {			lun = cbw->bCBWLUN;			if (p->bhd)				p->bhd(p, lun, p->blen);			p->fsm_bulk = FSM_BULK_DATA_OUT_WAIT;		}		break;	case FSM_BULK_DATA_OUT_WAIT:		break;	default:		goto err;	}	return;err:	d12_stall_bulk(p, 1);			/* stall EP2 */	p->fsm_bulk = FSM_BULK_IDLE;}static void ep2_tx(struct d12 *p){	struct cbw *cbw;	int stat, len, lun;	stat = d12_read_last_trans(p, EPX_BULK_I);	if (!(stat & D_READ_LTRNS_SUCCESS))		return;	if (p->fsm_dev != FSM_DEV_CONFIGURED)		goto err;	cbw = &p->cbw;	switch (p->fsm_bulk) {	case FSM_BULK_IDLE:			/* CSW ack */		break;	case FSM_BULK_DATA_IN:		len = p->blen - p->bptr;		if (len) {			len = d12_buf_write(p, EPX_BULK_I, p->bbuf + p->bptr, len);			p->bptr += len;			p->bxferptr += len;		} else {			stat = d12_status_get(p, EPX_BULK_I);			stat &= D_READ_ENDP_STAT_BUF0 | D_READ_ENDP_STAT_BUF1;			if (!stat) {				if ((p->bxferptr == p->bxferlen) || p->cswearly)					csw_write(p);				else {					p->fsm_bulk = FSM_BULK_DATA_IN_WAIT;					lun = cbw->bCBWLUN;					if (p->bhd)						p->bhd(p, lun, p->blen);				}			}		}		break;	default:		goto err;	}	return;err:	d12_stall_bulk(p, 1);			/* stall EP2 */	p->fsm_bulk = FSM_BULK_IDLE;}static void usbd12_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct d12 *p;	int ints;	p = (struct d12 *)dev_id;	ints = d12_in2(p, CMD_READ_INT);	if (ints & D_READ_INT_BUSRESET) {		d12_reset(p);		p->feat_wakeup = 0;		p->fsm_dev = FSM_DEV_DEFAULT;		p->fsm_ctl = FSM_CTL_IDLE;	}	if (ints & D_READ_INT_SUSPENDCHG)		p->suspend = GPIO_D12_SUSP;	if (ints & D_READ_INT_EP0_I)		/* host <- d12 ack, control */		ep0_tx(p);	if (ints & D_READ_INT_EP0_O)		/* host -> d12, control */		ep0_rx(p);	if (ints & D_READ_INT_EP1_I)		/* host <- d12 ack, bulk */		ep1_tx(p);	if (ints & D_READ_INT_EP1_O)		/* host -> d12, bulk */		ep1_rx(p);	if (ints & D_READ_INT_EP2_I)		/* host <- d12 ack, bulk */		ep2_tx(p);	if (ints & D_READ_INT_EP2_O)		/* host -> d12, bulk */		ep2_rx(p);}/* ------------------------------------------------------------------------- *//* * device I/O thread */static int dio_thread(void *arg){	struct d12 *p;	volatile struct dioreq *dio;	int cmd, lun;	__u32 lba, blks, nblks, i;	unsigned char *buf;	struct buffer_head *bh;	p = (struct d12 *)arg;	dio = &p->dio;	daemonize();	reparent_to_init();	strcpy(current->comm, "kusbd12");	current->nice = -20;#if 0	spin_lock_irq(&current->sigmask_lock);	sigemptyset(&current->blocked);	recalc_sigpending(current);	spin_unlock_irq(&current->sigmask_lock);#endif	complete(&p->cpl_dio_sync);		/* initialized */	for ( ; ; ) {		down(&p->wait_dio_cmd);#if 0		if (signal_pending(current)) {			spin_lock_irq(&current->sigmask_lock);			flush_signals(current);			spin_unlock_irq(&current->sigmask_lock);		}#endif		d12_lock(p);		cmd = dio->cmd;		lun = dio->lun;		lba = dio->lba;		blks = dio->blks;		nblks = dio->nblks;		buf = (unsigned char *)dio->buf;		d12_unlock(p);		if (cmd == DIO_CMD_EXIT)			break;		switch (cmd) {		case DIO_CMD_READ:			for (i = 0 ; i < blks ; i++) {				bh = bread(p->atd_dev[lun], lba, p->atd_blk[lun]);				if (!bh)					break;				memcpy(buf + i * p->atd_blk[lun], bh->b_data, p->atd_blk[lun]);				brelse(bh);				lba++;			}						d12_lock(p);			ep_bulk_write(p, buf, i * p->atd_blk[lun]);			if (i != blks) {				scsi_sense_lba_set(p, lba, SCSI_ASC_UNRECOVERED_READ_ERROR);				p->cswearly = 1;			}			d12_unlock(p);			break;		case DIO_CMD_WRITE:			for (i = 0 ; i < blks ; i++) {				bh = getblk(p->atd_dev[lun], lba, p->atd_blk[lun]);				if (!bh)					break;				memcpy(bh->b_data, buf + i * p->atd_blk[lun], p->atd_blk[lun]);				mark_buffer_uptodate(bh, 1);				mark_buffer_dirty(bh);				ll_rw_block(WRITE, 1, &bh);				wait_on_buffer(bh);				brelse(bh);				lba++;			}			d12_lock(p);			if (i != blks) {				scsi_sense_lba_set(p, lba, SCSI_ASC_WRITE_ERROR);				csw_write(p);			} else if (nblks)				ep_bulk_read(p, buf, nblks * p->atd_blk[lun]);			else				csw_write(p);			d12_unlock(p);			break;		case DIO_CMD_VERIFY:			for (i = 0 ; i < blks ; i++) {				bh = bread(p->atd_dev[lun], lba, p->atd_blk[lun]);				if (!bh)					goto vfyerr;				brelse(bh);				lba++;			}vfyerr:			d12_lock(p);			if (i != blks)				scsi_sense_lba_set(p, lba, SCSI_ASC_UNRECOVERED_READ_ERROR);			csw_write(p);			d12_unlock(p);			break;		}	}	complete_and_exit(&p->cpl_dio_sync, 0);}/* ------------------------------------------------------------------------- */#define w(x) ((x) & 0xFF), (((x) >> 8) & 0xFF)#define u(x) (x), 0#define MAX_DESC_STR		6#define STR_MANUFACTURER	1#define STR_PRODUCT		2#define STR_SERIALNUM		3#define STR_CONFIG		4#define STR_INTERFACE		5static const unsigned char T_DESC_STR_0[] = {	4,				/* bLength */	DESC_TYPE_STRING,		/* bDescriptorType */	w(DEF_LANG)			/* (english, US) */};static const unsigned char T_DESC_STR_1[] = {	26,				/* bLength */	DESC_TYPE_STRING,		/* bDescriptorType */	u('C'),				/* (manufacturer) */	u('i'),	u('r'),	u('r'),	u('u'),	u('s'),	u(' '),	u('L'),	u('o'),	u('g'),	u('i'),	u('c')};static const unsigned char T_DESC_STR_2[] = {	16,				/* bLength */	DESC_TYPE_STRING,		/* bDescriptorType */	u('e'),				/* (product) */	u('d'),	u('b'),	u('7'),	u('3'),	u('1'),	u('2')};static const unsigned char T_DESC_STR_3[] = {	26,				/* bLength */	DESC_TYPE_STRING,		/* bDescriptorType */	u('0'),				/* (serial number) */	u('0'),	u('0'),	u('0'),	u('0'),	u('0'), 	u('0'),	u('0'),	u('0'),	u('0'),	u('0'),	u('0')};static const unsigned char T_DESC_STR_4[] = {	10,				/* bLength */	DESC_TYPE_STRING,		/* bDescriptorType */	u('c'),				/* (configuration) */	u('f'),	u('g'),	u('0')};static const unsigned char T_DESC_STR_5[] = {	8,				/* bLength */	DESC_TYPE_STRING,		/* bDescriptorType */	u('i'),				/* (interface) */	u('f'),	u('0')};static const void * const T_DESC_STR[MAX_DESC_STR] = {	T_DESC_STR_0,	T_DESC_STR_1,	T_DESC_STR_2,	T_DESC_STR_3,	T_DESC_STR_4,	T_DESC_STR_5};static const int T_DESC_STR_LEN[MAX_DESC_STR] = {	sizeof(T_DESC_STR_0),	sizeof(T_DESC_STR_1),	sizeof(T_DESC_STR_2),	sizeof(T_DESC_STR_3),	sizeof(T_DESC_STR_4),	sizeof(T_DESC_STR_5)};static const unsigned char T_DESC_DEV[] = {	/* --- device descriptor --- */	18,				/* bLength */	DESC_TYPE_DEVICE,		/* bDescriptorType */	0x01, 0x01,			/* bcdUSB */	0,				/* bDeviceClass */	0,				/* bDeviceSubClass */	0,				/* bDeviceProtocol */	EP_CTRL_SIZE,			/* bMaxPacketSize0 */	0xDB, 0xCE,			/* idVendor */	0x12, 0x73,			/* idProduct */	0x00, 0x01,			/* bcdDevice */	STR_MANUFACTURER,		/* iManufacturer */	STR_PRODUCT,			/* iProduct */	STR_SERIALNUM,			/* iSerialNumber */	1				/* bNumConfigurations */};static const unsigned char T_DESC_CFG[] = {	/* --- configuration descriptor --- */	9,				/* bLength */	DESC_TYPE_CONFIGURATION,	/* bDescriptorType */	w(9 + 9 + 7 + 7),		/* wTotalLength */	1,				/* bNumInterfaces */	CONFIG_VAL,			/* bConfigurationValue */	STR_CONFIG,			/* iConfiguration */	0xE0,				/* bmAttributes */	0,				/* MaxPower (0 mA) */	/* --- interface descriptor --- */	9,				/* bLength */	DESC_TYPE_INTERFACE,		/* bDescriptorType */	0,				/* bInterfaceNumber */	0,				/* bAlternateSetting */	2,				/* bNumEndpoints */	CLASS_MASS_STORAGE,		/* bInterfaceClass (mass-storage) */	SUBCLASS_SCSI,			/* bInterfaceSubClass (scsi) */	PROTOCOL_BULK,			/* bInterfaceProtocol (bulk) */	STR_INTERFACE,			/* iInterface */	/* --- out endpoint descriptor --- */	7,				/* bLength */	DESC_TYPE_ENDPOINT,		/* bDescriptorType */	EP_BULK | 0x00,			/* bEndpointAddress */	0x02,				/* bmAttributes (bulk) */	w(EP_BULK_SIZE),		/* wMaxPacketSize */	0,				/* bInterval */	/* --- in endpoint descriptor --- */	7,				/* bLength */	DESC_TYPE_ENDPOINT,		/* bDescriptorType */	EP_BULK | 0x80,			/* bEndpointAddress */	0x02,				/* bmAttributes (bulk) */	w(EP_BULK_SIZE),		/* wMaxPacketSize */	0				/* bInterval */};#undef w#undef ustatic const char T_STR_SCSI_VENDOR[] = "CIRRUSL ";static const char T_STR_SCSI_PRODUCT[] = "EDB7312         ";static const char T_STR_SCSI_REVISION[] = "0000";/* --- */static int thread_init(struct d12 *p){	int r;	init_completion(&p->cpl_dio_sync);	sema_init(&p->wait_dio_cmd, 0);	r = kernel_thread(dio_thread, p, 0);	if (r < 0) {		printk("%s: couldn't spawn thread\n", __FUNCTION__);		return r;	}	wait_for_completion(&p->cpl_dio_sync);	/* wait thread initialize */	return 0;}static void thread_exit(struct d12 *p){	p->dio.cmd = DIO_CMD_EXIT;	up(&p->wait_dio_cmd);	wait_for_completion(&p->cpl_dio_sync);	/* wait thread exit */}static void dev_add(struct d12 *p, kdev_t dev){	int lun, maj, min;	lun = p->max_lun;	if (lun == 16) {		printk("ignored, limit of 16 reached\n");		goto err0;	}	maj = MAJOR(dev);	min = MINOR(dev);	printk("%s: dev %u:%u - ", ID, maj, min);	if (is_mounted(dev)) {		printk("ignored, mounted\n");		goto err0;	}	p->bdev[lun] = bdget(dev);	if (!p->bdev[lun]) {		printk("ignored, no memory\n");		goto err0;	}	if (blkdev_get(p->bdev[lun], FMODE_READ | FMODE_WRITE, 0, BDEV_RAW)) {		printk("ignored, blkdev_get() error\n");		goto err0;	}	p->scsi_str_vendor[lun] = T_STR_SCSI_VENDOR;	p->scsi_str_product[lun] = T_STR_SCSI_PRODUCT;	p->scsi_str_revision[lun] = T_STR_SCSI_REVISION;	p->atd_dev[lun] = dev;	p->atd_blk[lun] = get_hardsect_size(dev);	if (!p->atd_blk[lun] || (p->atd_blk[lun] > MAX_CHUNKBUF)) {		printk("ignored (bogus sector size %u)\n", p->atd_blk[lun]);		goto err1;	}	if (set_blocksize(dev, p->atd_blk[lun])) {		printk("ignored, set_blocksize() error\n");		goto err1;	}	p->atd_chunkblk[lun] = MAX_CHUNKBUF / p->atd_blk[lun];	p->atd_lba_capacity[lun] = 0;	if (blk_size[maj])		p->atd_lba_capacity[lun] = blk_size[maj][min];	if (!p->atd_lba_capacity[lun]) {		printk("ignored (zero size)\n");		goto err1;	}	p->atd_stat[lun] = ATD_STAT_READY;	printk("added %s\n", (p->atd_stat[lun] & ATD_STAT_RO) ? "read-only" : "read-write");	p->max_lun++;	return;err1:	blkdev_put(p->bdev[lun], BDEV_RAW);err0:	return;}static void dev_del(struct d12 *p){	int lun;	for (lun = 0 ; lun < p->max_lun ; lun++) {		blkdev_put(p->bdev[lun], BDEV_RAW);	}}int __init usbd12_init_module(void){	struct d12 *p;	int r = -EINVAL;	printk("PDIUSBD12 / mass-storage support for EDB7312\n");	/* prepare context */	p = &d12;	p->reg_cmd = REG_D12_CMD;	p->reg_dat = REG_D12_DAT;	p->irq = IRQ_D12;	p->desc_dev = T_DESC_DEV;	p->desc_dev_len = sizeof(T_DESC_DEV);	p->desc_cfg = T_DESC_CFG;	p->desc_cfg_len = sizeof(T_DESC_CFG);	p->desc_str_max = MAX_DESC_STR;	p->desc_str = T_DESC_STR;	p->desc_str_len = T_DESC_STR_LEN;	/* attach devices */	dev_add(p, MKDEV(1, 1));		/* /dev/ram1 */#if 0	dev_add(p, MKDEV(3, 1));		/* /dev/hda1 */	dev_add(p, MKDEV(3, 65));		/* /dev/hdb1 */#endif	if (!p->max_lun) {		printk("%s: no devices attached, skipping driver loading\n", ID);		goto err0;	}	r = thread_init(p);	if (r)		goto err1;	d12_init(p);	p->suspend = GPIO_D12_SUSP;	r = request_irq(p->irq, usbd12_interrupt, SA_SHIRQ, "pdiusbd12", p);	if (r) {		printk("%s: couldn't allocate IRQ %u\n", ID, p->irq);		goto err2;	}        edb7312_enable_eint1();	return 0;err2:	thread_exit(p);err1:	dev_del(p);err0:	return r;}static void __exit usbd12_exit_module(void){	struct d12 *p;	p = &d12;	free_irq(p->irq, p);	thread_exit(p);	dev_del(p);}module_init(usbd12_init_module);module_exit(usbd12_exit_module);MODULE_AUTHOR("Vladimir Ivanov <vladitx@nucleusys.com>");MODULE_DESCRIPTION("PDIUSBD12 / mass-storage support for EDB7312");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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