阅读:5140回复:33
在RAM中实现USB DISK---1
我最近用D12实现了一个U盘,目前只是在内存中存放数据,给大家说说我的开发过程。
首先我用的是嵌入式linux+arm7+16Msdram+16M nor-flash+ pdiusbd12,因此我的内存比MCU大多了:),我第一步设想就是在ram中完全实现U盘。首先是最基本的初始化,包括USB标准函数的实现,具体参数采用philips的mass storage参数。这一步能让windows2k认出是个USB mass storage disk,开始下面的有关U盘的设置。 |
|
沙发#
发布于:2002-08-15 13:12
我最近用D12实现了一个U盘,目前只是在内存中存放数据,给大家说说我的开发过程。 几天没来,好想法真多!!! |
|
|
板凳#
发布于:2002-08-15 13:23
工欲善其事,必先利其器,先说说USB disk开发工具。首推bus bound,本论坛有几位大侠已经成功修改了试用版的限制。利用bus bound可以看到windows发送、接收的scsi命令处理情况。抓包时选择usb mass storage device就可以了。具体调试工具看你用什么开发环境了。
|
|
地板#
发布于:2002-08-15 17:28
再说说U盘基本原理。windows对硬盘的操作封装在disk.sys里,根据硬盘物理类型的不同,底层命令被送到不同的驱动,ide硬盘送到ide硬盘控制器驱动,usb盘送到usbstor.sys(windows 2000下),然后usbstor.sys封装硬盘访问命令到CBW里,通过USB bulk或interrupt端口发送,接下来是数据读写阶段,最后是状态返回阶段,底层把访问状态封装在CSW里发给PC,最终到usbstor.sys。因此,底层主要任务就是接收CBW并解释其中命令,正确返回或读出数据,在CSW里返回状态。
|
|
地下室#
发布于:2002-08-15 17:37
再说说文件系统问题,其实U盘不用管文件系统,只要根据sbc命令正确读写block就行了,没有文件系统,windows帮你建。当然,如果底层需要访问文件,就另当别论了。fat也不复杂,只是长文件名需要注意,在linux howto vfat里,就有讨论。大概就是用几个目录项存储剩下的文件名,属性设成0x0f,第一个目录项序号会或0x10。这样dos访问时,超过8个的文件名dos认为属性不是文件,最后一个有6个字符和~1,属性也是对的。
|
|
5楼#
发布于:2002-08-15 17:42
看来感兴趣的人不多,不贴了!
|
|
6楼#
发布于:2002-08-15 18:22
我想问一下,如果不建文件系统,那怎样读BLOCK呢?
windows怎样建?要访问该盘,就要读盘信息,那这些信息怎样组织?谢谢! |
|
7楼#
发布于:2002-08-15 19:08
SBC基本操作单位是block,可以看作flash里的sector,sector的数目及大小在readcapacity里返回,开始没有什么文件系统,windows格式化会写正确的数据到指定block里,访问U盘,到底层就是具体那个block。底层不需要关心文件系统,只要保证读写block正确。
|
|
8楼#
发布于:2002-08-15 19:39
用户被禁言,该主题自动屏蔽! |
|
9楼#
发布于:2002-08-16 08:01
可以去参观一下吗?
|
|
10楼#
发布于:2002-08-16 08:35
写得不错,请教你实现了多个分区吗? 比如将的部分SDRAM 做一个分区, 你的NOR-FLASH做另一个分区,在win98/winMe下,是可以,在Win2000/XP 可以吗?
|
|
11楼#
发布于:2002-08-16 09:38
继续贴啊!这么好的贴子,怎么能不写完呢? :)
等你写完了,我移到精华区,好好收藏! |
|
|
12楼#
发布于:2002-08-16 10:08
一定要继续写啊,大家都看着呢。只是因为对这方面感兴趣,但是就是不知道怎样入门,更别说提问题了。:)
|
|
|
13楼#
发布于:2002-08-16 10:10
现在还没有实现多个分区,我也不知道该怎么去实现。现在只是一个基本的U盘,希望对做U盘的兄弟有点帮助。版主鼓励,我就继续下去了。
|
|
14楼#
发布于:2002-08-16 10:17
再明确一点,我现在是在linux中写驱动控制pdiusbd12,我的内存相对51等MCU大的多了,但是对于内存,可以有其他折衷办法,比如philips的mass驱动是这样做的,如果windows发送命令读一个block,512字节,显然8052的256没办法全部读出来,phlips先发送命令让cpld产生ata读时序的开始几个状态,在传数据时暂停,然后到main的datain里每次从硬盘读一个数据,通过USB发送出去,再读第2个。但是这方面跟U盘本身无关,就看大家怎么做了。我的驱动里就是简单的内存操作,这样流程更清楚。
|
|
15楼#
发布于:2002-08-16 10:25
我们的驱动仿照philips的参数,包括descriptor,SerialPage等,对照协议可以很好的理解这些参数的意义。有了这些基本的东西,正确的控制中断,windows可以顺利的发现U盘设备,然后用bus hound就可以收到RBC命令包了。philips驱动定义成0x06,scsi命令集而不是rbc,这也无关紧要,好像windows反复也就是那几个命令。另外,不同的U盘windows发送的命令顺序不太一样,至少我收的第一个命令是0x12,inquiry,而oti的u盘上来就是0x28,read。
|
|
16楼#
发布于:2002-08-16 10:31
为了更好的理解软件流程,放一个流程图上来,有3页,第一页是philips mass storage流程分析,第2页是我原来d12基本驱动分析,第3页是u盘流程图,都是最上层示意图。现在驱动跟philips相比,最大不同是所有工作都在USB中断里完成,而且数据都是一次性传输。
|
|
17楼#
发布于:2002-08-16 10:45
结合流程图,说说最基本的思想。windows发送rbc命令,底层处理数据并返回csw,有3种可能:windows发数据,windows收数据,没有数据。1.windows发数据,底层收到rbc命令后,设置状态为dataout,在dataout状态里收数据,收完后发送csw。2.windows收数据,底层设置状态为datain,然后写一包数据,在datain里底层发送所有数据,发送完成后发送csw。3.底层直接发送csw,先写csw到fifo里一次。软件框架大概这样
// Handle an interrupt on the bulk out endpoint. if(ulIntStatus & USB_INT1_ENDPOINT2_OUT) { if(BOTFSMstate == USBFSM4BOT_IDLE) { 收rbc命令并处理;根据命令设置BOTFSMstate; } if(BOTFSMstate == USBFSM4BOT_DATAOUT) { 读数据; if(BOTXfer_wResidue == 0) { 数据读完,发CSW; } } } // Handle an interrupt on the bulk in endpoint. if(ulIntStatus & USB_INT1_ENDPOINT2_IN) { if(BOTFSMstate == USBFSM4BOT_IDLE) return; if(BOTFSMstate == USBFSM4BOT_DATAIN) 发数据; if(BOTXfer_wResidue == 0) 发送CSW; if(BOTFSMstate == USBFSM4BOT_CSW) { //发送CSW状态 发送CSW剩下数据; 发送完成后状态设为BOTFSMstate = USBFSM4BOT_IDLE; } } |
|
18楼#
发布于:2002-08-16 10:50
下面具体分析各个命令的实现。总的来说关键命令是read,write,readcapacity,其它命令只要能让windows认为正确就可以了,就是说windows读写多少数据你能正确处理返回good状态就可以了,比如testunit,直接在csw里返回0x00就行了。
第一个命令,inquiry,0x12. BOOLEAN SPC_Inquiry(void) //0x12 { #define cdbInquirySPC RBC_CDB.SpcCdb_Inquiry BOOLEAN retStatus = FALSE; printk(\"In SPC_Inquiry.\\n\"); // show_spc_inquiry_cmd(); if(cdbInquirySPC.EnableVPD) { switch(cdbInquirySPC.PageCode) { case VPDPAGE_SERIAL_NUMBER: BOTXfer_pData =(PINT8) &SerialPage; BOTXfer_wResidue = sizeof(VPD_SERIAL_PAGE); break; case VPDPAGE_DEVICE_IDENTITY: retStatus = TRUE; BOTXfer_pData = (PINT8)&DeviceIDPage; BOTXfer_wResidue = sizeof(VPD_DEVICE_ID_PAGE); break; default: //retStatus = FALSE; TPBulksup_ErrorHandler(CASECMDFAIL,BOTXfer_wResidue); RBC_BuildSenseData(SCSI_SENSE_ILLEGAL_REQUEST,SCSI_ADSENSE_ILLEGAL_COMMAND,0x00); TPBulk_CSWHandler();// Goto USBFSM4BOT_CSWPROC; return retStatus; } } else if(cdbInquirySPC.CmdSupportData) { //retStatus = FALSE; TPBulksup_ErrorHandler(CASECMDFAIL,BOTXfer_wResidue); RBC_BuildSenseData(SCSI_SENSE_ILLEGAL_REQUEST,SCSI_ADSENSE_ILLEGAL_COMMAND,0x00); TPBulk_CSWHandler();// Goto USBFSM4BOT_CSWPROC; return retStatus; } else { BOTXfer_pData =(PINT8) &inquiryData; BOTXfer_wResidue = sizeof(STD_INQUIRYDATA); } retStatus = TRUE; Xfer_Space &= BOTXFERSPACE_MASK; //BOTXfer_atROM = 1; Xfer_Space = BOTXfer_atROM; //bit6 =1 //printk(\"BOTXfer_wResidue =%d ,CBW_wXferLen = %d.\\n\",BOTXfer_wResidue,CBW_wXferLen); if( BOTXfer_wResidue > CBW_wXferLen ) { BOTXfer_wResidue = CBW_wXferLen; TPBulksup_ErrorHandler(CASE6,BOTXfer_wResidue); RBC_BuildSenseData(SCSI_SENSE_NO_SENSE,0,0); } else if ( BOTXfer_wResidue == CBW_wXferLen ) { TPBulksup_ErrorHandler(CASE6,BOTXfer_wResidue); RBC_BuildSenseData(SCSI_SENSE_NO_SENSE,0,0); } else { TPBulksup_ErrorHandler(CASE5,BOTXfer_wResidue); RBC_BuildSenseData(SCSI_SENSE_NO_SENSE,0,0); } BOTFSMstate = USBFSM4BOT_DATAIN;// Goto USBFSM4BOT_DATAIN USBWriteCommand(USB_COMMAND_SELECT_ENDPOINT + USB_ENDPOINT_BULK_IN); FlexByte = USBReadData(); //printk(\"ep5 status is %x.\\n\",FlexByte); if(FlexByte == 0) {// BulkIn is not full // printk(\"inquiry data len is%d\\n\",BOTXfer_wResidue); // show_char_buf(&inquiryData,BOTXfer_wResidue); // show_char_buf(BOTXfer_pData,BOTXfer_wResidue); USBWriteEndpoint(USB_ENDPOINT_BULK_IN, (char **)&BOTXfer_pData,&BOTXfer_wResidue); } //printk(\"First sent inquiry,len is %d\\n\",BOTXfer_wResidue); return retStatus; #undef cdbInquirySPC // return (TRUE); } |
|
19楼#
发布于:2002-08-16 10:58
inquiry就是返回serialpage数据给windows,关键是最后的部分,
USBWriteEndpoint(USB_ENDPOINT_BULK_IN, (char **) &BOTXfer_pData,&BOTXfer_wResidue); RBC命令处理是在endpoint out中断里,发送数据在endpoint in中断里完成。windows要读数据,发送cbw后就会读endpoint in端口,因此这里我们要先写endpoint in一次。 |
|
上一页
下一页