Chinaunix首页 | 论坛 | 博客
  • 博客访问: 218123
  • 博文数量: 90
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-29 10:12
文章分类
文章存档

2015年(2)

2014年(54)

2013年(34)

我的朋友

分类: LINUX

2013-11-01 15:27:41

 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上的说明,下载固件需要使用一下的请求:

TM_thumb

则在USB的设备驱动中,需要通过USB core提供的API 进行操作,API的原型如下:

  1. 104 /**
  2. 105 * usb_control_msg - Builds a control urb, sends it off and waits for completion
  3. 106 * @dev: pointer to the usb device to send the message to
  4. 107 * @pipe: endpoint "pipe" to send the message to
  5. 108 * @request: USB message request value
  6. 109 * @requesttype: USB message request type value
  7. 110 * @value: USB message value
  8. 111 * @index: USB message index value
  9. 112 * @data: pointer to the data to send
  10. 113 * @size: length in bytes of the data to send
  11. 114 * @timeout: time in msecs to wait for the message to complete before timing
  12. 115 * out (if 0 the wait is forever)
  13. 116 *
  14. 117 * Context: !in_interrupt ()
  15. 118 *
  16. 119 * This function sends a simple control message to a specified endpoint and
  17. 120 * waits for the message to complete, or timeout.
  18. 121 *
  19. 122 * If successful, it returns the number of bytes transferred, otherwise a
  20. 123 * negative error number.
  21. 124 *
  22. 125 * Don't use this function from within an interrupt context, like a bottom half
  23. 126 * handler. If you need an asynchronous message, or need to send a message
  24. 127 * from within interrupt context, use usb_submit_urb().
  25. 128 * If a thread in your driver uses this call, make sure your disconnect()
  26. 129 * method can wait for it to complete. Since you don't have a handle on the
  27. 130 * URB used, you can't cancel the request.
  28. 131 */
  29. 132 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
  30. 133 __u8 requesttype, __u16 value, __u16 index, void *data,
  31. 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 }

  1. 579 /* Download data specify data to cy68013, data size speicied by size, download address specify by addr */
  2. 580 static int cy68013_control_msg(struct kref *kref, __u16 addr, void *data, __u16 size)
  3. 581 {
  4. 582 int retval = 0;
  5. 583
  6. 584 /* According usb_device pointer get struct usb_cy68013 data structure pointer */
  7. 585 struct usb_cy68013 *cyusb = to_cy68013_dev(kref);
  8. 586
  9. 587 /* Make sure only once can send contol message to device */
  10. 588 mutex_lock(&cyusb->io_mutex);
  11. 589
  12. 590 /* Check current usb is connect to bus */
  13. 591 if (!cyusb->interface){
  14. 592 mutex_unlock(&cyusb->io_mutex);
  15. 593 return -ENODEV;
  16. 594 }
  17. 595
  18. 596 /* Send control message to cy68013 */
  19. 597 retval = usb_control_msg(cyusb->udev, usb_sndctrlpipe(cyusb->udev, 0), CY68013_VENDOR_REQ, CY68013_REQ_T_OUT, addr, 0, data, size, HZ);
  20. 598
  21. 599 mutex_unlock(&cyusb->io_mutex);
  22. 600
  23. 601 return retval < 0 ? retval : 0;
  24. 602 }

阅读(1072) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~