CY68013的固件可以保存在主机上,当其被USB总线识别出来之后,可以通过驱动程序动态的加载USB固件,Linux内核中已经提供了完善的机制来加载设备的固件。
将需要加载的固件存放到/lib/firmware文件夹中,然后调用request_firmware函数,其中name为固件的名称(不需要路径)当固件成功加载到内核中会保存在struct firmware结构体中,size是固件的大小,data是固件中的内容(注意:固件内容是否正确以及固件如何解析需要在内核中完成)。当固件发送到设备之后,就可以调用release_firmware函数释放固件。
struct firmware {
size_t size;
u8 *data;
};
固件加载函数:
int request_firmware(const struct firmware **fw, char*name, struct device *device);
固件释放函数:
void release_firmware(struct firmware *fw);
当调用request_firmware函数成功获取CY68013的固件之后,在内核中需要对固件进行验证,检查加载到内核中的时候是有效的固件,然后将固件下载到USB设备中。
根据CY68013技术手册TRM上的说明下载固件到USB设备中需要按一下的步骤操作:
- 首先通过控制端点EP0,发送控制消息使8051核进入复位状态(CPUCS = 1);
- 然后根据HEX文件中的记录,通过EP0端点发送的控制消息下载数据到指定的地址;
- 待所有的HEX数据都下载完毕,再使8051恢复运行状态(CPUCS = 0);
如果新下载的固件中设置了USBCS中的RENUM位,则在8051核恢复运行状态之后会模拟USB设备断开与主机的连接,然后在连接主机重新进行设备的枚举。这时新下载的固件需要处理设备枚举中主机的各种请求。
按照CY68013 TRM上的说明,下载固件需要使用一下的请求:
则在USB的设备驱动中,需要通过USB core提供的API 进行操作,API的原型如下:
- 104 /**
-
105 * usb_control_msg - Builds a control urb, sends it off and waits for completion
-
106 * @dev: pointer to the usb device to send the message to
-
107 * @pipe: endpoint "pipe" to send the message to
-
108 * @request: USB message request value
-
109 * @requesttype: USB message request type value
-
110 * @value: USB message value
-
111 * @index: USB message index value
-
112 * @data: pointer to the data to send
-
113 * @size: length in bytes of the data to send
-
114 * @timeout: time in msecs to wait for the message to complete before timing
-
115 * out (if 0 the wait is forever)
-
116 *
-
117 * Context: !in_interrupt ()
-
118 *
-
119 * This function sends a simple control message to a specified endpoint and
-
120 * waits for the message to complete, or timeout.
-
121 *
-
122 * If successful, it returns the number of bytes transferred, otherwise a
-
123 * negative error number.
-
124 *
-
125 * Don't use this function from within an interrupt context, like a bottom half
-
126 * handler. If you need an asynchronous message, or need to send a message
-
127 * from within interrupt context, use usb_submit_urb().
-
128 * If a thread in your driver uses this call, make sure your disconnect()
-
129 * method can wait for it to complete. Since you don't have a handle on the
-
130 * URB used, you can't cancel the request.
-
131 */
-
132 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
-
133 __u8 requesttype, __u16 value, __u16 index, void *data,
-
134 __u16 size, int timeout)
usb_control_msg参数中的pipe必须通过usb_sndctrlpipe函数进行处理之后才能使用,request对应表3-8中的bRequest, requesttype对应表3-8中的bmRequest, value则是要下载到USB设备RAM中的起始地址(例如CPUCS寄存器的地址为0XE600),index按照表的说明始终为0, data则是要下载的数据,而size指明数据的大小,timeout则指明超时的时间,通常以HZ为参考处理。
一下是驱动程序中的相关代码,将usb_control_msg封装为3个函数,分别用来完成固件下载的3个步骤:
3 #define CY68013_VENDOR_REQ 0xa0 /* Cypress vendor bRequest */
4 #define CY68013_REQ_T_OUT 0x40 /* Cypress firmware download bmRequest */
5 #define CY68013_REG_CPUCS 0xE600 /* CY68013 CPUCS register address it control 8051 core reset and out of reset */
6 #define CY68013_RUN_CMD 0x00 /* Write this value to cy68013 CPUCS register make 8051 core run */
7 #define CY68013_RESET_CMD 0x01 /* Write this value to cy68013 CPUCS register mak e 8051 core reset */
35 /* Make CY68013 out of reset */
36 static int cy68013_run(struct kref *kref)
37 {
38 unsigned char run = CY68013_RUN_CMD;
39
40 /* Write 0x0(run) to CPUCS bit0 make cy68013 out of reset */
41 return cy68013_control_msg(kref, CY68013_REG_CPUCS, (void *)&run, sizeof(run));
42 }
43
44 /* Make CY68013 into reset */
45 static int cy68013_reset(struct kref *kref)
46 {
47 unsigned char reset = CY68013_RESET_CMD;
48
49 /* Write 0x1 to CPUCS bit0 make cy68013 into reset*/
50 return cy68013_control_msg(kref, CY68013_REG_CPUCS, (void *)&reset, sizeof(reset));
51 }
- 579 /* Download data specify data to cy68013, data size speicied by size, download address specify by addr */
-
580 static int cy68013_control_msg(struct kref *kref, __u16 addr, void *data, __u16 size)
-
581 {
-
582 int retval = 0;
-
583
-
584 /* According usb_device pointer get struct usb_cy68013 data structure pointer */
-
585 struct usb_cy68013 *cyusb = to_cy68013_dev(kref);
-
586
-
587 /* Make sure only once can send contol message to device */
-
588 mutex_lock(&cyusb->io_mutex);
-
589
-
590 /* Check current usb is connect to bus */
-
591 if (!cyusb->interface){
-
592 mutex_unlock(&cyusb->io_mutex);
-
593 return -ENODEV;
-
594 }
-
595
-
596 /* Send control message to cy68013 */
-
597 retval = usb_control_msg(cyusb->udev, usb_sndctrlpipe(cyusb->udev, 0), CY68013_VENDOR_REQ, CY68013_REQ_T_OUT, addr, 0, data, size, HZ);
-
598
-
599 mutex_unlock(&cyusb->io_mutex);
-
600
-
601 return retval < 0 ? retval : 0;
-
602 }
阅读(1886) | 评论(0) | 转发(0) |