AT89C5131实现U盘
2016-08-08 22:06
447 查看
初始化USB外设:
定义一堆USB协议中定义的描述符:
处理CBW和CSW:
// created by perry.peng 2012/04/21
void main (void) { LEDCON = 0xff; // 10 mA current source. CKCON0 |= 7; // Set the system and the T0 working in X2 mode. TMOD = 0x01; // M10=0; M00=1; 16bit-timer TH0 = 0; // init values TL0 = 0; TF0 = 0; // reset interrupt flag (already done by hardware) TR0 = 1; // timer0 run ms_multiple_drive = 0; USBCON |= MSK_USBE; ///< Suspend USB Clock PLLDIV = PLL_12MHz; ///< PLL clock source is 12MHz PLLCON |= MSK_PLLEN; ///< enable PLL USBCON &= ~MSK_SUSPCLK; USBINT &= ~MSK_SPINT; USBCON |= MSK_DETACH; /* Attach Command, Vref pin at high level. */ while (!TF0); TF0 = 0; TR0 = 0; /* timer0 stop */ P3 = 0; USBCON &= ~MSK_DETACH; /* Attach Command, Vref pin at high level. */ USBIEN = MSK_ESPINT | MSK_EWUPCPU | MSK_EEORINT | MSK_ESOFINT; IEN1 |= MSK_EUSB; sei (); Usb_ep_setup (EP_CTRL, EP_ENABLE | EP_TYPE_CONTROL | EP_DIR_OUT); USBCON &= ~MSK_DETACH; /* Attach Command, Vref pin at high level. */UsbConnected = TRUE;处理USB协议中的Setup包:
void Usb_setup_packet_handler (void) { #define D2H(x) ((x) << 8 | 0x80) ///< 设备到主机包 #define D2HX(x, n) (((x) << 8) | (n)) ///< 设备到主机包,子功能。 #define H2D(x) ((x) << 8) ///< 主机到设备包 #define H2DX(x, n) (((x) << 8) | (n)) ///< 主机到设备包,子功能 #define GDT(x) ((x) << 8) #define GDTS(x, n) (((x) << 8) | (n)) UEPNUM = EP_CTRL; // select control endport. if (!(UEPSTAX & MSK_RXSETUP)) /* Check if a Setup packet is received. */ return; cfgPacket.bytes[1] = UEPDATX; //!< bmRequestType cfgPacket.bytes[0] = UEPDATX; //!< bRequest /* SETUP packet: bmRequestType bRequest wValue wIndex wLength GET_DESCRIPTOR: 0x80 0x06 DType & DIndex Lang ID DLength *D=Descriptor GET_DESCRIPTOR: 0x80 0x06 */ switch (cfgPacket.reqId) { case D2H (GET_DESCRIPTOR): cfgPacket.bytes[3] = UEPDATX; /* read LSB of wValue */ cfgPacket.bytes[2] = UEPDATX; /* read MSB of wValue */ cfgPacket.bytes[5] = UEPDATX; /* read LSB of wValue */ cfgPacket.bytes[4] = UEPDATX; /* read MSB of wValue */ cfgPacket.bytes[7] = UEPDATX; /* read LSB of wLength */ cfgPacket.bytes[6] = UEPDATX; /* read MSB of wLength */ switch (cfgPacket.R.wValue) { case GDT(DEVICE_DESCRIPTOR): TransferDataSize = DeviceDescriptor[0]; //!< sizeof (DeviceDescriptor); TransferDataPtr = &DeviceDescriptor[0]; break; case GDT(CONFIGURATION_DESCRIPTOR): TransferDataSize = ConfigurationDescriptor[2]; //!< sizeof (ConfigurationDescriptor); TransferDataPtr = &ConfigurationDescriptor[0]; break; case GDTS(STRING_DESCRIPTOR, USB_STRING_LANG): TransferDataSize = StringDescriptorLanguageID[0]; //!< sizeof (StringDescriptorLanguageID); TransferDataPtr = &StringDescriptorLanguageID[0]; break; case GDTS(STRING_DESCRIPTOR, USB_STRING_MANU): TransferDataSize = StringDescriptorManuf[0]; //!< sizeof (StringDescriptorManuf); TransferDataPtr = &StringDescriptorManuf[0]; break; case GDTS(STRING_DESCRIPTOR, USB_STRING_PROD): TransferDataSize = StringDescriptorProduct[0]; //!< sizeof (StringDescriptorProduct); TransferDataPtr = &StringDescriptorProduct[0]; break; case GDTS(STRING_DESCRIPTOR, USB_STRING_SN): TransferDataSize = StringDescriptorSerialNumber[0]; //!< sizeof (StringDescriptorSerialNumber); TransferDataPtr = &StringDescriptorSerialNumber[0]; break; default: UEPSTAX |= MSK_STALLRQ; UEPSTAX &= ~MSK_RXSETUP; return; } NeedZeroPacket = FALSE; /* no zero length packet */ UEPSTAX &= ~MSK_RXSETUP; //!< clear the receive setup flag UEPSTAX |= MSK_DIR; /* set out on EP0 */ if (cfgPacket.R.wLength > TransferDataSize) { if ((TransferDataSize % EP_CONTROL_LENGTH) == 0) NeedZeroPacket = TRUE; else NeedZeroPacket = FALSE; //!< no need of zero length packet } else { TransferDataSize = (uint8_t) cfgPacket.R.wLength; //!< send only requested number of data } while ((TransferDataSize != 0) && (!(UEPSTAX & MSK_RXOUTB0B1))) { uint8_t c; // New if (TransferDataSize > EP_CONTROL_LENGTH) c = EP_CONTROL_LENGTH; else c = TransferDataSize; TransferDataSize -= c; while (c != 0) { UEPDATX = *TransferDataPtr; TransferDataPtr++; c--; } UEPSTAX |= MSK_TXRDY; while ((!(UEPSTAX & MSK_TXCMPL)) && (!(UEPSTAX & MSK_RXOUTB0B1))); UEPSTAX &= ~MSK_TXCMPL; } if (UEPSTAX & MSK_RXOUTB0B1) { //!< abort from Host UEPSTAX &= ~MSK_RXOUT; return; } if (NeedZeroPacket == TRUE) { UEPSTAX |= MSK_TXRDY; while ((!(UEPSTAX & MSK_TXCMPL)) && (!(UEPSTAX & MSK_RXOUTB0B1))); UEPSTAX &= ~MSK_TXCMPL; } while (!(UEPSTAX & MSK_RXOUTB0B1)); UEPSTAX &= ~MSK_RXOUT; break; case D2H (GET_CONFIGURATION): UEPSTAX &= ~MSK_RXSETUP; UEPSTAX |= MSK_DIR; /* set out on EP0 */ UEPDATX = UsbCurrentConfig; UEPSTAX |= MSK_TXRDY; while (!UEPSTAX & MSK_TXCMPL); UEPSTAX &= ~MSK_TXCMPL; while (!UEPSTAX & MSK_RXOUTB0B1); UEPSTAX &= ~MSK_RXOUT; break; case H2D (SET_ADDRESS): UEPSTAX &= ~MSK_RXSETUP; UEPSTAX |= MSK_TXRDY; //!< send a ZLP for STATUS phase while (!(UEPSTAX & MSK_TXCMPL)); //!< waits for status phase done //!< before using the new address UEPSTAX &= ~MSK_TXCMPL; // for Tiger compatibility USBADDR &= ~MSK_FEN; USBADDR = cfgPacket.bytes[2]; USBADDR |= MSK_FEN; break; case H2D (SET_CONFIGURATION): cfgPacket.bytes[3] = UEPDATX; cfgPacket.bytes[2] = UEPDATX; if (cfgPacket.bytes[3] > NB_CONFIGURATIONS) { UEPSTAX |= MSK_STALLRQ; UEPSTAX &= ~MSK_RXSETUP; break; } UEPSTAX &= ~MSK_RXSETUP; UsbCurrentConfig = cfgPacket.bytes[3]; UEPSTAX |= MSK_TXRDY; //!< send a ZLP for STATUS phase while (!UEPSTAX & MSK_TXCMPL); UEPSTAX &= ~MSK_TXCMPL; Usb_ep_setup (EP_MS_IN, EP_ENABLE | EP_TYPE_BULK | EP_DIR_IN); Usb_ep_setup (EP_MS_OUT, EP_ENABLE | EP_TYPE_BULK | EP_DIR_OUT); break; case H2DX (SET_FEATURE, ENDPOINT_TYPE): cfgPacket.bytes[3] = UEPDATX; cfgPacket.bytes[2] = UEPDATX; cfgPacket.bytes[5] = UEPDATX; cfgPacket.bytes[4] = UEPDATX; if (cfgPacket.R.wValue == FEATURE_ENDPOINT_HALT) { uint8_t wIndex; wIndex = cfgPacket.R.wIndex & EP_DIR; UEPNUM = wIndex; if (wIndex != EP_CTRL && UEPCONX & MSK_EPEN) { UEPSTAX |= MSK_STALLRQ; UEPNUM = EP_CTRL; endpoint_status[wIndex] = 0x01; UEPSTAX &= ~MSK_RXSETUP; UEPSTAX |= MSK_TXRDY; break; } } UEPSTAX |= MSK_STALLRQ; UEPSTAX &= ~MSK_RXSETUP; break; case D2HX (GET_STATUS, REQUEST_DEVICE_STATUS): UEPSTAX &= ~MSK_RXSETUP; UEPSTAX |= MSK_DIR; UEPDATX = DEVICE_STATUS; UEPDATX = 0x00; UEPSTAX |= MSK_TXRDY; while (!UEPSTAX & MSK_TXCMPL); UEPSTAX &= ~MSK_TXCMPL; while (!UEPSTAX & MSK_RXOUTB0B1); UEPSTAX &= ~MSK_RXOUT; break; case D2HX (GET_STATUS, REQUEST_INTERFACE_STATUS): UEPSTAX &= ~MSK_RXSETUP; UEPSTAX |= MSK_DIR; UEPDATX = INTERFACE_STATUS; UEPDATX = 0x00; UEPSTAX |= MSK_TXRDY; while (!UEPSTAX & MSK_TXCMPL); UEPSTAX &= ~MSK_TXCMPL; while (!UEPSTAX & MSK_RXOUTB0B1); UEPSTAX &= ~MSK_RXOUT; break; case D2HX (GET_STATUS, REQUEST_ENDPOINT_STATUS): cfgPacket.bytes[3] = UEPDATX; cfgPacket.bytes[2] = UEPDATX; cfgPacket.bytes[5] = UEPDATX; cfgPacket.bytes[4] = UEPDATX; UEPSTAX &= ~MSK_RXSETUP; UEPSTAX |= MSK_DIR; UEPDATX = endpoint_status[cfgPacket.R.wIndex & EP_DIR]; UEPDATX = 0x00; UEPSTAX |= MSK_TXRDY; while (!UEPSTAX & MSK_TXCMPL); UEPSTAX &= ~MSK_TXCMPL; while (!UEPSTAX & MSK_RXOUTB0B1); UEPSTAX &= ~MSK_RXOUT; break; case H2DX (CLEAR_FEATURE, ENDPOINT_TYPE): cfgPacket.bytes[3] = UEPDATX; cfgPacket.bytes[2] = UEPDATX; cfgPacket.bytes[5] = UEPDATX; cfgPacket.bytes[4] = UEPDATX; if (cfgPacket.R.wValue == FEATURE_ENDPOINT_HALT) { cfgPacket.R.wIndex &= EP_DIR; UEPNUM = cfgPacket.R.wIndex; if (UEPCONX & MSK_EPEN) { if (cfgPacket.R.wIndex != EP_CTRL) { UEPSTAX &= ~MSK_STALLRQ; UEPRST = 1 << (uint8_t) cfgPacket.R.wIndex; UEPRST = 0; } UEPNUM = EP_CTRL; endpoint_status[cfgPacket.R.wIndex] = 0x00; UEPSTAX &= ~MSK_RXSETUP; UEPSTAX |= MSK_TXRDY; break; } } UEPSTAX |= MSK_STALLRQ; UEPSTAX &= ~MSK_RXSETUP; break; //case D2H (MASS_STORAGE_RESET): case H2D (MASS_STORAGE_RESET): UEPSTAX &= ~MSK_RXSETUP; UEPSTAX |= MSK_TXRDY; break; //case D2H (GET_MAX_LUN): case H2D (GET_MAX_LUN): UEPSTAX &= ~MSK_RXSETUP; UEPSTAX |= MSK_DIR; /* set out on EP0 */ UEPDATX = MAX_LUN - 1; UEPSTAX |= MSK_TXRDY; while (!UEPSTAX & MSK_TXCMPL); UEPSTAX &= ~MSK_TXCMPL; ms_multiple_drive = 1; break; case H2D (SET_DESCRIPTOR): case H2D (SET_INTERFACE): case H2DX (SET_FEATURE, ZERO_TYPE): case H2DX (SET_FEATURE, INTERFACE_TYPE): case H2DX (CLEAR_FEATURE, ZERO_TYPE): case H2DX (CLEAR_FEATURE, INTERFACE_TYPE): case D2H (SYNCH_FRAME): case D2H (GET_INTERFACE): default: UEPSTAX |= MSK_STALLRQ; UEPSTAX &= ~MSK_RXSETUP; break; } }
定义一堆USB协议中定义的描述符:
//! Usb Device Descriptor static const uint8_t const __code DeviceDescriptor[] = { /* bLength = */ 0x12, //!< Size of this descriptor in bytes /* bDescriptorType = */ DEVICE_DESCRIPTOR, //!< DEVICE descriptor type /* bscUSB = */ 0x02, //!< Binay Coded Decimal Spec. release 0x00, /* bDeviceClass = */ 0x00, //!< Class code assigned by the USB /* bDeviceSubClass = */ 0x00, //!< Sub-class code assigned by the USB /* bDeviceProtocol = */ 0x00, //!< Protocol code assigned by the USB /* bMaxPacketSize0 = */ EP_CONTROL_LENGTH, //!< Max packet size for EP0 /* idVender = */ 0x03, //!< ??ID?,ATMEL?ID?0xeb03,??????,??????*/ 0xeb, /* idProduct = */ 0x13, //!< ??ID?,HID??0x2013, ??????,??????*/ 0x20, /* bcdDevice = */ 0x00, //!< ????USB??????,???1.0??,?0x0100?*/ 0x01, /* iManufacturer = */ USB_STRING_MANU, //!< ?????????,?????????,???????1????*/ /* iProduct = */ USB_STRING_PROD, //!< ??????????????1,????2???????????????????*/ /* iSerialNumber = */ USB_STRING_SN, //!< ????????????????3?????*/ /* bNumConfigurations=*/ 0x01 //!< ???????????????????????,???????1?*/ }; //! Usb Device Descriptor __code uint8_t DeviceQualifierDescriptor[] = { /* bLength = */ 0x0a, //!< Size of this descriptor in bytes /* bDescriptorType = */ DEVICE_QUALIFIER_DESCRIPTOR, //!< DEVICEQUALIFIER descriptor type /* bscUSB = */ 0x02, //!< Binay Coded Decimal Spec. release 0x00, /* bDeviceClass = */ 0x00, //!< Class code assigned by the USB /* bDeviceSubClass = */ 0x00, //!< Sub-class code assigned by the USB /* bDeviceProtocol = */ 0x00, //!< Protocol code assigned by the USB /* bMaxPacketSize0 = */ EP_CONTROL_LENGTH, //!< Max packet size for EP0 /* bNumConfigurations = */0x01, //!< Number of possible configurations /* bReserved = */ 0x00 //!< Reserved for future use, must be zero }; //! Configuration Descriptor __code uint8_t ConfigurationDescriptor[] = { /* bLength = */ 0x09, //!< size of this descriptor in bytes /* bDescriptorType = */ CONFIGURATION_DESCRIPTOR, //!< CONFIGURATION descriptor type /* wTotalLength = */ (0x09+0x09+0x07+0x07), //!< total length of data returned 0x00, /* bNumInterfaces = */ 0x01, //!< number of interfaces for this conf. /* bConfigurationValue = */0x01, //!< value for SetConfiguration resquest /* iConfiguration = */ 0x00, //!< index of string descriptor /* bmAttibutes = */ USB_CONFIG_BUSPOWERED, //!< Configuration characteristics /* MaxPower = */ 50, //!< 50 = 100mA, maximum power consumption /* bLength = */ 0x09, //!< size of this descriptor in bytes /* bDescriptorType = */ INTERFACE_DESCRIPTOR, //!< INTERFACE descriptor type /* bInterfaceNumber = */ 0x00, //!< Number of interface /* bAlternateSetting = */ 0x00, //!< value to select alternate setting /* bNumEndpoints = */ 0x02, //!< Number of EP except EP 0 /* bInterfaceClass = */ 0x08, //!< 0x08 = Mass Storage, Class code assigned by the USB /* bInterfaceSubClass = */0x06, //!< 0x06 = SCSI transparent Cammand Set, Sub-class code assigned by the USB /* bInterfaceProtocol = */0x50, //!< 0x50 = Bulk-Only Transport, Protocol code assigned by the USB /* iInterface = */ 0x00, //!< Index of string descriptor /* bLength = */ 0x07, //!< size of this descriptor in bytes /* bDescriptorType = */ ENDPOINT_DESCRIPTOR, //!< ENDPOINT descriptor type /* bEndpointAddress = */ (EP_MS_IN | 0x80), //!< Address of the endpoint /* bmAttributes = */ EP_TYPE_BULK, //!< Endpoint's attributes /* wMaxPacketSize = */ 64, //!< Maximum packet size for this EP 0x00, /* bInterval = */ 0x00, //!< Interval for polling EP in ms /* bLength = */ 0x07, //!< size of this descriptor in bytes /* bDescriptorType = */ ENDPOINT_DESCRIPTOR, //!< ENDPOINT descriptor type /* bEndpointAddress = */ EP_MS_OUT, //!< Address of the endpoint /* bmAttributes = */ EP_TYPE_BULK, //!< Endpoint's attributes /* wMaxPacketSize = */ 64, //!< Maximum packet size for this EP 0x00, /* bInterval = */ 0x00 //!< Interval for polling EP in ms }; // StringDescriptor LanguageID __code uint8_t StringDescriptorLanguageID[] = { /* bLength = */ 0x04, //!< size of this descriptor in bytes /* bDescriptorType = */ STRING_DESCRIPTOR, //!< STRING_DESCRIPTOR descriptor type /* wLanguageID = */ 0x09, //!< wLanguageID = 0x0409 0x04 }; // StringDescriptor Manufacture __code uint8_t StringDescriptorManuf[] = { /* bLength = */ 24, //!< size of this descriptor in bytes /* bDescriptorType = */ STRING_DESCRIPTOR, //!< STRING_DESCRIPTOR descriptor type WCHAR('F'), WCHAR('l'), WCHAR('e'), WCHAR('x'), WCHAR('t'), WCHAR('r'), WCHAR('o'), WCHAR('n'), WCHAR('i'), WCHAR('c'), WCHAR('s') }; // StringDescriptor Product __code uint8_t StringDescriptorProduct[] = { /* bLength = */ 14, //!< size of this descriptor in bytes /* bDescriptorType = */ STRING_DESCRIPTOR, //!< STRING_DESCRIPTOR descriptor type WCHAR('U'), WCHAR('S'), WCHAR('B'), WCHAR('D'), WCHAR('i'), WCHAR('s'), WCHAR('k') }; // StringDescriptor SerialNumber, Serial Number should be at least 12 characters long __code uint8_t StringDescriptorSerialNumber[] = { /* bLength = */ 16, //!< size of this descriptor in bytes /* bDescriptorType = */ STRING_DESCRIPTOR, //!< STRING_DESCRIPTOR descriptor type WCHAR('2'), WCHAR('A'), WCHAR('S'), WCHAR('4'), WCHAR('2'), WCHAR('5'), WCHAR('6') };
处理CBW和CSW:
void usb_mass_storage_cbw (void) { __bit cbw_error; uint8_t c; cbw_error = FALSE; UEPNUM = EP_MS_OUT; //! check if dCBWSignature is correct if (0x55 != UEPDATX) cbw_error = TRUE; //! 'U' if (0x53 != UEPDATX) cbw_error = TRUE; //! 'S' if (0x42 != UEPDATX) cbw_error = TRUE; //! 'B' if (0x43 != UEPDATX) cbw_error = TRUE; //! 'C' dCBWTag[0] = UEPDATX; //! Store CBW Tag to be repeated in CSW dCBWTag[1] = UEPDATX; dCBWTag[2] = UEPDATX; dCBWTag[3] = UEPDATX; ((uint8_t *) & g_scsi_data_remaining)[3] = UEPDATX; ((uint8_t *) & g_scsi_data_remaining)[2] = UEPDATX; ((uint8_t *) & g_scsi_data_remaining)[1] = UEPDATX; ((uint8_t *) & g_scsi_data_remaining)[0] = UEPDATX; if (UEPDATX != 0x00) { ms_data_direction = 1; if (cbw_error) { Usb_ack_receive_out_ms (); UEPNUM = EP_MS_IN; UEPSTAX |= MSK_STALLRQ; return; } } else { ms_data_direction = 0; if (cbw_error) { UEPSTAX |= MSK_STALLRQ; Usb_ack_receive_out_ms (); return; } } usb_LUN = UEPDATX; if (!ms_multiple_drive) { usb_LUN = 0; } ACC = UEPDATX; //! dummy CBWCBLength read for (c = 0; c < 16; c++) // store scsi_command { g_scsi_command[c] = UEPDATX; } Usb_ack_receive_out_ms (); if (ms_data_direction == 1) { UEPNUM = EP_MS_IN; } if (TRUE != scsi_decode_command ()) { if (g_scsi_data_remaining != 0) { UEPSTAX |= MSK_STALLRQ; } } } void usb_mass_storage_csw (void) { UEPNUM = EP_MS_IN; while (UEPSTAX & MSK_STALLRQ) { Usb_setup_packet_handler (); UEPNUM = EP_MS_IN; } UEPNUM = EP_MS_OUT; while (UEPSTAX & MSK_STALLRQ) { Usb_setup_packet_handler (); UEPNUM = EP_MS_OUT; } UEPNUM = EP_MS_IN; //! write CSW Signature Usb_write_byte (0x55); //! 'U' Usb_write_byte (0x53); //! 'S' Usb_write_byte (0x42); //! 'B' Usb_write_byte (0x53); //! 'S' //! write stored CBW Tag Usb_write_byte (dCBWTag[0]); Usb_write_byte (dCBWTag[1]); Usb_write_byte (dCBWTag[2]); Usb_write_byte (dCBWTag[3]); //! write data residue value Usb_write_byte (((uint8_t *) & g_scsi_data_remaining)[3]); Usb_write_byte (((uint8_t *) & g_scsi_data_remaining)[2]); Usb_write_byte (((uint8_t *) & g_scsi_data_remaining)[1]); Usb_write_byte (((uint8_t *) & g_scsi_data_remaining)[0]); //! write command status Usb_write_byte (g_scsi_status); //! 0 -> PASS, 1 -> FAIL Usb_send_in (); }
LEDCON = 0xff; // 10 mA current source. CKCON0 |= 7; // Set the system and the T0 working in X2 mode.
相关文章推荐
- 【U盘安装系统】通过UltralISO软件,实现U盘安装系统教程。
- 详解Linux实现U盘自动挂载(图文教程)
- mdev实现U盘或SD卡的自动挂载
- 使用ARM-LPC3131上的nandflash实现U盘模式心得(一)
- U盘小偷——C++实现U盘插入检测和文件扫描拷贝
- U盘实现密码破解
- 【转帖】USB过滤驱动,实现U盘只读控制
- 2015年08月01日——如何无损制作UD三分区的双启U盘(20150801图文),已经编程实现!
- LPC1788 U盘读写及IAP的实现 第一章
- U盘安装centos6.5教程(两种实现方法)
- U盘安装MAC双系统完美方案实现在MAC系统下使用双系统
- java实现u盘内容的自动复制
- mdev的使用方法和原理以及实现U盘或SD卡的自动挂载
- 通过编写自定义的gina.dll实现U盘开机锁
- linux嵌入式系统下实现U盘、SD卡自动挂载功能
- 嵌入式linux 实现mdev SD卡和U盘自动挂载和卸载的方法 mdev.conf
- mdev实现U盘或SD卡自动挂载
- USB过滤驱动,实现U盘只读控制
- Udev实现U盘或SD卡的自动挂载
- 如何在openwrt上实现 U盘的自动挂载