原文地址:
http://hengch.blog.163.com/blog/static/1078006720086141327970
在《USB系列之三》中,我们实现了一系列的SCSI命令,在这个系列中,我们要实现向U盘上写扇区的命令,所以,本文相对比较容易,更多地是给出一个实现的源程序。
在《USB系列之三》中,我们实现的SCSI命令有:INQUIRY、READ CAPACITY(10)、TEST UNIT READY、REQUEST SENSE、READ(10);都是一些读出的命令,所以不会破坏U盘的内容,在文档SBC-2的第29页有一个SCSI命令的表,在这个表中列出了所有的命令,其TYPE为“M”的都是SCSI设备必须实现的命令,这些命令有:
Num Command Name Operation Code Type Reference
-----------------------------------------------------------------
1 FORMAT UNIT 04h M SBC-2
2 INQUIRY 12h M SPC-3
3 READ(6) 08h M SBC-2
4 READ(10) 28h M SBC-2
5 READ(16) 88h M SBC-2
6 READ CAPACITY(10) 25h M SBC-2
7 READ CAPACITY(16) 9Eh/10h M SBC-2
8 REQUEST SENSE 03h M SPC-3
9 SEND DIAGNOSTIC 1Dh M SPC-3
10 TEST UNIT READY 00h M SPC-3
11 WRITE(10) 2Ah O SBC-2
这里面最后的一个命令并不是SBC-2中要求强制实现的,而是可选的,但如果我们不去实现,U盘的操作将失色很多;我们不打算去实现序号为1、3、5、7和9的命令,READ(6)、READ(16)和READ(10)十分相似,只是LBA的长度不同而已,如果需要实现,参考READ(10)就可以了,FORMAT和SEND DIAGNOSTIC两个命令对使用芯片的U盘来说没有什么意义,当然对硬盘是有意义的,所以在本文中,我们只需要实现一个很重要的WRTE(10),向U盘上写数据,我们需要准备一张没有有用数据的U盘,因为我们要改变其中的内容。
WRITE(10)源代码下载地址:
http://blog.hengch.com/source/usb-write.zip
程序中,我们向《USB系列三》中的程序一样,先reset,然后得到最大的LUN,这个步骤不是必须的,然后我们向device发出WRITE(10)命令,注意,这是一个OUT事务,所以,CBW_FLAGS=0X00而不是像以前一样是0X80,发出WRITE(10)命令后,我们还要向device发送要写入的数据,每次64个字节,一个扇区512字节需要启动8个OUT事务,这个工作又函数putData完成,每次发送的64个字节我们分别写入了0--63,程序中,我们把这些数据写入到了LBA=100的扇区中,写入后,我们在使用在《USB系列之三》中介绍过的READ(10)命令把相同的扇区读出来,我们会看到我们所希望的结果,由于在读之前,我们已经把buffer全部清为0了,所以我们有把握相信,我们读到的数据是真实的。
到这里,我们已经把控制U盘的主要命令都介绍完了,利用DOSUSB,我们已经有可能为U盘编写一个简单的驱动程序,但可能我们还不知道DOS下的驱动程序该如何写,从下一篇文章开始,我们将暂时放下USB系列文章,介绍一下DOS下驱动程序的写法。
Original address:
http://hengch.blog.163.com/blog/static/1078006720086141327970
In "USB Series III", we implemented a series of SCSI commands. In this series, we are going to implement the command to write sectors to the USB flash drive, so this article is relatively easy, mainly giving an implementation source code.
In "USB Series III", the SCSI commands we implemented are: INQUIRY, READ CAPACITY(10), TEST UNIT READY, REQUEST SENSE, READ(10); all are some read commands, so they will not damage the content of the USB flash drive. On page 29 of document SBC-2, there is a table of SCSI commands. In this table, all commands with TYPE "M" are commands that SCSI devices must implement. These commands are:
Num Command Name Operation Code Type Reference
-----------------------------------------------------------------
1 FORMAT UNIT 04h M SBC-2
2 INQUIRY 12h M SPC-3
3 READ(6) 08h M SBC-2
4 READ(10) 28h M SBC-2
5 READ(16) 88h M SBC-2
6 READ CAPACITY(10) 25h M SBC-2
7 READ CAPACITY(16) 9Eh/10h M SBC-2
8 REQUEST SENSE 03h M SPC-3
9 SEND DIAGNOSTIC 1Dh M SPC-3
10 TEST UNIT READY 00h M SPC-3
11 WRITE(10) 2Ah O SBC-2
The last command here is not a mandatory one required by SBC-2, but optional. However, if we don't implement it, the operation of the USB flash drive will be much less interesting. We don't plan to implement the commands with serial numbers 1, 3, 5, 7, and 9. READ(6), READ(16), and READ(10) are very similar, just the length of LBA is different. If needed to implement, refer to READ(10). The FORMAT and SEND DIAGNOSTIC commands are not meaningful for USB flash drives using the chip, but they are meaningful for hard disks. So in this article, we only need to implement an important WRTE(10) to write data to the USB flash drive. We need to prepare a USB flash drive with no useful data because we are going to change its content.
Download address of WRITE(10) source code:
http://blog.hengch.com/source/usb-write.zip
In the program, we, just like in the program of "USB Series III", first reset, then get the maximum LUN. This step is not necessary. Then we send the WRITE(10) command to the device. Note that this is an OUT transaction, so CBW_FLAGS=0X00 instead of 0X80 as before. After sending the WRITE(10) command, we also need to send the data to be written to the device. Each time 64 bytes, and one sector of 512 bytes requires starting 8 OUT transactions. This work is done by the function putData. Each time 64 bytes sent, we write 0--63 respectively. In the program, we write these data to the sector with LBA=100. After writing, we use the READ(10) command introduced in "USB Series III" to read the same sector again. We will see the result we expect. Since we have cleared the buffer to 0 before reading, we are confident that the data we read is real.
Up to here, we have introduced all the main commands to control the USB flash drive. Using DOSUSB, we have the possibility to write a simple driver for the USB flash drive. But maybe we don't know how to write a driver under DOS yet. Starting from the next article, we will temporarily put aside the USB series articles and introduce how to write a driver under DOS.