中国Linux公社论坛's Archiver

CoryXie 发表于 2005-8-21 03:05

我把chw75移植成功的USB代码整理了一遍,(已更新!)

我主要将命名函数和变量的命名规则化了(还有极少数没来得及弄——太晚了,都3点了!)。大家看我还有没有必要继续进行下去:
还作了一些:
1.将Setup packet做成结构体并对原来的代码全部进行相应改动,使得代码可读性更强!
[code:1]
/*
* USB_SETUP_PACKET
*/
typedef struct  _USB_SETUP_PACKET
{
U8 bmRequestType;                        /* bmRequestType */
U8 bRequest;                /* bRequest */
U16 wValue;                        /*wValue */
U16 wIndex;                        /*wIndex*/
U16 wLength;                /*wLength*/
} __packed USB_SETUP_PACKET, *pUSB_SETUP_PACKET;
[/code:1]
2.增加了对上述结构体的解析处理,可用一些新添加的宏来解析收到的8个字节的具体信息。这个也是一是为了方便编程,另外也可以方便阅读。
3.增加了对String Descriptor的支持。添加了两个结构体,以及对它的读取支持。这个一般不是必须支持的,但是作为对USB规范的学习,我在这里练习一下!
4.修改了两个小Bug。
[code:1]
/*UsbSendDescriptor()
*
*Send the descriptors to the host.
*/
void UsbSendDescriptor()
{
        U32 sendLength;/*(17Aug05,Cory,Added)*//*how long shall we send this time?*/
        canUsbSendDescriptor = sendBufferLength>=Ep0PacketSize;        /*To indicate if we still have more data to send after send this part of data */
                Delay(20);
        sendLength=(sendBufferLength>Ep0PacketSize)?Ep0PacketSize:sendBufferLength;/*Send no more than 'Ep0PacketSize' bytes of data*/
        D12WriteEndpointBuffer(1, (U8 *)sendBufferPointer, sendLength);
                Delay(20);
        sendBufferLength -= sendLength;/*Ep0PacketSize;*//*(17Aug05,Cory,Modified)*//*Decrease length to indicate we have sent 'sendLength' bytes.*/
                Delay(20);
        sendBufferPointer    += sendLength;/*Ep0PacketSize;*//*(17Aug05,Cory,Modified)*//*'Increase buffer pointer to indicate we have sent 'sendLength' bytes
                                                                                                                                *and we will send the following buffer next time.*/
       
}[/code:1]
[code:1]
        else if((pSetup->bmRequestType&USB_RT_RECIPIENT_MASK)==USB_RT_ENDPOINT)/*To get endpoint status.*/
        {
                endpointIndex=((pSetup->wIndex&0x00FF)*2)+(((pSetup->wIndex&0x00FF))&USB_RT_DIRECTION_MASK)?1:0;
                D12SelectEndpoint(endpointIndex);/*Select the endpoint*/
                standardStatus.status[0]=(D12DataPortValue&0x02)?1:0;/*Read after select the endpoint will get 1 byte,the bit1 of this byte indicate the STALL status*/
                standardStatus.status[1]=0;
        }[/code:1]
4.对几乎所有的相关操作都添加了注释,这些注释一方面有我个人对原作者编程思路的理解,另一方面更多是查阅文档,对照USB规范,并对比别人代码的总结.所以
应该有纰漏之处,但是也不会太多,这个我可以保证质量。每一个注释我都是查过资料的!
===============================================
当初要是把对命令口和数据口的读写写成函数户或者宏就好了。现在的代码有一些地方必须要让人转弯思考!

chw75 发表于 2005-8-21 17:14

小伙子,干劲十足,不错!! :-D

chw75 发表于 2005-8-21 17:16

小伙子,干劲十足,不错!! :-D

CoryXie 发表于 2005-8-21 23:11

我只能唯chw75马首是瞻啦!你的基本功能已经出来了哦!好佩服!学习中。。。。

alexander123 发表于 2005-9-1 09:39

在D12def.h中有一个宏定义
[color=red][size=18]#define D12Base 0x07fd0000
USB设备使用的开发板的extern io bank 0,我在读lumit提供的bootloader的startup.s文件中分析出来,开发板启动后,extern io bank0设置的base_addr=0x03fd0000,为什么这两个地址会不相同[/size]?[/color]谢谢!!!

chw75 发表于 2005-9-1 10:13

这段代码是我从斑竹提供的usb-test的代码中移植过去的。
在斑竹最初提供的usb-test的代码中有如下说明:
//  for USB DATA and COMMAND, set addr[26] = 1 so the accessed data is non-cacheable
#define D12_DATA  0x07fd0000   //D12 use nECS0 as the chip selection
#define D12_COMMAND        0x07fd0001

chw75 发表于 2005-9-1 10:29

在s3c4510的pdf上是这么讲的:
NON-CACHEABLE AREA CONTROL BIT
Although the cache affects the entire system memory, it is sometimes necessary to define non-cacheable areas
when the consistency of data stored in memory and the cache must be ensured. To support this, the S3C4510B
provides a non-cacheable area control bit in the address field, ADDR[26].
If ADDR[26] in the ROM/SRAM, flash memory, DRAM, or external I/O bank's access address is "0", then the
accessed data is cacheable. If the ADDR[26] value is "1", the accessed data is non-cacheable.

youhunjian 发表于 2005-9-9 16:37

很好啊! 我们这些菜菜看起来就方便多了啊!
问个问题:
         程序进入到d12Main()后,执行完chipID检查和 usbInit()后,就循环等待D12中断,发生D12Ep0Int时 ,会去接收一个8字节的数据包,把它转换为 一个USB_SETUP_PACKET数据,然后对它分析处理。
         我理解是PC 上的驱动发送给D12一些数据,然后D12提取出命令组合成一个8字节的包给ARM,是要与USB设备建立通信用的,对吗?
         有没有关于这方面的资料,驱动发什么样的数据给D12,然后D12把它如何转换给ARM ?
         能不能把PC机如何与USB设备建立联系,都发给D12什么数据,D12 又发给ARM什么数据大致讲一下啊,如果没时间,提供点资料也可啊!

         能否提供LEDDEMO.EXE源码?
         讲讲如何做的PC驱动更好,呵呵要求有点多,菜菜的求知欲太旺啊!

chw75 发表于 2005-9-9 16:59

你可以装个bushound工具去分析数据!

youhunjian 发表于 2005-9-9 17:26

呵呵! 还莫有开发板 我是用AXD一步步 分析的 所以不知道PC 向ARM 发了什么东东,才问上面的 问题的 :mrgreen:

chw75 发表于 2005-9-12 18:35

我也没有LEDDEMO.EXE源码,你可以问问斑竹。
你用AXD一步步分析,如果经济上不困难,建议到斑竹那里买一块开发板,这样学的快些,理解的透彻些,否则学起来挺麻烦的!!

limingth 发表于 2005-9-13 00:46

我也没有 leddemo 的源码,好像是 zhaoic 从优龙板子光盘资料里面找到的,主要用来测试 usb 接口。
新的开发板现在我也没有了,前段时间给北邮做了一批累的半死,总算是把外包装的问题解决了。 最近要的恐怕得等一段时候了。  :cry:

CoryXie 发表于 2005-9-15 14:05

很久没来,因为工作好忙,家里还没装宽带。
Enumeration: How the Host Learns about Devices
from USB Complete, Third Edition

One of the duties of a hub is to detect the attachment and removal of devices. Each hub has an interrupt IN endpoint for reporting these events to the host. On system boot-up, the host polls its root hub to learn if any devices are attached, including additional hubs and devices attached to those hubs. After boot-up, the host continues to poll periodically to learn of any newly attached or removed devices.

On learning of a new device, the host sends a series of requests to the device’s hub, causing the hub to establish a communications path between the host and the device. The host then attempts to enumerate the device by sending control transfers containing standard USB requests to the device’s Endpoint 0. All USB devices must support control transfers, the standard requests, and Endpoint 0. For a successful enumeration, the device must respond to each request by returning requested information and taking other requested actions.

From the user’s perspective, enumeration is invisible and automatic except for possibly a message that announces the detection of a new device and whether the attempt to configure it succeeded. Sometimes on first use, the user needs to assist in selecting a driver or specifying where the host should look for driver files.

When enumeration is complete, Windows adds the new device to the Device Manager’s display in the Control Panel. When a user removes a device from the bus, Windows removes the device from the Device Manager.

In a typical device, firmware contains the information the host will request, and a combination of hardware and firmware decodes and responds to requests for the information. Some controllers can manage the enumeration entirely in hardware, with no firmware support. On the host side, under Windows there’s no need to write code for enumerating because the operating system handles the process.
Enumeration Steps

The USB specification defines six device states. During enumeration, a device moves through four of the states: Powered, Default, Address, and Configured. (The other states are Attached and Suspend.) In each state, the device has defined capabilities and behavior.

The steps below are a typical sequence of events that occurs during enumeration under Windows. But device firmware must not assume that the enumeration requests and events will occur in a particular order. To function successfully, a device must detect and respond to any control request or other bus event at any time.

1. The user attaches a device to a USB port. Or the system powers up with a device already attached. The port may be on the root hub at the host or a hub that connects downstream from the host. The hub provides power to the port, and the device is in the Powered state.

2. The hub detects the device. The hub monitors the voltages on the signal lines of each of its ports. The hub has a pull-down resistor of 14.25 to 24.8 kilohms on each of the port’s two signal lines (D+ and D-). A device has a pull-up resistor of 900 to 1575 ohms on either D+ for a full-speed device or D- for a low-speed device. High-speed-capable devices attach at full speed. When a device plugs into a port, the device’s pull-up brings its line high, enabling the hub to detect that a device is attached. Chapter 15 has more on how hubs detect devices.
On detecting a device, the hub continues to provide power but doesn’t yet transmit USB traffic to the device.

3. The host learns of the new device. Each hub uses its interrupt endpoint to report events at the hub. The report indicates only whether the hub or a port (and if so, which port) has experienced an event. On learning of an event, the host sends the hub a Get_Port_Status request to find out more. Get_Port_Status and the other requests described here are standard hub-class requests that all hubs support. The information returned tells the host when a device is newly attached.

4. The hub detects whether a device is low or full speed. Just before the hub resets the device, the hub determines whether the device is low or full speed by examining the voltages on the two signal lines. The hub detects the speed of a device by determining which line has the higher voltage when idle. The hub sends the information to the host in response to the next Get_Port_Status request. A 1.x hub may instead detect the device’s speed just after a bus reset. USB 2.0 requires speed detection to occur before the reset so the hub knows whether to check for a high-speed-capable device during reset, as described below.

5. The hub resets the device. When a host learns of a new device, the host controller sends the hub a Set_Port_Feature request that asks the hub to reset the port. The hub places the device’s USB data lines in the Reset condition for at least 10 milliseconds. Reset is a special condition where both D+ and D- are a logic low. (Normally, the lines have opposite logic states.) The hub sends the reset only to the new device. Other hubs and devices on the bus don’t see the reset.

6. The host learns if a full-speed device supports high speed. Detecting whether a device supports high speed uses two special signal states. In the Chirp J state, only the D+ line is driven and in the Chirp K state, only the D- line is driven.

During the reset, a device that supports high speed sends a Chirp K. A high-speed-capable hub detects the chirp and responds with a series of alternating Chirp Ks and Chirp Js. On detecting the pattern KJKJKJ, the device removes its full-speed pull up and performs all further communications at high speed. If the hub doesn’t respond to the device’s Chirp K, the device knows it must continue to communicate at full speed. All high-speed devices must be capable of responding to enumeration requests at full speed.

7. The hub establishes a signal path between the device and the bus. The host verifies that the device has exited the reset state by sending a Get_Port_Status request. A bit in the returned data indicates whether the device is still in the reset state. If necessary, the host repeats the request until the device has exited the reset state.

When the hub removes the reset, the device is in the Default state. The device’s USB registers are in their reset states and the device is ready to respond to control transfers at Endpoint 0. The device communicates with the host using the default address of 00h. The device can draw up to 100 milliamperes from the bus.

8. The host sends a Get_Descriptor request to learn the maximum packet size of the default pipe. The host sends the request to device address 0, Endpoint 0. Because the host enumerates only one device at a time, only one device will respond to communications addressed to device address 0, even if several devices attach at once.

The eighth byte of the device descriptor contains the maximum packet size supported by Endpoint 0. A Windows host requests 64 bytes, but after receiving just one packet (whether or not it has 64 bytes), the host begins the Status stage of the transfer. On completion of the Status stage, a Windows host requests the hub to reset the device, as in Step 5 above. The USB specification doesn’t require a reset here. Resetting is a precaution that ensures that the device will be in a known state when the reset ends.

9. The host assigns an address. The host controller assigns a unique address to the device by sending a Set_Address request. The device completes the Status stage of the request using the default address and then implements the new address. The device is now in the Address state. All communications from this point on use the new address. The address is valid until the device is detached, the port is reset, or the system reboots. On the next enumeration, the host may assign a different address to the device.

10. The host learns about the device’s abilities. The host sends a Get_Descriptor request to the new address to read the device descriptor. This time the host retrieves the entire descriptor. The descriptor is a data structure containing the maximum packet size for Endpoint 0, the number of configurations the device supports, and other basic information about the device. The host uses this information in the communications that follow.

The host continues to learn about the device by requesting the one or more configuration descriptors specified in the device descriptor. A request for a configuration descriptor is actually a request for the configuration descriptor followed by all of that descriptor’s subordinate descriptors. A Windows host begins by requesting just the configuration descriptor’s nine bytes. Included in these bytes is the total length of the configuration descriptor and its subordinate descriptors.

Windows then requests the configuration descriptor again, this time using the retrieved total length. The device responds by sending the configuration descriptor followed by the configuration’s interface descriptor(s), with each interface descriptor followed by any endpoint descriptors for the interface. Some configurations also include class- or vendor-specific descriptors that extend or modify another descriptor. These descriptors follow the descriptor being extended or modified. Each descriptor begins with its length and type. The Descriptors section in this chapter has more on what each descriptor contains.

11. The host assigns and loads a device driver (except for composite devices). After learning about a device from its descriptors, the host looks for the best match in a device driver to manage communications with the device. In selecting a driver, Windows tries to match the information in the PC’s INF files with the Vendor ID, Product ID, and (optional) release number retrieved from the device. If there is no match, Windows looks for a match with any class, subclass, and protocol values retrieved from the device. If the device has been enumerated previously, Windows can use information in the system registry instead of searching the INF files. After the operating system assigns and loads the driver, the driver may request the device to resend descriptors or send other class-specific descriptors.

An exception to this sequence is composite devices, which can have different drivers assigned to different interfaces in a configuration. The host can assign these drivers only after the interfaces are enabled, which requires the device to be configured (as described in the next step).

12. The host’s device driver selects a configuration. After learning about a device from the descriptors, the device driver requests a configuration by sending a Set_Configuration request with the desired configuration number. Some devices support only one configuration. If a device supports multiple configurations, the driver can decide which configuration to request based on information the driver has about how the device will be used, or the driver can ask the user what to do or just select the first configuration. The device reads the request and enables the requested configuration. The device is now in the Configured state and the device’s interface(s) are enabled.

For composite devices, the host assigns drivers at this point. As with other devices, the host uses the information retrieved from the device to find a matching driver for each active interface in the configuration. The device is now ready for use.

CoryXie 发表于 2005-9-24 23:44

一封回信

你好,你的2410板子使用的是D12吗?在Lumit板子上的D12的U盘的工作过程大致如下:
1.当把USB线连入PC后,PC机上的USB Host会向该USB设备发送一些USB 标准请求,比如Get Device Descriptor,Get Configuration Descriptor等等,获得该设备的基本信息,比如该设备支持什么Class(类),有哪些可用端点,各端点的特性如何等。这些信息对于设备来说,都是每个类特定的。比如我们的Mass Storage Class,会用
ThisDevDesc =
                                {
                                        {/*USB_DEVICE_DESCRIPTOR*/
                                                USB_DESCR_DEVICE_LENGTH,        /*bLength*/
                                                USB_DESCR_DEVICE,        /*bDescriptorType*/
                                                0x0110,                        /*bcdUSB*/
                                                0,                                 /*bDeviceClass*/
                                                0,                                 /*bDeviceSubClass*/
                                                0,                                /*bDeviceProtocol*/
                                                D12_ENDPOINT0_PACKET_SIZE,        /*bMaxPacketSize0*/
                                                0x0471,                        /*idVendor*//*Philips*/
                                                0x0222,                        /*idProduct*/
                                                0x0113,                        /*bcdDevice*/
                                                1,                                 /*iManufacturer*//*Changed from 0 to 1 to add support 1 string descriptor describing the lumit organization.(18Aug05,Cory)*/
                                                0,                                 /*iProduct*/
                                                0,                                /*iSerialNumber*/
                                                1                                /*bNumConfigurations*/
                                        },
                                        {/*USB_CONFIGURATION_DESCRIPTOR*/
                                                USB_DESCR_CONFIGURATION_LENGTH,                /*bLength*/
                                                USB_DESCR_CONFIGURATION,                /*bDescriptorType*/
                                                D12_TOTAL_CONFIGURATION_DESCRIPTOR_SIZE,         /*wTotalLength Low byte*/
                                                0,                                        /*wTotalLength High byte*//*It's not normal to set wTotalLength as two separate parts.(18Aug05,Cory) */
                                                1,                                        /*bNumInterfaces*/
                                                1,                                        /*bConfigurationValue*/
                                                0,                                        /*iConfiguration*/
                                                0x80,                                /*bmAttributes,Bus powered,do not support Remote Wake up*/
                                                0x32                                /*MaxPower=100mA*/
                                        },
                                        {/*USB_INTERFACE_DESCRIPTOR*/
                                                USB_DESCR_INTERFACE_LENGTH,                /*bLength*/
                                                USB_DESCR_INTERFACE,                /*bDescriptorType*/
                                                0,                                        /*bInterfaceNumber*/
                                                0,                                        /*bAlternateSetting*/
                                                D12_ENDPOINT_COUNT,                                /*bNumEndpoints*//*We need only to support 2 endpoints,not including default control endpoint 0.*/
                                                USB_MASS_STORAGE_CLASS,        /*bInterfaceClass*/
                                                USB_MASS_STORAGE_SUB_CLASS_SCSI,                /*bInterfaceSubClass*/
                                                USB_MASS_STORAGE_PROTOCOL_BULK_ONLY,                /*bInterfaceProtocol*/
                                                0                                        /*iInterface*/
                                        },
                                        {/*USB_ENDPOINT_DESCRIPTOR*/
                                                USB_DESCR_ENDPOINT_LENGTH,                /*bLength*/
                                                USB_DESCR_ENDPOINT,                /*bDescriptorType*/
                                                0x82,                                /*bEndpointAddress*//* IN endpoint,endpoint number is 2*/
                                                USB_ENDPOINT_BULK,                        /*bmAttributes*//*BULK*/
                                                D12_ENDPOINT2_PACKET_SIZE,                /*wMaxPacketSize Low byte*/
                                                0,                                        /*wMaxPacketSize High byte*//*It's not normal to set wMaxPacketSize as two separate parts.(18Aug05,Cory) */
                                                0                                        /*bInterval*//*Has no meaning for BULK endpoint*/
                                        },
                                        {/*USB_ENDPOINT_DESCRIPTOR*/
                                                USB_DESCR_ENDPOINT_LENGTH,                /*bLength*/
                                                USB_DESCR_ENDPOINT,                /*bDescriptorType*/
                                                0x02,                                /*bEndpointAddress*//* OUT endpoint,endpoint number is 2*/
                                                USB_ENDPOINT_BULK,                        /*bmAttributes*//*BULK*/
                                                D12_ENDPOINT2_PACKET_SIZE,                /*wMaxPacketSize Low byte*/
                                                0,                                        /*wMaxPacketSize High byte*//*It's not normal to set wMaxPacketSize as two separate parts.(18Aug05,Cory) */
                                                0                                        /*bInterval*//*Has no meaning for BULK endpoint*/
                                        }
                                };
来描述他是
           USB_MASS_STORAGE_CLASS,        /*bInterfaceClass,MassStorage 类*/
                                                USB_MASS_STORAGE_SUB_CLASS_SCSI,                /*bInterfaceSubClass,支持SCSI命令,这是USB Mass Storage 类的一个可选命令集*/
                                                USB_MASS_STORAGE_PROTOCOL_BULK_ONLY,                /*bInterfaceProtocol,使用Bulk Only 类规范*/
同时还告诉主机该设备除了默认的控制端点外还有两个BULK端点。其中endpoint 4是BULK OUT,主机到设备方向;endpoint 5是BULK IN,设备到主机方向;这样,主机在收到这些信息后,进行一些初始化操作,根据设备的类加载Class Driver,对于windows 就是usbstr.sys;根据端点地址和方向,通过BULK OUT端点向设备发起SCSI命令,但是这些命令被封装成命令块(CBW,Command Block Wraper);设备在接到这些CBW后,就会对这些]命令进行解析,根据不同的SCSI命名来执行相应的操作,例如SCSI有一个命令是用于使设备开使将FLASH中的某一个区间的数据传给PC,设备受到这个命名,就会去读在命令中指定的扇区,并将读到的数据通过BULK IN端点传送给PC。接着,设备还要通过BULK IN端点向主机发送命令状态块(CSW,Command Status Block),用于告诉PC上一个命令完成的状态。
就这么简单。关键是解析PC的命令并完成操作。

细节的东西我没法讲,太多了。如果有具体的问题,还可以一起讨论。论坛上的代码不是我写的,我只是将CHW75等人的代码整理了一下,一是自己学习,另外就是让代码注释更详细,以便大家共同学习。

CoryXie

youhunjian 发表于 2005-10-7 08:43

非常感谢CoryXie的回答! :D

caiqun2006 发表于 2006-1-1 15:36

小伙子写的不错.

支持..

并学习中..

页: [1]

Powered by Discuz! Archiver 6.1.0F  © 2001-2007 Comsenz Inc.