hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:5140回复:33

在RAM中实现USB DISK---1

楼主#
更多 发布于:2002-08-15 12:24
我最近用D12实现了一个U盘,目前只是在内存中存放数据,给大家说说我的开发过程。
首先我用的是嵌入式linux+arm7+16Msdram+16M nor-flash+
pdiusbd12,因此我的内存比MCU大多了:),我第一步设想就是在ram中完全实现U盘。首先是最基本的初始化,包括USB标准函数的实现,具体参数采用philips的mass storage参数。这一步能让windows2k认出是个USB mass storage disk,开始下面的有关U盘的设置。

最新喜欢:

templatempla sraccoonsracco...
DK-boy
驱动中牛
驱动中牛
  • 注册日期2001-07-22
  • 最后登录2005-09-21
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2002-08-15 13:12
我最近用D12实现了一个U盘,目前只是在内存中存放数据,给大家说说我的开发过程。
首先我用的是嵌入式linux+arm7+16Msdram+16M nor-flash+
pdiusbd12,因此我的内存比MCU大多了:),我第一步设想就是在ram中完全实现U盘。首先是最基本的初始化,包括USB标准函数的实现,具体参数采用philips的mass storage参数。这一步能让windows2k认出是个USB mass storage disk,开始下面的有关U盘的设置。

几天没来,好想法真多!!!
喜欢清静?享受人生
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-08-15 13:23
工欲善其事,必先利其器,先说说USB disk开发工具。首推bus bound,本论坛有几位大侠已经成功修改了试用版的限制。利用bus bound可以看到windows发送、接收的scsi命令处理情况。抓包时选择usb mass storage device就可以了。具体调试工具看你用什么开发环境了。
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于: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里返回状态。
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-08-15 17:37
再说说文件系统问题,其实U盘不用管文件系统,只要根据sbc命令正确读写block就行了,没有文件系统,windows帮你建。当然,如果底层需要访问文件,就另当别论了。fat也不复杂,只是长文件名需要注意,在linux howto vfat里,就有讨论。大概就是用几个目录项存储剩下的文件名,属性设成0x0f,第一个目录项序号会或0x10。这样dos访问时,超过8个的文件名dos认为属性不是文件,最后一个有6个字符和~1,属性也是对的。
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2002-08-15 17:42
看来感兴趣的人不多,不贴了!
jg4664
驱动牛犊
驱动牛犊
  • 注册日期2002-05-14
  • 最后登录2008-09-28
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望2点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2002-08-15 18:22
我想问一下,如果不建文件系统,那怎样读BLOCK呢?
windows怎样建?要访问该盘,就要读盘信息,那这些信息怎样组织?谢谢!
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2002-08-15 19:08
SBC基本操作单位是block,可以看作flash里的sector,sector的数目及大小在readcapacity里返回,开始没有什么文件系统,windows格式化会写正确的数据到指定block里,访问U盘,到底层就是具体那个block。底层不需要关心文件系统,只要保证读写block正确。
zjb9606
禁止发言
禁止发言
  • 注册日期2001-03-31
  • 最后登录2018-06-02
  • 粉丝0
  • 关注0
  • 积分28476分
  • 威望148950点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
  • 社区居民
8楼#
发布于:2002-08-15 19:39
用户被禁言,该主题自动屏蔽!
xugy5867
驱动牛犊
驱动牛犊
  • 注册日期2002-07-03
  • 最后登录2018-05-29
  • 粉丝1
  • 关注0
  • 积分2分
  • 威望10点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
  • 社区居民
9楼#
发布于:2002-08-16 08:01
可以去参观一下吗?
panxz
驱动牛犊
驱动牛犊
  • 注册日期2002-04-04
  • 最后登录2007-04-12
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望1点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2002-08-16 08:35
写得不错,请教你实现了多个分区吗? 比如将的部分SDRAM 做一个分区, 你的NOR-FLASH做另一个分区,在win98/winMe下,是可以,在Win2000/XP 可以吗?
rayyang2000
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2012-09-13
  • 粉丝3
  • 关注0
  • 积分1036分
  • 威望925点
  • 贡献值3点
  • 好评度823点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2002-08-16 09:38
继续贴啊!这么好的贴子,怎么能不写完呢?  :)
等你写完了,我移到精华区,好好收藏!
天天coding-debugging中----超稀饭memory dump file ======================================================== [b]Windows Device Driver Development and Consulting Service[/b] [color=blue][url]http://www.ybwork.com[/url][/color] ========================================================
yuri69
驱动小牛
驱动小牛
  • 注册日期2002-07-12
  • 最后登录2005-12-31
  • 粉丝0
  • 关注0
  • 积分5分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2002-08-16 10:08
一定要继续写啊,大家都看着呢。只是因为对这方面感兴趣,但是就是不知道怎样入门,更别说提问题了。:)
我不会停止对你的思念,就像呼吸一样,我不去特意的想,但是,只能屏息,而不可能停止
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2002-08-16 10:10
现在还没有实现多个分区,我也不知道该怎么去实现。现在只是一个基本的U盘,希望对做U盘的兄弟有点帮助。版主鼓励,我就继续下去了。
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
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盘本身无关,就看大家怎么做了。我的驱动里就是简单的内存操作,这样流程更清楚。
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
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。
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2002-08-16 10:31
为了更好的理解软件流程,放一个流程图上来,有3页,第一页是philips mass storage流程分析,第2页是我原来d12基本驱动分析,第3页是u盘流程图,都是最上层示意图。现在驱动跟philips相比,最大不同是所有工作都在USB中断里完成,而且数据都是一次性传输。
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
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;
}
}
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
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);
}
hunterkiller
驱动牛犊
驱动牛犊
  • 注册日期2002-05-20
  • 最后登录2004-03-27
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
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一次。
 
上一页
游客

返回顶部