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

📄 usbdrv.c

📁 软USB核的电力开关PowerSwitch
💻 C
字号:
/* Name: usbdrv.c * Project: AVR USB driver * Author: Christian Starkjohann * Creation Date: 2004-12-29 * Tabsize: 4 * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH * License: Proprietary, free under certain conditions. See Documentation. * This Revision: $Id: usbdrv.c 20 2005-02-20 16:39:43Z cs $ */#include <avr/io.h>#include <avr/pgmspace.h>#include "usbdrv.h"#include "oddebug.h"/*General Description:This module implements the C-part of the USB driver. See usbdrv.h for adocumentation of the entire driver.*//* ------------------------------------------------------------------------- *//* raw USB registers / interface to assembler code: *//* usbRxBuf MUST be in 1 byte addressable range (because usbInputBuf is only 1 byte) */static char	usbRxBuf[2][USB_BUFSIZE];/* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */uchar		usbNDeviceId = 0xff;/* inverted, assigned during enumeration, defaults to 0xff */uchar		usbInputBuf;		/* ptr to raw buffer used for receiving */uchar		usbAppBuf;			/* ptr to raw buffer passed to app for processing */char		usbRxLen;			/* = 0; number of bytes in usbAppBuf; 0 means free */uchar		usbCurrentTok;		/* last token received (inverse of) */uchar		usbRxToken;			/* token for data we received */char		usbMsgLen = -1;		/* remaining number of bytes, no msg to send if negative (see usbMsgPtr) */char		usbTxLen = -1;		/* number of bytes to transmit with next IN token */uchar		usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen == -1 */#ifdef USB_HAVE_ENDPOINT1uchar		usbRxEndp;			/* endpoint which was addressed (1 bit in MSB) */char		usbTxLen1 = -1;		/* TX count for endpoint 1 */uchar		usbTxBuf1[USB_BUFSIZE];/* TX data for endpoint 1 */#endifuchar		usbAckBuf[1] = {USBPID_ACK};	/* transmit buffer for ack tokens */uchar		usbNakBuf[1] = {USBPID_NAK};	/* transmit buffer for nak tokens *//* USB status registers / not shared with asm code */static uchar	*usbMsgPtr;		/* data to transmit next -- ROM or RAM address */static char		usbPkgCount;	/* counts data packets, negative if ROM address -- reset for new msg */static uchar	usbNewDeviceId;	/* = 0; device ID which should be set after status phase */static uchar	usbIsReset;		/* = 0; USB bus is in reset phase *//*optimizing hints:- do not post/pre inc/dec integer values in operations- assign value of PRG_RDB() to register variables and don't use side effects in arg- use narrow scope for variables which should be in X/Y/Z register- assign char sized expressions to variables to force 8 bit arithmetics*//* ------------------------------------------------------------------------- */static char	usbDescrDevice[] PROGMEM = {	/* USB device descriptor */	18,			/* sizeof(usbDescrDevice): length of descriptor in bytes */	1,			/* descriptor type */	0x01, 0x01,	/* USB version supported */	0xff,		/* device class */	0,			/* device subclass */	0,			/* protocol */	8,			/* max packet size */	0xeb, 0x03,	/* vendor ID: 0x03eb = ATMEL */	0x53, 0x6a,	/* device ID */	0x00, 0x01,	/* device version number */	1,			/* manufacturer string index */	2,			/* product string index */	0,			/* serial number string index */	1,			/* number of configurations */};static char	usbDescrConfig[] PROGMEM = {	/* USB configuration descriptor */	9,			/* sizeof(usbDescrConfig): length of descriptor in bytes */	2,			/* descriptor type */	18, 0,		/* total length of data returned (including inlined descriptors) */	1,			/* number of interfaces in this configuration */	1,			/* index of this configuration */	0,			/* configuration name string index */#if USB_IS_SELFPOWERED	USBATTR_SELFPOWER,	/* attributes */#else	USBATTR_BUSPOWER,	/* attributes */#endif	10,			/* max USB current in 2mA units *//* interface descriptor follows inline: */	9,			/* sizeof(usbDescrInterface): length of descriptor in bytes */	4,			/* descriptor type */	0,			/* index of this interface */	0,			/* alternate setting for this interface */	0,			/* endpoints excl 0: number of endpoint descriptors to follow */	0,			/* interface class */	0,			/* interface subclass */	0,			/* interface protocol */	0,			/* string index for interface *//* endpoint descriptors would follow inline */};static char	usbDescrString0[] PROGMEM = {	/* language descriptor */	4,			/* sizeof(usbDescrString0): length of descriptor in bytes */	3,			/* descriptor type */	0x09, 0x04,	/* language index (0x0409 = US-English) */};static int	usbDescrString1[] PROGMEM = {	26 | (3<<8),	/* length of descriptor in bytes | descriptor type */	'w', 'w', 'w', '.', 'o', 'b', 'd', 'e', 'v', '.', 'a', 't'};static int	usbDescrString2[] PROGMEM = {	24 | (3<<8),	/* length of descriptor in bytes | descriptor type */	'P', 'o', 'w', 'e', 'r', 'S', 'w', 'i', 't', 'c', 'h',};/* We don't use prog_int or prog_int16_t for compatibility with older libc * versions. *//* ------------------------------------------------------------------------- */void	usbSendMsg(uchar *data, uchar len, uchar options){	usbMsgPtr = data;	usbMsgLen = len;	usbTxLen = -1;	/* abort any pending sends */	usbPkgCount = options;}static void	usbProcessRx(uchar *data, uchar len){/* We use if() cascades because the compare is done byte-wise while switch() * is int-based. The if() cascades are therefore more efficient. */	DBG2(0x10 + (usbRxToken == (uchar)~USBPID_SETUP), data, len);	if(usbRxToken == (uchar)~USBPID_SETUP){		static uchar statusReply[2];		uchar *replyData = statusReply, replyLen = 0, replyOptions = USBSND_DATA1_RAM;		uchar recipient = data[0] & 0x1f;	/* assign arith ops to variables to enforce byte size */		uchar type = data[0] & (3 << 5);		if(len == 8){	/* all valid setup requests have length 8 */			if(type == USBRQ_TYPE_STANDARD << 5){				if(data[1] == 0){/* GET_STATUS */					statusReply[1] = 0;					statusReply[0] = recipient == USBRQ_RCPT_DEVICE ? USB_IS_SELFPOWERED : 0;					replyLen = 2;				}else if(data[1] == 5){	/* SET_ADDRESS */					usbNewDeviceId = data[2];				}else if(data[1] == 6){	/* GET_DESCRIPTOR */					replyOptions = USBSND_DATA1_ROM;					if(data[3] == 1){	/* descriptor type requested */						replyData = (uchar *)usbDescrDevice;						replyLen = sizeof(usbDescrDevice);					}else if(data[3] == 2){						replyData = (uchar *)usbDescrConfig;						replyLen = sizeof(usbDescrConfig);					}else if(data[3] == 3){	/* string descriptor */						if(data[2] == 0){	/* descriptor index */							replyData = (uchar *)usbDescrString0;							replyLen = sizeof(usbDescrString0);						}else if(data[2] == 1){							replyData = (uchar *)usbDescrString1;							replyLen = sizeof(usbDescrString1);						}else if(data[2] == 2){							replyData = (uchar *)usbDescrString2;							replyLen = sizeof(usbDescrString2);						}					}				}else if(data[1] == 8){	/* GET_CONFIGURATION */					statusReply[0] = 1;	/* no config required */					replyLen = 1;				}else if(data[1] == 10){	/* GET_INTERFACE */					statusReply[0] = 0;					replyLen = 1;				}else{					/* the following requests can be ignored, send default reply */					/* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */					/* 9: SET_CONFIGURATION, 11: SET_INTERFACE, 12: SYNCH_FRAME */				}			}else if(type == USBRQ_TYPE_VENDOR << 5){				replyLen = usbVendorSetup(data, statusReply);			}		}		if(!data[7] && replyLen > data[6]){	/* max length is in data[7]:data[6] */			replyLen = data[6];		}		usbSendMsg(replyData, replyLen, replyOptions);	/* send reply */	}else{	/* out request */		if(len == 0){	/* ACK -- to SETUP answer */			/* just ignore */		}	}}/* ------------------------------------------------------------------------- */static void	usbBuildTxBlock(void){uchar		len, i, *p, *r;unsigned	crc;	i = USBPID_DATA0;	if(usbPkgCount & 1)		i = USBPID_DATA1;	usbTxBuf[0] = i;	usbPkgCount++;	/* do not post-inc above because gcc produces bad code */	if(usbMsgLen >= 8){		len = 8;		usbMsgLen -= len;	}else{	/* this is the final terminating block */		len = usbMsgLen;		usbMsgLen = -1;	}	if(len < 128){	/* transmit may have been aborted due to reception of out or setup token */		i = len;		p = &usbTxBuf[1];		r = usbMsgPtr;		if(usbPkgCount < 0){	/* ROM data */			while(i--){				char c = PRG_RDB(r);	/* use separate statement -- compiler does not like PRG_RDB() */				*p++ = c;				r++;			}		}else{					/* RAM data */			while(i--)				*p++ = *r++;		}		usbMsgPtr = r;		crc = usbCrc16(&usbTxBuf[1], len);		*p++ = crc;		*p++ = crc >> 8;		usbTxLen = len + 4;	/* len must be given including sync byte */		DBG2(0x20, usbTxBuf, usbTxLen-1);	}}static inline uchar	isNotSE0(void){uchar	rval;/* We want to do *     return (USBIN & USBMASK); * here, but the compiler does int-expansion acrobatics. * We can avoid this by assigning to a char-sized variable. */	rval = USBIN & USBMASK;	return rval;}/* ------------------------------------------------------------------------- */void	usbPoll(void){uchar	i, *p;	if(usbRxLen > 0){		p = (uchar *)(unsigned)(usbAppBuf);		i = usbRxLen;		do{			*p = ~*p;			p++;		}while(--i);/* We could check CRC16 here -- but ACK has already been sent anyway. If you * need data integrity checks with this driver, check the CRC in your app * code and report errors back to the host. Since the ACK was already sent, * retries must be handled on application level. * unsigned crc = usbCrc16((uchar *)(unsigned)(usbAppBuf + 1), usbRxLen - 3); */		if((i = usbRxLen - 3) < 128){			usbProcessRx((uchar *)(unsigned)(usbAppBuf + 1), i);		}		usbRxLen = 0;	}	if(usbMsgLen >= 0 && usbTxLen < 0)		usbBuildTxBlock();	if(usbNewDeviceId && usbTxLen < 0){	/* tx system idle: all blocks sent */		usbNDeviceId = ~usbNewDeviceId;		DBG1(1, &usbNewDeviceId, 1);		usbNewDeviceId = 0;	}	if(isNotSE0()){	/* SE0 state */		usbIsReset = 0;	}else{		/* check whether SE0 lasts for more than 2.5us (3.75 bit times) */		if(!usbIsReset){			for(i=100;i;i--){				if(isNotSE0())					break;			}			if(!i){				usbIsReset = 1;				usbNDeviceId = ~0;				usbNewDeviceId = 0;				DBG1(0xff, 0, 0);			}		}	}}/* ------------------------------------------------------------------------- */void	usbInit(void){	usbInputBuf = (uchar)usbRxBuf[0];	usbAppBuf = (uchar)usbRxBuf[1];	MCUCR |= (1 << ISC00) | (1 << ISC01);	/* rising edge interrupt */	GIMSK |= (1 << INT0);}/* ------------------------------------------------------------------------- */

⌨️ 快捷键说明

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