www.pudn.com > USBDriver.rar > Chap_9.c


/****************************************Copyright (c)************************************************** 
**                               广州周立功单片机发展有限公司 
**                                     研    究    所 
**                                        产品一部  
** 
**                                 http://www.zlgmcu.com 
** 文   件   名: Chap_9.c 
** 最后修改日期: 2004年7月2日 
** 描        述: USB驱动程序软件包: PDIUSBD12 设备端驱动程序 协议层 
** 版	     本: V1.0 
**********************************************************************************************************/ 
 
#include  
#include  
 
#include "config.h" 
#include "D12Config.h" 
#include "D12CI.h" 
#include "D12HAL.h" 
#include "Chap_9.h" 
#include "Descriptor.h" 
 
//定义传输控制结构变量 
CONTROL_XFER ControlData; 
 
//定义USB事件标志变量 
EPPFLAGS bEPPflags; 
 
extern OS_EVENT *pSetup_Event; 
 
//************************************************************************* 
//USB标准设备请求入口地址指针表 
//************************************************************************* 
void (*StandardDeviceRequest[])(void) = 
{ 
	get_status, 
	clear_feature, 
	reserved, 
	set_feature, 
	reserved, 
	set_address, 
	get_descriptor, 
	reserved, 
	get_configuration, 
	set_configuration, 
	get_interface, 
	set_interface, 
	reserved, 
	reserved, 
	reserved, 
	reserved 
}; 
 
   //************************************************************************* 
   // USB 协议层函数 
   //************************************************************************* 
    
/************************************* 
** 函数名称: void stall_ep0(void) 
** 功能描述: 使控制端点处于停止状态 
**************************************/ 
void stall_ep0(void) 
{ 
	D12_SetEndpointStatus(0, 1); 
	D12_SetEndpointStatus(1, 1); 
} 
    
    
/************************************* 
** 函数名称: void reserved(void) 
** 功能描述: 保留子程序 
**************************************/    
void reserved(void) 
{ 
	stall_ep0();				//返回STALL 
} 
 
 
/********************************************** 
** 函数名称: void init_unconfig(void) 
** 功能描述: 进入地址状态,禁止0除外的所有端点 
***********************************************/ 
void init_unconfig(void) 
{ 
	D12_SetEndpointEnable(0);	//禁止0除外的所有端点 
} 
 
/********************************************** 
** 函数名称: void init_config(void) 
** 功能描述: 配置处理,允许端点收发 
***********************************************/ 
void init_config(void) 
{ 
	D12_SetEndpointEnable(1);	//使能普通/同步端点使能 
} 
 
 
/********************************************************* 
** 函数名称: void single_transmit(INT8U * buf, INT8U len) 
** 功能描述: 通过端点索引 1 发送数据(DATA 类型) 
** 输	 入: INT8U * buf:	发送数据指针 
			 INT8U len:		发送数据长度 
** 输	 出: 无 
**********************************************************/ 
void single_transmit(INT8U * buf, INT8U len) 
{ 
	if( len <= EP0_PACKET_SIZE) {			//长度小于EP0最大信息包大小才允许发送 
		D12_WriteEndpoint(1, len, buf); 
	} 
} 
 
/************************************************************* 
** 函数名称: void code_transmit(INT8U * pRomData, INT16U len) 
** 功能描述: 通过端点索引 1 发送数据(CODE类型) 
** 输	 入: INT8U  *pRomData:	发送数据指针 
			 INT16U len:		发送数据长度 
** 输	 出: 无 
**************************************************************/ 
void code_transmit(INT8U * pRomData, INT16U len) 
{ 
	ControlData.wCount = 0;								//传输字节数计数器清0 
	if(ControlData.wLength > len) 
		ControlData.wLength = len;						//传输数据总字节数不得超过len 
 
	ControlData.pData = pRomData;						//传输数据指针指向pRomData 
	if( ControlData.wLength >= EP0_PACKET_SIZE) {		//传输数据总字节数大于端点0最大信息包大小 
		D12_WriteEndpoint(1, EP0_PACKET_SIZE, ControlData.pData);	//发送端点0最大信息包大小个字节 
		ControlData.wCount += EP0_PACKET_SIZE;						//统计已发送字节数 
 
		OS_ENTER_CRITICAL(); 
		bEPPflags.bits.control_state = USB_TRANSMIT;				//标志数据发送状态			 
		OS_EXIT_CRITICAL(); 
	} 
	else { 
		D12_WriteEndpoint(1, ControlData.wLength, pRomData);		//写入传输数据总字节数 
		ControlData.wCount += ControlData.wLength;					//统计已发送字节数 
		OS_ENTER_CRITICAL(); 
		bEPPflags.bits.control_state = USB_IDLE;					//标志空闲状态 
		OS_EXIT_CRITICAL(); 
	} 
} 
 
   //************************************************************************* 
   // USB 标准设备请求服务程序 
   //************************************************************************* 
 
/******************************************************************** 
** 函数名称: void get_status(void) 
** 功能描述: 主机要求获取状态,设备返回16位的状态描述给主机 
*********************************************************************/ 
void get_status(void) 
{ 
	INT8U endp, txdat[2], c; 
	INT8U bRecipient = ControlData.DeviceRequest.bmRequestType & USB_RECIPIENT;	 
																//取得设备请求类型	 
	if (bRecipient == USB_RECIPIENT_DEVICE) {					//对设备请求 
		if(bEPPflags.bits.remote_wakeup == 1)			 
			txdat[0] = 3;										//支持远程唤醒、自供电 
		else 
			txdat[0] = 1;										//不支持远程唤醒、自供电 
		txdat[1]=0;												//高8位为0 
		single_transmit(txdat, 2);								//发送16位的状态到主机 
		 
	} else if (bRecipient == USB_RECIPIENT_INTERFACE) {			//对接口请求 
		txdat[0]=0; 
		txdat[1]=0; 
		single_transmit(txdat, 2);	 
									//发送16位的状态到主机 
	} else if (bRecipient == USB_RECIPIENT_ENDPOINT) {			//对端点请求 
		endp = (INT8U)(ControlData.DeviceRequest.wIndex & MAX_ENDPOINTS); 
		if (ControlData.DeviceRequest.wIndex & (INT8U)USB_ENDPOINT_DIRECTION_MASK) 
			c = D12_SelectEndpoint(endp*2 + 1);					//读取输入端点状态 
		else 
			c = D12_SelectEndpoint(endp*2);						//读取输出端点状态 
		if(c & D12_STALL) 
			txdat[0] = 1;										//端点禁止 
		else 
			txdat[0] = 0;										//端点有效 
		txdat[1] = 0; 
		single_transmit(txdat, 2);								//发送16位的状态到主机 
 
	} else 
		stall_ep0();					//非标准请求,发STALL 
} 
 
 
/**************************************** 
** 函数名称: void clear_feature(void) 
** 功能描述: 清除特性 
*****************************************/ 
void clear_feature(void) 
{ 
	INT8U endp;												//读取请求类型中的接收方 
	INT8U bRecipient = ControlData.DeviceRequest.bmRequestType & USB_RECIPIENT; 
															//读取请求类型 
	if (bRecipient == USB_RECIPIENT_DEVICE					//对设备请求 
		&& ControlData.DeviceRequest.wValue == USB_FEATURE_REMOTE_WAKEUP) { 
		OS_ENTER_CRITICAL();								//清除远程唤醒特性	 
		bEPPflags.bits.remote_wakeup = 0;					//清0远程唤醒标志 
		OS_EXIT_CRITICAL(); 
		single_transmit(0, 0);								//返回一个空的数据表示执行完毕 
	} 
	 
	else if (bRecipient == USB_RECIPIENT_ENDPOINT			//对端点请求 
		&& ControlData.DeviceRequest.wValue == USB_FEATURE_ENDPOINT_STALL) { 
		//清除端点禁止特性,恢复其使用 
		endp = (INT8U)(ControlData.DeviceRequest.wIndex & MAX_ENDPOINTS); 
		if (ControlData.DeviceRequest.wIndex & (INT8U)USB_ENDPOINT_DIRECTION_MASK) 
			D12_SetEndpointStatus(endp*2 + 1, 0);			//清除控制输入端点STALL特性 
		else 
			D12_SetEndpointStatus(endp*2, 0);				//清除控制输出端点STALL特性 
		single_transmit(0, 0);								//返回一个空的数据表示执行完毕 
	} else 
		stall_ep0();					//没有该请求,返回STALL							 
} 
 
 
/**************************************** 
** 函数名称: void set_feature(void) 
** 功能描述: 设置特性 
*****************************************/ 
void set_feature(void) 
{ 
	INT8U endp;											//读取请求类型中的接收方 
	INT8U bRecipient = ControlData.DeviceRequest.bmRequestType & USB_RECIPIENT; 
														//读取请求类型 
	if (bRecipient == USB_RECIPIENT_DEVICE				//对设备请求 
		&& ControlData.DeviceRequest.wValue == USB_FEATURE_REMOTE_WAKEUP) { 
														//设置远程唤醒特性 
		OS_ENTER_CRITICAL(); 
		bEPPflags.bits.remote_wakeup = 1;				//置1远程唤醒标志 
		OS_EXIT_CRITICAL(); 
		single_transmit(0, 0);							//返回一个空的数据表示执行完毕 
	}	 
	 
	else if (bRecipient == USB_RECIPIENT_ENDPOINT		//对端点请求 
		&& ControlData.DeviceRequest.wValue == USB_FEATURE_ENDPOINT_STALL) { 
		//禁止端点 
		endp = (INT8U)(ControlData.DeviceRequest.wIndex & MAX_ENDPOINTS); 
		if (ControlData.DeviceRequest.wIndex & (INT8U)USB_ENDPOINT_DIRECTION_MASK) 
			D12_SetEndpointStatus(endp*2 + 1, 1);		//设置输入端点禁止 
		else 
			D12_SetEndpointStatus(endp*2, 1);			//设置输出端点禁止 
		single_transmit(0, 0);							//返回一个空的数据表示执行完毕 
	} else 
		stall_ep0();					//没有该请求,返回STALL 
} 
 
 
/**************************************** 
** 函数名称: void set_address(void) 
** 功能描述: 设置地址 
*****************************************/ 
void set_address(void) 
{ 
	D12_SetAddressEnable((INT8U)(ControlData.DeviceRequest.wValue & 
						 DEVICE_ADDRESS_MASK), 1); 
	single_transmit(0, 0);				//发送一个空的数据响应 
} 
 
 
/**************************************** 
** 函数名称: void get_descriptor(void) 
** 功能描述: 获取描述符 
*****************************************/ 
void get_descriptor(void) 
{ 
	INT8U bDescriptor = MSB(ControlData.DeviceRequest.wValue);			//读取请求的描述符类型 
 
	if (bDescriptor == USB_DEVICE_DESCRIPTOR_TYPE){						//获取设备描述符 
		code_transmit((INT8U *)&DeviceDescr, sizeof(USB_DEVICE_DESCRIPTOR)); 
	 
	}else if (bDescriptor == USB_CONFIGURATION_DESCRIPTOR_TYPE) {		//获取其它描述符 
		  		if (ControlData.DeviceRequest.wLength > CONFIG_DESCRIPTOR_LENGTH){  
					 ControlData.DeviceRequest.wLength = CONFIG_DESCRIPTOR_LENGTH; 
				} 
			    code_transmit((INT8U *)&(usb_descr.ConfigDescr), ControlData.DeviceRequest.wLength); 
			    														//发送描述符内容 
	   	   }else 
				stall_ep0();					//没有该请求,返回STALL 
} 
 
 
/**************************************** 
** 函数名称: void get_configuration(void) 
** 功能描述: 获取配置 
*****************************************/ 
void get_configuration(void) 
{ 
	INT8U c = bEPPflags.bits.configuration;	//取出配置值 
		 
	single_transmit(&c, 1);				//发送配置值 
} 
 
/**************************************** 
** 函数名称: void set_configuration(void) 
** 功能描述: 设置配置 
*****************************************/ 
void set_configuration(void) 
{ 
	if (ControlData.DeviceRequest.wValue == 0) {			//配置值不对,设备进入未配置状态 
		single_transmit(0, 0);								//发向一个空包响应 
		OS_ENTER_CRITICAL(); 
		bEPPflags.bits.configuration = 0;					//标记未配置 
		OS_EXIT_CRITICAL(); 
		init_unconfig();									//进入地址状态,禁止0除外的所有端点 
		 
	} else if (ControlData.DeviceRequest.wValue == 1) {		//配置设备 
		single_transmit(0, 0);								//发向一个空包响应 
		init_unconfig();									//进入地址状态,禁止0除外的所有端点 
		init_config();										//配置处理,允许端点收发 
		OS_ENTER_CRITICAL(); 
		bEPPflags.bits.configuration = 1;					//标志已配置 
		OS_EXIT_CRITICAL(); 
	} else 
		stall_ep0();						//没有该请求,返回STALL 
} 
 
 
/**************************************** 
** 函数名称: void get_interface(void) 
** 功能描述: 获取接口信息 
*****************************************/ 
void get_interface(void) 
{ 
	INT8U txdat = 0;				//本设备只有一个接口 
	single_transmit(&txdat, 1);		//发送一个字节 
} 
 
 
/**************************************** 
** 函数名称: void set_interface(void) 
** 功能描述: 设置接口信息 
*****************************************/ 
void set_interface(void) 
{ 
	if (ControlData.DeviceRequest.wValue == 0 && ControlData.DeviceRequest.wIndex == 0) 
		single_transmit(0, 0);			//发送一个空的数据表示执行完毕 
	else		 
		stall_ep0();					//没有该请求,返回STALL					 
} 
 
/************************************************************* 
** 函数名称: void control_handler() 
** 功能描述: 控制传输 
**************************************************************/ 
void control_handler() 
{ 
	INT8U type, req; 
 
	type = ControlData.DeviceRequest.bmRequestType & USB_REQUEST_TYPE_MASK; 
												//读取请求代码 
	req = ControlData.DeviceRequest.bRequest & USB_REQUEST_MASK; 
	if (type == USB_STANDARD_REQUEST) 
		(*StandardDeviceRequest[req])();		//标准请求处理 
	//else if (type == USB_VENDOR_REQUEST)		//厂商请求 
	//	(*VendorDeviceRequest[req])(); 
	//else if(type == USB_CLASS_REQUEST) 
	//	(*ClassDeviceRequest[req])();			//类请求,如大容量类 
	else 
		stall_ep0();							//无效请求,返回STALL				 
} 
 
/*************************************** 
** 函数名称: void ep0_rxdone(void) 
** 功能描述: 通过端点索引 0 接收数据 
** 输	 入: 无 
** 输	 出: 无 
***************************************/ 
void ep0_rxdone(void) 
{ 
	INT8U ep_last, i; 
	INT8U req[sizeof(DEVICE_REQUEST)]; 
 
	ep_last = D12_ReadLastTransactionStatus(0);			 //清除中断寄存器状态,取得最后处理状态 
	if (ep_last & D12_SETUPPACKET) {					 //如果收到了建立包(Setup包) 
		ControlData.wLength = 0;				 		 //传输字节总数清0 
		ControlData.wCount = 0;					 		 //传输字节计数器清0 
		if(D12_ReadEndpoint(0, sizeof(ControlData.DeviceRequest),req)  
							!= sizeof(DEVICE_REQUEST) ) { 
												 		 //从端点0读8个字节失败 
			D12_SetEndpointStatus(0, 1);				 //停止控制端点0 
			D12_SetEndpointStatus(1, 1);			 	 //停止控制端点1 
			bEPPflags.bits.control_state = USB_IDLE;	 //设置为等待状态 
			return; 
		} 
		/******* 以下语句通信中的解决大小端问题,使该函数与编译器无关 ****/ 
		ControlData.DeviceRequest.bmRequestType = req[0]; 
		ControlData.DeviceRequest.bRequest	    = req[1]; 
		ControlData.DeviceRequest.wValue 	 	= req[3] * 256 + req[2];  
		ControlData.DeviceRequest.wIndex        = req[5] * 256 + req[4]; 
		ControlData.DeviceRequest.wLength       = req[7] * 256 + req[6];  
		 
		/********  接收建立包成功 **********/ 
		D12_AcknowledgeEndpoint(0);						 //对控制端点0进行建立包应答 
		D12_AcknowledgeEndpoint(1);						 //对控制端点1进行建立包应答 
		ControlData.wLength = ControlData.DeviceRequest.wLength; 	 //取出要传输数据的总字节数 
		 
		if (ControlData.DeviceRequest.bmRequestType & (INT8U)USB_ENDPOINT_DIRECTION_MASK) { 
 														//如果控制传输是控制读取 
			 OSSemPost(pSetup_Event);					//通知control_handler()处理Setup包 
			 bEPPflags.bits.control_state = USB_TRANSMIT;	         	   //设置为发送状态 
		} 
		else{								 			//控制传输是控制写入 
			  if (ControlData.DeviceRequest.wLength == 0) { 
				  OSSemPost(pSetup_Event);		     	//通知control_handler()处理Setup包				   
				  bEPPflags.bits.control_state = USB_IDLE;	       //设置为等待状态 
			  } 
			  else { 
				    if (ControlData.DeviceRequest.wLength > MAX_CONTROLDATA_SIZE) {	 
																	 //数据长度出错 
					     bEPPflags.bits.control_state = USB_IDLE;	 //设置为等待状态	 
					     D12_SetEndpointStatus(0, 1);			  	 //停止控制端点0 
				 	     D12_SetEndpointStatus(1, 1);			     //停止控制端点1 
				    } 
				    else 
					    bEPPflags.bits.control_state = USB_RECEIVE;  //设置为接收状态 
			  }// set command with data 
		 }// else set command 
	}// if setup packet 
 
	/*****  下面为控制写入的数据阶段  ***************/ 
	else if (bEPPflags.bits.control_state == USB_RECEIVE) {	  	     //如果为接收状态 
			 i = D12_ReadEndpoint(0, EP0_PACKET_SIZE, 
			 ControlData.dataBuffer + ControlData.wCount);	 	     //从端点0接收数据 
			 ControlData.wCount += i;					 			  //统计已接收的字节数 
			 if( i != EP0_PACKET_SIZE || ControlData.wCount >= ControlData.wLength) {  		                                                          	//数据接收完毕 
				 OSSemPost(pSetup_Event);				//通知control_handler()处理Setup包 
				 bEPPflags.bits.control_state = USB_IDLE;	          //设置为等待状态 
			 } 
		 }else  
		 	 bEPPflags.bits.control_state = USB_IDLE;				  //设置等待状态 
} 
 
/*************************************** 
** 函数名称: void ep0_txdone(void) 
** 功能描述: 通过端点索引 0 发送数据 
** 输	 入: 无 
** 输	 出: 无 
***************************************/ 
void ep0_txdone(void) 
{ 
	INT16 i = ControlData.wLength - ControlData.wCount;	//计算未发送的字节数 
 
	D12_ReadLastTransactionStatus(1); 					//清除中断寄存器标志位 
 
	if (bEPPflags.bits.control_state != USB_TRANSMIT){	//非发送状态												 
		single_transmit(0, 0);						 
		return;											//返回 
	} 
	 
	if( i >= EP0_PACKET_SIZE) {							//未发送字节数大于16,发送16个字节 
		D12_WriteEndpoint(1, EP0_PACKET_SIZE, ControlData.pData + ControlData.wCount); 
		ControlData.wCount += EP0_PACKET_SIZE; 
		bEPPflags.bits.control_state = USB_TRANSMIT;	 
	} 
	else if( i != 0) {									//发送所有未发送的字节 
		D12_WriteEndpoint(1, i, ControlData.pData + ControlData.wCount); 
		ControlData.wCount += i; 
		bEPPflags.bits.control_state = USB_IDLE;		//置状态为等待状态 
	} 
	else if (i == 0){ 
		D12_WriteEndpoint(1, 0, 0); 					//发送完毕,发0个字节 
		bEPPflags.bits.control_state = USB_IDLE; 
	} 
}