手机U盘模式MSG

1 通用概念
1.1 原理分析
将手机以U盘模式(Mass Storage Gadget,MSG)通过OTG线连到Android手机上(as host),切换手机的USB模式为USB存储,此时我们在Android手机上查看文件管理器是没有外接手机的SD卡存储目录的。

现象是只有/dev/block/sda,但是没有/dev/block/sda1。


原因分析如下(Ubuntu也有该issue):
由于Android是将形如 /dev/block/mmcblk0p1 写到USB的 /sys/class/android_usb/android0/f_mass_storage/lun0/file 里面,并且 /dev/block/mmcblk0p1 只有PBR扇区而没有MBR扇区,导致Linux内核 kernel/block/partitions/msdos.c 分析该分区时没有找到MBR以致产生分区节点失败,为了解决这一问题可以在函数int msdos_partition(struct parsed_partitions *state) 中的 p = (struct partition *) (data + 0x1be)之前添加如下形式的代码:

if (state->bdev->bd_disk->part0.nr_sects > 0) {
    state->parts[1].from = 0;
    state->parts[1].size = state->bdev->bd_disk->part0.nr_sects;
}

即可解决该问题(备注:Android 8.0后只需要修改external/gptfdisk/sgdisk.cc,不再需要修改kernel代码)。

该patch的另外一个应用就是USB-ZIP和USB-FDD格式的安装U盘。原因是:USB-ZIP和USB-FDD会将U盘的第一个扇区格式化成DOS.PBR而不是DOS.MBR。
USB-FDD和USB-ZIP的来历:软盘的容量小,没有分区结构,所以软盘是没有MBR的,整个软盘只有一个分区,第一个扇区就是PBR。

1.2 创建USB-FDD或者USB-ZIP格式U盘步骤
1)Android上:dd if=/dev/zero of=/dev/block/sda bs=512 count=4
2)Windows上:快速格式化该U盘,这个U盘就只有PBR扇区而没有MBR扇区

2 Windows文件系统
2.1 FAT32分配单元大小
FAT32分配单元大小 - 簇的大小,譬如16KB,命令chkdsk f:\

3 Linux文件系统
3.1 GRUB简介
GRUB镜像组成:
- GRUB.MBR(boot.img)
- 硬盘扇区offset 1 到offset 62放置GRUB的core.img
- /boot分区的boot/grub/grub.cfg

3.2 block设备性能分析工具
CONFIG_BLK_DEV_IO_TRACE
@ external/e2fsprogs/debugfs
@ external/blktrace
需要加下面的声明在blkparse.c,否则编译出错。
extern int strverscmp (const char *s1, const char *s2);

blktrace -d /dev/block/sda -o - | blkparse -i - -o /data/blk.parsed

根据扇区offset找到具体的文件:
ls -l /dev/block
debugfs -R "stats" /dev/block/sda1 |grep "Block size"

BLKNO=SECTOR_OFFSET/8
debugfs -R "icheck $BLKNO" /dev/block/sda1

GOT THE INODE NUMBER FROM THE LAST CMD: 9
debugfs -R "ncheck 9" /dev/block/sda1

3.3 ext4调试步骤
@ external/e2fsprogs/misc/dumpe2fs.c

1)找到inode号,stat /data/mytest.txt,磁盘上的inode结构体是struct ext4_inode
2)dumpe2fs /dev/block/mmcblk1p19,从超级块中获得每个块组有多少个inode数目、block size、以及inode的大小(一般256Bytes)
3)块组偏移 = inode号 / 每个块组的inode数目
4)块组内inode偏移 = inode号 % 每个块组的inode数目
5)inode在块组内哪个块which_block,块组内inode偏移 = (4096 / 256) * which_block + 剩余的inode数目residue_inode
6)dumpe2fs /dev/block/mmcblk1p19,获得对应块组Inode table块偏移
7)dd if=/dev/block/mmcblk1p19 bs=4096 skip=<块组Inode table块偏移 + which_block> |busybox hexdump -Cv -n 4096
8)从超级块中可以获得每个inode大小一般是256Bytes,从上一步dump出来的数据中偏移residue_inode * 256Bytes,找到对应的256字节内容
9)i_size在inode中偏移为4字节,大小为4字节;i_block[0]在inode中的偏移为40(0x28)字节,大小为4字节,如果i_block[0]的前2个字节是0xf30a,说明使用了extent tree
10)extent tree包含3种结构:ext4_extent_header(12byte),ext4_extent_idx(12byte),ext4_extent(12byte)
11)查看ext4_extent_header的第6个字节(偏移46和47字节)的eh_depth,如果depth=0,则header后跟一个ext4_extent结构,该结构指向一个数据块
12)读出偏移(0x38,0x39)处的块计数,LE模式
13)读出偏移(0x40,0x41)处的块地址的HI,偏移(0x42,0x43,0x44,0x45)处的块地址的LO,都是LE模式,组成完整的文件起始48位块地址start_block_no
14)查看文件第一个块的内容:dd if=/dev/block/mmcblk1p19 bs=4096 skip=<start_block_no> |busybox hexdump -Cv -n 4096

3.4 Linx command
fdisk -l /dev/block/sda
fdisk -l mbr.img
gdisk -l gpt.img

4 USB MSC
4.1 LUN
LUN - 表示一块硬盘,可以是物理上的,也可以是逻辑上,譬如Android MSG的一个mmcblk0p1分区,命令lsscsi查看
lshw
lsscsi - 返回值Host:Controller:Target:LUN
lscpu
lsusb
lsblk

4.2 SCSI CDB
31个字节长度的USB CBW报文的前15个字节是固定的头,从偏移15开始到偏移30结束是16个字节长度的SCSI CDB。
13个字节长度的USB CSW的最后一个字节表示SCSI CDB执行状态,0表示成功,1或者2表示失败。

4.3 Linux内核SCSI硬盘盘符分配
- usb层和scsi层传自定义参数
通过struct Scsi_Host {}

4.4 TUR执行流程
4.4.1 methodology
drivers/usb/storage/scsiglue.c
queuecommand_lck()
add dump_stack() to find who calls TUR.

4.4.2 enable TUR polling
echo 2000 > \
/sys/module/block/parameters/events_dfl_poll_msecs

dfl means default.

4.4.3 Construct TUR Fail CDB
If the device is not ready, the bCSWStatus field in CSW is set to 0x01 (command failed). When device reports 00h in the bCSWStatus field in CSW, which indicates that media is ready.

// srb->sense_buffer
unsigned char
usb_stor_sense_media_notpresent[18] = {
    [0] = 0x70,
    [2] = 2,           /* Sense Key */
    [7] = 0x0a,
    [12] = 0x3a,   /* ASC */
    [13] = 0,         /* ASCQ */
};

4.5 REQUEST_SENSE auto_sense
USB host MSC(transport.c)每发送一个命令后,都会检测设备返回的CSW的状态值是否为0(Good Status),如果不为0,则USB host MSC马上发送REQUEST_SENSE命令,获取18字节的出错信息,并保存在srb->sense_buffer中供SCSI层分析。

drivers/usb/storage/transport.c
usb_stor_invoke_transport()
srb->sense_buffer

5 Abbreviations
ARC:Argonant RISC Core
AT91SAM9260:SAM means Smart ARM-based Microcontroller
ATMEL SAMBA:ATMEL Smart ARM-based Microcontroller Boot Assistant
DWC2:Design Ware Controller 2,Apple的嵌入式设备,包括iPad和iPhone都是使用的DWC2
ISP1161:Philips' Integrated host Solution Pairs 1161,“Firms introduce USB host controllers”,https://www.eetimes.com/document.asp?doc_id=1290054
MSG:Mass Storage Gadget
Quirks:the attributes of a device that are considered to be noncompliant with expected operation
SL811HS:Cypress/ScanLogic 811 Host/Slave,性能上与ISP1161(Integrated host Solution Pairs 1161)相当
TDI:TransDimension Inc.,该公司首先发明了将TT集成到EHCI RootHub中的方法,这样对于嵌入式系统来说,就省去了OHCI/UHCI的硬件,同时降低了成本,作为对该公司的纪念,Linux内核定义了宏ehci_is_TDI(ehci);产品UHC124表示USB Host Controller;收购了ARC USB技术;现已被chipidea收购,chipidea又被mips收购
TT:Transaction Translator(事务转换器,将USB2.0的包转换成USB1.1的包)
USB BH reset:Bigger Hammer or Brad Hosler,表示warm reset;you may be confused why the USB 3.0 spec calls the same type of reset "warm reset" in some places and "BH reset" in other places. "BH" reset is supposed to stand for "Big Hammer" reset, but it also stands for "Brad Hosler". Brad died shortly after the USB 3.0 bus specification was started, and they decided to name the reset after him. The suggestion was made shortly before the spec was finalized, so the wording is a bit inconsistent.

STM32系列微控制器是意法半导体(STMicroelectronics)推出的32位微控制器,广泛应用于各种嵌入式系统中。STM32微控制器支持多种通讯接口,其中USB(通用串行总线)通讯是一种常见且重要的接口。 ### STM32 USB通讯简介 STM32微控制器的USB接口支持多种USB协议,包括USB 2.0全速(12 Mbps)和低速(1.5 Mbps)模式。通过USB接口,STM32可以与PC、智能手机、平板电脑等设备进行数据传输和设备控制。 ### USB协议栈 为了简化USB通讯的开发,STMicroelectronics提供了USB设备库(USB Device Library)和USB主机库(USB Host Library)。这些库提供了对USB协议的封装,开发者可以通过调用库函数来实现USB设备或主机的功能。 ### USB设备模式 在设备模式下,STM32可以作为USB设备与主机(如PC)进行通讯。常见的设备类包括: - **人机接口设备(HID)**:如键、鼠标、游戏手柄等。 - **大容量存储设备(MSC)**:如U、SD卡读卡器等。 - **通信设备类(CDC)**:如虚拟串口,用于串行数据通讯。 ### USB主机模式 在主机模式下,STM32可以作为USB主机与USB设备进行通讯。常见的应用包括: - **USB闪存驱动**:读取和写入U数据。 - **USB打印机**:控制打印机进行打印操作。 - **USB摄像头**:获取摄像头图像数据。 ### 开发步骤 1. **硬件连接**:将STM32的USB接口与目标设备(如PC)连接。 2. **配置时钟**:配置系统时钟和USB时钟,确保USB通讯的稳定性。 3. **初始化USB**:调用库函数初始化USB设备或主机。 4. **实现USB协议**:根据具体的应用场景,实现相应的USB协议,如HID、MSC或CDC。 5. **数据处理**:处理接收到的数据或发送数据到目标设备。 ### 示例代码 以下是一个简单的USB CDC设备示例代码,演示如何初始化USB并发送数据: ```c #include "stm32f4xx_hal.h" #include "usbd_cdc_if.h" int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USB_DEVICE_Init(); while (1) { char msg[] = "Hello, USB!\n"; CDC_Transmit_FS((uint8_t*)msg, sizeof(msg)); HAL_Delay(1000); } } ``` ### 总结 STM32微控制器的USB通讯功能强大,支持多种协议和应用场景。通过使用STMicroelectronics提供的USB设备库和主机库,开发者可以方便地实现USB通讯功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值