当前位置:   article > 正文

fastboot系统更新代码流程分析_ifc_match_func

ifc_match_func

说明:本流程基于Android4.4.2中的fastboot源代码讲解,该代码路径在"/system/core/fastboot"下。

从fastboot.c文件的main函数开始

  1. int main(int argc, char **argv)
  2. {
  3. int wants_wipe = 0;
  4. int wants_reboot = 0;
  5. int wants_reboot_bootloader = 0;
  6. int erase_first = 1;
  7. void *data;
  8. unsigned sz;
  9. int status;
  10. int c;
  11. int r;
  12. const struct option longopts[] = {
  13. {"base", required_argument, 0, 'b'},
  14. {"kernel_offset", required_argument, 0, 'k'},
  15. {"page_size", required_argument, 0, 'n'},
  16. {"ramdisk_offset", required_argument, 0, 'r'},
  17. {"help", 0, 0, 'h'},
  18. {0, 0, 0, 0}
  19. };
  20. serial = getenv("ANDROID_SERIAL");
  21. while (1) {
  22. int option_index = 0;
  23. c = getopt_long(argc, argv, "wub:k:n:r:s:S:lp:c:i:m:h", longopts, NULL);
  24. if (c < 0) {
  25. break;
  26. }
  27. /* Alphabetical cases */
  28. switch (c) {
  29. case 'b':
  30. base_addr = strtoul(optarg, 0, 16);
  31. break;
  32. case 'c':
  33. cmdline = optarg;
  34. break;
  35. case 'h':
  36. usage();
  37. return 1;
  38. case 'i': {
  39. char *endptr = NULL;
  40. unsigned long val;
  41. val = strtoul(optarg, &endptr, 0);
  42. if (!endptr || *endptr != '\0' || (val & ~0xffff))
  43. die("invalid vendor id '%s'", optarg);
  44. vendor_id = (unsigned short)val;
  45. break;
  46. }
  47. case 'k':
  48. kernel_offset = strtoul(optarg, 0, 16);
  49. break;
  50. case 'l':
  51. long_listing = 1;
  52. break;
  53. case 'n':
  54. page_size = (unsigned)strtoul(optarg, NULL, 0);
  55. if (!page_size) die("invalid page size");
  56. break;
  57. case 'p':
  58. product = optarg;
  59. break;
  60. case 'r':
  61. ramdisk_offset = strtoul(optarg, 0, 16);
  62. break;
  63. case 's':
  64. serial = optarg;
  65. break;
  66. case 'S':
  67. sparse_limit = parse_num(optarg);
  68. if (sparse_limit < 0) {
  69. die("invalid sparse limit");
  70. }
  71. break;
  72. case 'u':
  73. erase_first = 0;
  74. break;
  75. case 'w':
  76. wants_wipe = 1;
  77. break;
  78. case '?':
  79. return 1;
  80. default:
  81. abort();
  82. }
  83. }
  84. argc -= optind;
  85. argv += optind;
  86. if (argc == 0 && !wants_wipe) {
  87. usage();
  88. return 1;
  89. }
  90. if (argc > 0 && !strcmp(*argv, "devices")) {
  91. skip(1);
  92. list_devices();
  93. return 0;
  94. }
  95. if (argc > 0 && !strcmp(*argv, "help")) {
  96. usage();
  97. return 0;
  98. }
  99. usb = open_device();
  100. while (argc > 0) {
  101. if(!strcmp(*argv, "getvar")) {
  102. require(2);
  103. fb_queue_display(argv[1], argv[1]);
  104. skip(2);
  105. } else if(!strcmp(*argv, "erase")) {
  106. require(2);
  107. if (fb_format_supported(usb, argv[1])) {
  108. fprintf(stderr, "******** Did you mean to fastboot format this partition?\n");
  109. }
  110. fb_queue_erase(argv[1]);
  111. skip(2);
  112. } else if(!strcmp(*argv, "format")) {
  113. require(2);
  114. if (erase_first && needs_erase(argv[1])) {
  115. fb_queue_erase(argv[1]);
  116. }
  117. fb_queue_format(argv[1], 0);
  118. skip(2);
  119. } else if(!strcmp(*argv, "signature")) {
  120. require(2);
  121. data = load_file(argv[1], &sz);
  122. if (data == 0) die("could not load '%s': %s", argv[1], strerror(errno));
  123. if (sz != 256) die("signature must be 256 bytes");
  124. fb_queue_download("signature", data, sz);
  125. fb_queue_command("signature", "installing signature");
  126. skip(2);
  127. } else if(!strcmp(*argv, "reboot")) {
  128. wants_reboot = 1;
  129. skip(1);
  130. } else if(!strcmp(*argv, "reboot-bootloader")) {
  131. wants_reboot_bootloader = 1;
  132. skip(1);
  133. } else if (!strcmp(*argv, "continue")) {
  134. fb_queue_command("continue", "resuming boot");
  135. skip(1);
  136. } else if(!strcmp(*argv, "boot")) {
  137. char *kname = 0;
  138. char *rname = 0;
  139. skip(1);
  140. if (argc > 0) {
  141. kname = argv[0];
  142. skip(1);
  143. }
  144. if (argc > 0) {
  145. rname = argv[0];
  146. skip(1);
  147. }
  148. data = load_bootable_image(kname, rname, &sz, cmdline);
  149. if (data == 0) return 1;
  150. fb_queue_download("boot.img", data, sz);
  151. fb_queue_command("boot", "booting");
  152. } else if(!strcmp(*argv, "flash")) {
  153. char *pname = argv[1];
  154. char *fname = 0;
  155. require(2);
  156. if (argc > 2) {
  157. fname = argv[2];
  158. skip(3);
  159. } else {
  160. fname = find_item(pname, product);
  161. skip(2);
  162. }
  163. if (fname == 0) die("cannot determine image filename for '%s'", pname);
  164. if (erase_first && needs_erase(pname)) {
  165. fb_queue_erase(pname);
  166. }
  167. do_flash(usb, pname, fname);
  168. } else if(!strcmp(*argv, "flash:raw")) {
  169. char *pname = argv[1];
  170. char *kname = argv[2];
  171. char *rname = 0;
  172. require(3);
  173. if(argc > 3) {
  174. rname = argv[3];
  175. skip(4);
  176. } else {
  177. skip(3);
  178. }
  179. data = load_bootable_image(kname, rname, &sz, cmdline);
  180. if (data == 0) die("cannot load bootable image");
  181. fb_queue_flash(pname, data, sz);
  182. } else if(!strcmp(*argv, "flashall")) {
  183. skip(1);
  184. do_flashall(usb, erase_first);
  185. wants_reboot = 1;
  186. } else if(!strcmp(*argv, "update")) {
  187. if (argc > 1) {
  188. do_update(usb, argv[1], erase_first);
  189. skip(2);
  190. } else {
  191. do_update(usb, "update.zip", erase_first);
  192. skip(1);
  193. }
  194. wants_reboot = 1;
  195. } else if(!strcmp(*argv, "oem")) {
  196. argc = do_oem_command(argc, argv);
  197. } else {
  198. usage();
  199. return 1;
  200. }
  201. }
  202. if (wants_wipe) {
  203. fb_queue_erase("userdata");
  204. fb_queue_format("userdata", 1);
  205. fb_queue_erase("cache");
  206. fb_queue_format("cache", 1);
  207. }
  208. if (wants_reboot) {
  209. fb_queue_reboot();
  210. } else if (wants_reboot_bootloader) {
  211. fb_queue_command("reboot-bootloader", "rebooting into bootloader");
  212. }
  213. if (fb_queue_is_empty())
  214. return 0;
  215. status = fb_execute_queue(usb);
  216. return (status) ? 1 : 0;
  217. }

第108行:usb = open_device(); //打开单板设备对应的usb设备

1、 open_device代码如下

总结:打开特定vendor的usb设备,白名单在  match_fastboot_with_serial函数中,详情请往下看。

  1. usb_handle *open_device(void)
  2. {
  3. static usb_handle *usb = 0;
  4. int announce = 1;
  5. if(usb) return usb;
  6. for(;;) {
  7. usb = usb_open(match_fastboot);
  8. if(usb) return usb;
  9. if(announce) {
  10. announce = 0;
  11. fprintf(stderr,"< waiting for device >\n");
  12. }
  13. sleep(1);
  14. }
  15. }

第8行到第15行是一个循环结构,如果没有找到可用的usb设备,则一直循环,并在第一次没有找到设备时打印“waiting for devece”;

第9行,使用usb_open函数打开usb设备,该函数针对不同的操作系统(windows,linux,os)有三种不同的实现,本文以linux为例。

1.1 usb_open

  1. usb_handle *usb_open(ifc_match_func callback)
  2. {
  3. return find_usb_device("/dev/bus/usb", callback);
  4. }

usb_open函数的第三行,它调用了find_usb_device函数,并以"/dev/bus/usb"作为第一个参数,以callback作为第二个参数。

1.1.1 find_usb_device
  1. static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
  2. {
  3. usb_handle *usb = 0;
  4. char busname[64], devname[64];
  5. char desc[1024];
  6. int n, in, out, ifc;
  7. DIR *busdir, *devdir;
  8. struct dirent *de;
  9. int fd;
  10. int writable;
  11. busdir = opendir(base);
  12. if(busdir == 0) return 0;
  13. while((de = readdir(busdir)) && (usb == 0)) {
  14. if(badname(de->d_name)) continue;
  15. sprintf(busname, "%s/%s", base, de->d_name);
  16. devdir = opendir(busname);
  17. if(devdir == 0) continue;
  18. // DBG("[ scanning %s ]\n", busname);
  19. while((de = readdir(devdir)) && (usb == 0)) {
  20. if(badname(de->d_name)) continue;
  21. sprintf(devname, "%s/%s", busname, de->d_name);
  22. // DBG("[ scanning %s ]\n", devname);
  23. writable = 1;
  24. if((fd = open(devname, O_RDWR)) < 0) {
  25. // Check if we have read-only access, so we can give a helpful
  26. // diagnostic like "adb devices" does.
  27. writable = 0;
  28. if((fd = open(devname, O_RDONLY)) < 0) {
  29. continue;
  30. }
  31. }
  32. n = read(fd, desc, sizeof(desc));
  33. if(filter_usb_device(fd, desc, n, writable, callback,
  34. &in, &out, &ifc) == 0) {
  35. usb = calloc(1, sizeof(usb_handle));
  36. strcpy(usb->fname, devname);
  37. usb->ep_in = in;
  38. usb->ep_out = out;
  39. usb->desc = fd;
  40. n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &ifc);
  41. if(n != 0) {
  42. close(fd);
  43. free(usb);
  44. usb = 0;
  45. continue;
  46. }
  47. } else {
  48. close(fd);
  49. }
  50. }
  51. closedir(devdir);
  52. }
  53. closedir(busdir);
  54. return usb;
  55. }
先来看一下linux下usb设备节点的目录结构:



由以上信息可以得知,在"/dev/bus/usb"目录下有子目录001,002等,在子目录下有对应usb设备对应的文件节点,这样我们看find_usb_device函数的第13行到第24行,就更容易理解了。

第13行:打开"/dev/bus/usb"目录;

第14行:打开失败,返回;

第16行:循环遍历"/dev/bus/usb"的第一级子目录,如002;

第20行:打开某一个第一级子目录,如002;

第24行:循环遍历第一级子目录(如/dev/bus/usb/002")下的usb驱动节点文件;

第31行:以读写方式打开usb驱动节点文件,其实就是以读写方式打开usb设备,如果返回值小于于等于0,则说明打开成功失败;设置writable值。 

第35行:以方式打开usb驱动节点文件,打开失败则终止本次循环,测试下一个usb节点; 

第40行:读取usb节点文件信息,包含了vid,pid等。

第42行:过滤usb设备,代码如下

1.1.1.1 filter_usb_device

  1. static int filter_usb_device(int fd, char *ptr, int len, int writable,
  2. ifc_match_func callback,
  3. int *ept_in_id, int *ept_out_id, int *ifc_id)
  4. {
  5. struct usb_device_descriptor *dev;
  6. struct usb_config_descriptor *cfg;
  7. struct usb_interface_descriptor *ifc;
  8. struct usb_endpoint_descriptor *ept;
  9. struct usb_ifc_info info;
  10. int in, out;
  11. unsigned i;
  12. unsigned e;
  13. struct stat st;
  14. int result;
  15. if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
  16. return -1;
  17. dev = (void*) ptr;
  18. len -= dev->bLength;
  19. ptr += dev->bLength;
  20. if(check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
  21. return -1;
  22. cfg = (void*) ptr;
  23. len -= cfg->bLength;
  24. ptr += cfg->bLength;
  25. info.dev_vendor = dev->idVendor;
  26. info.dev_product = dev->idProduct;
  27. info.dev_class = dev->bDeviceClass;
  28. info.dev_subclass = dev->bDeviceSubClass;
  29. info.dev_protocol = dev->bDeviceProtocol;
  30. info.writable = writable;
  31. // read device serial number (if there is one)
  32. info.serial_number[0] = 0;
  33. if (dev->iSerialNumber) {
  34. struct usbdevfs_ctrltransfer ctrl;
  35. // Keep it short enough because some bootloaders are borked if the URB len is > 255
  36. // 128 is too big by 1.
  37. __u16 buffer[127];
  38. memset(buffer, 0, sizeof(buffer));
  39. ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
  40. ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
  41. ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
  42. //language ID (en-us) for serial number string
  43. ctrl.wIndex = 0x0409;
  44. ctrl.wLength = sizeof(buffer);
  45. ctrl.data = buffer;
  46. ctrl.timeout = 50;
  47. result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
  48. if (result > 0) {
  49. int i;
  50. // skip first word, and copy the rest to the serial string, changing shorts to bytes.
  51. result /= 2;
  52. for (i = 1; i < result; i++)
  53. info.serial_number[i - 1] = buffer[i];
  54. info.serial_number[i - 1] = 0;
  55. }
  56. }
  57. /* We need to get a path that represents a particular port on a particular
  58. * hub. We are passed an fd that was obtained by opening an entry under
  59. * /dev/bus/usb. Unfortunately, the names of those entries change each
  60. * time devices are plugged and unplugged. So how to get a repeatable
  61. * path? udevadm provided the inspiration. We can get the major and
  62. * minor of the device file, read the symlink that can be found here:
  63. * /sys/dev/char/<major>:<minor>
  64. * and then use the last element of that path. As a concrete example, I
  65. * have an Android device at /dev/bus/usb/001/027 so working with bash:
  66. * $ ls -l /dev/bus/usb/001/027
  67. * crw-rw-r-- 1 root plugdev 189, 26 Apr 9 11:03 /dev/bus/usb/001/027
  68. * $ ls -l /sys/dev/char/189:26
  69. * lrwxrwxrwx 1 root root 0 Apr 9 11:03 /sys/dev/char/189:26 ->
  70. * ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3
  71. * So our device_path would be 1-4.2.3 which says my device is connected
  72. * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per
  73. * http://www.linux-usb.org/FAQ.html).
  74. */
  75. info.device_path[0] = '\0';
  76. result = fstat(fd, &st);
  77. if (!result && S_ISCHR(st.st_mode)) {
  78. char cdev[128];
  79. char link[256];
  80. char *slash;
  81. ssize_t link_len;
  82. snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d",
  83. major(st.st_rdev), minor(st.st_rdev));
  84. link_len = readlink(cdev, link, sizeof(link) - 1);
  85. if (link_len > 0) {
  86. link[link_len] = '\0';
  87. slash = strrchr(link, '/');
  88. if (slash)
  89. snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1);
  90. }
  91. }
  92. for(i = 0; i < cfg->bNumInterfaces; i++) {
  93. if(check(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE))
  94. return -1;
  95. ifc = (void*) ptr;
  96. len -= ifc->bLength;
  97. ptr += ifc->bLength;
  98. in = -1;
  99. out = -1;
  100. info.ifc_class = ifc->bInterfaceClass;
  101. info.ifc_subclass = ifc->bInterfaceSubClass;
  102. info.ifc_protocol = ifc->bInterfaceProtocol;
  103. for(e = 0; e < ifc->bNumEndpoints; e++) {
  104. if(check(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE))
  105. return -1;
  106. ept = (void*) ptr;
  107. len -= ept->bLength;
  108. ptr += ept->bLength;
  109. if((ept->bmAttributes & 0x03) != 0x02)
  110. continue;
  111. if(ept->bEndpointAddress & 0x80) {
  112. in = ept->bEndpointAddress;
  113. } else {
  114. out = ept->bEndpointAddress;
  115. }
  116. }
  117. info.has_bulk_in = (in != -1);
  118. info.has_bulk_out = (out != -1);
  119. if(callback(&info) == 0) {
  120. *ept_in_id = in;
  121. *ept_out_id = out;
  122. *ifc_id = ifc->bInterfaceNumber;
  123. return 0;
  124. }
  125. }
  126. return -1;
  127. }
第5行到第8行的这四个结构体定义在android4.2.2的external\kernel-headers\original\linux\usb\Ch9.h文件中。

整个函数就是为了找到正确的数据填充这四个结构体,并最终转存到第9行的info变量中,还有就是找到usb对应的in与out端口用来传输数据。

第136行:callback(&info),callback为函数指针,由外层函数 1、open_device 传进来的,实际指向match_fastboot函数,代码如下所示:

  1. int match_fastboot(usb_ifc_info *info)
  2. {
  3. return match_fastboot_with_serial(info, serial);
  4. }

  1. int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
  2. {
  3. if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
  4. (info->dev_vendor != 0x18d1) && // Google
  5. (info->dev_vendor != 0x8087) && // Intel
  6. (info->dev_vendor != 0x0451) &&
  7. (info->dev_vendor != 0x0502) &&
  8. (info->dev_vendor != 0x0fce) && // Sony Ericsson
  9. (info->dev_vendor != 0x05c6) && // Qualcomm
  10. (info->dev_vendor != 0x22b8) && // Motorola
  11. (info->dev_vendor != 0x0955) && // Nvidia
  12. (info->dev_vendor != 0x413c) && // DELL
  13. (info->dev_vendor != 0x2314) && // INQ Mobile
  14. (info->dev_vendor != 0x0b05) && // Asus
  15. (info->dev_vendor != 0x0bb4)) // HTC
  16. return -1;
  17. if(info->ifc_class != 0xff) return -1;
  18. if(info->ifc_subclass != 0x42) return -1;
  19. if(info->ifc_protocol != 0x03) return -1;
  20. // require matching serial number or device path if requested
  21. // at the command line with the -s option.
  22. if (local_serial && (strcmp(local_serial, info->serial_number) != 0 &&
  23. strcmp(local_serial, info->device_path) != 0)) return -1;
  24. return 0;
  25. }

第3-15行:如果能够匹配其中的某一个vid,则跳转到第17行,并执行后面的语句。

回到1.1.1.1 filter_usb_device;

第137行:获取到in端口;

第138行:获取到out端口;

回到1.1.1 find_usb_device:

第44行:申请usb对象内存;

第45-48行:将usb的节点路径,in、out端口,设备句柄保存在usb变量中。

第65,返回该usb变量。这个就是我们以后

再回到1.1 usb_open函数也执行完了,那么open_device返回的就是usb的句柄。


回到main函数来:

第164行:此处就是更新系统的分支;(更新命令如:fastboot flash boot boot.img为例)

第165行:pname保存分区名;

第166-174:找到boot.img在pc机上的位置;

第175行:检查文件名是否合法;

第179行:将boot.img写到设备上,下面我们分析该函数。


2、do_flash

总结:将要更新的系统数据保存到了action_list链表中。
  1. void do_flash(usb_handle *usb, const char *pname, const char *fname)
  2. {
  3. struct fastboot_buffer buf;
  4. if (load_buf(usb, fname, &buf)) {
  5. die("cannot load '%s'", fname);
  6. }
  7. flash_buf(pname, &buf);
  8. }
2.1、load_buf
  1. static int load_buf(usb_handle *usb, const char *fname,
  2. struct fastboot_buffer *buf)
  3. {
  4. int fd;
  5. fd = open(fname, O_RDONLY | O_BINARY);
  6. if (fd < 0) {
  7. die("cannot open '%s'\n", fname);
  8. }
  9. return load_buf_fd(usb, fd, buf);
  10. }
2.1.1、load_buf_fd
  1. static int load_buf_fd(usb_handle *usb, int fd,
  2. struct fastboot_buffer *buf)
  3. {
  4. int64_t sz64;
  5. void *data;
  6. int64_t limit;
  7. sz64 = file_size(fd);
  8. if (sz64 < 0) {
  9. return -1;
  10. }
  11. limit = get_sparse_limit(usb, sz64);
  12. if (limit) {
  13. struct sparse_file **s = load_sparse_files(fd, limit);
  14. if (s == NULL) {
  15. return -1;
  16. }
  17. buf->type = FB_BUFFER_SPARSE;
  18. buf->data = s;
  19. } else {
  20. unsigned int sz;
  21. data = load_fd(fd, &sz);
  22. if (data == 0) return -1;
  23. buf->type = FB_BUFFER;
  24. buf->data = data;
  25. buf->sz = sz;
  26. }
  27. return 0;
  28. }
将数据加载到了buf。
2.2、flash_buf
  1. static void flash_buf(const char *pname, struct fastboot_buffer *buf)
  2. {
  3. struct sparse_file **s;
  4. switch (buf->type) {
  5. case FB_BUFFER_SPARSE:
  6. s = buf->data;
  7. while (*s) {
  8. int64_t sz64 = sparse_file_len(*s, true, false);
  9. fb_queue_flash_sparse(pname, *s++, sz64);
  10. }
  11. break;
  12. case FB_BUFFER:
  13. fb_queue_flash(pname, buf->data, buf->sz);
  14. break;
  15. default:
  16. die("unknown buffer type: %d", buf->type);
  17. }
  18. }
2.2.1、fb_queue_flash
  1. void fb_queue_flash(const char *ptn, void *data, unsigned sz)
  2. {
  3. Action *a;
  4. a = queue_action(OP_DOWNLOAD, "");
  5. a->data = data;
  6. a->size = sz;
  7. a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
  8. a = queue_action(OP_COMMAND, "flash:%s", ptn);
  9. a->msg = mkmsg("writing '%s'", ptn);
  10. }
这个函数看似将数据放到了变量a里面,我们来看一下queue_action函数
  1. static Action *queue_action(unsigned op, const char *fmt, ...)
  2. {
  3. Action *a;
  4. va_list ap;
  5. size_t cmdsize;
  6. a = calloc(1, sizeof(Action));
  7. if (a == 0) die("out of memory");
  8. va_start(ap, fmt);
  9. cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
  10. va_end(ap);
  11. if (cmdsize >= sizeof(a->cmd)) {
  12. free(a);
  13. die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd));
  14. }
  15. if (action_last) {
  16. action_last->next = a;
  17. } else {
  18. action_list = a;
  19. }
  20. action_last = a;
  21. a->op = op;
  22. a->func = cb_default;
  23. a->start = -1;
  24. return a;
  25. }
原来a是action_list链表中的一个元素,也就是将要写的数据保存到了链表 action_list中
2.3、调用流程图如下



回到main函数,第230行:status = fb_execute_queue(usb),如下

3、fb_execute_queue

总结:最终调用ioctl将数据写到usb设备上。
  1. int fb_execute_queue(usb_handle *usb)
  2. {
  3. Action *a;
  4. char resp[FB_RESPONSE_SZ+1];
  5. int status = 0;
  6. a = action_list;
  7. if (!a)
  8. return status;
  9. resp[FB_RESPONSE_SZ] = 0;
  10. double start = -1;
  11. for (a = action_list; a; a = a->next) {
  12. a->start = now();
  13. if (start < 0) start = a->start;
  14. if (a->msg) {
  15. // fprintf(stderr,"%30s... ",a->msg);
  16. fprintf(stderr,"%s...\n",a->msg);
  17. }
  18. if (a->op == OP_DOWNLOAD) {
  19. status = fb_download_data(usb, a->data, a->size);
  20. status = a->func(a, status, status ? fb_get_error() : "");
  21. if (status) break;
  22. } else if (a->op == OP_COMMAND) {
  23. status = fb_command(usb, a->cmd);
  24. status = a->func(a, status, status ? fb_get_error() : "");
  25. if (status) break;
  26. } else if (a->op == OP_QUERY) {
  27. status = fb_command_response(usb, a->cmd, resp);
  28. status = a->func(a, status, status ? fb_get_error() : resp);
  29. if (status) break;
  30. } else if (a->op == OP_NOTICE) {
  31. fprintf(stderr,"%s\n",(char*)a->data);
  32. } else if (a->op == OP_FORMAT) {
  33. status = fb_format(a, usb, (int)a->data);
  34. status = a->func(a, status, status ? fb_get_error() : "");
  35. if (status) break;
  36. } else if (a->op == OP_DOWNLOAD_SPARSE) {
  37. status = fb_download_data_sparse(usb, a->data);
  38. status = a->func(a, status, status ? fb_get_error() : "");
  39. if (status) break;
  40. } else {
  41. die("bogus action");
  42. }
  43. }
  44. fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
  45. return status;
  46. }
这里,我们只分析OP_DOWNLOAD分支,请看:
第21行:fb_download_data,代码如下:
  1. int fb_download_data(usb_handle *usb, const void *data, unsigned size)
  2. {
  3. char cmd[64];
  4. int r;
  5. sprintf(cmd, "download:%08x", size);
  6. r = _command_send(usb, cmd, data, size, 0);
  7. if(r < 0) {
  8. return -1;
  9. } else {
  10. return 0;
  11. }
  12. }
再看_command_send:
  1. static int _command_send(usb_handle *usb, const char *cmd,
  2. const void *data, unsigned size,
  3. char *response)
  4. {
  5. int r;
  6. if (size == 0) {
  7. return -1;
  8. }
  9. r = _command_start(usb, cmd, size, response);
  10. if (r < 0) {
  11. return -1;
  12. }
  13. r = _command_data(usb, data, size);
  14. if (r < 0) {
  15. return -1;
  16. }
  17. r = _command_end(usb);
  18. if(r < 0) {
  19. return -1;
  20. }
  21. return size;
  22. }
这里调用了三个函数:_command_start、_command_data与_command_end,如下:
  1. static int _command_start(usb_handle *usb, const char *cmd, unsigned size,
  2. char *response)
  3. {
  4. int cmdsize = strlen(cmd);
  5. int r;
  6. if(response) {
  7. response[0] = 0;
  8. }
  9. if(cmdsize > 64) {
  10. sprintf(ERROR,"command too large");
  11. return -1;
  12. }
  13. if(usb_write(usb, cmd, cmdsize) != cmdsize) {
  14. sprintf(ERROR,"command write failed (%s)", strerror(errno));
  15. usb_close(usb);
  16. return -1;
  17. }
  18. return check_response(usb, size, response);
  19. }
  1. static int _command_data(usb_handle *usb, const void *data, unsigned size)
  2. {
  3. int r;
  4. r = usb_write(usb, data, size);
  5. if(r < 0) {
  6. sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
  7. usb_close(usb);
  8. return -1;
  9. }
  10. if(r != ((int) size)) {
  11. sprintf(ERROR, "data transfer failure (short transfer)");
  12. usb_close(usb);
  13. return -1;
  14. }
  15. return r;
  16. }
  1. static int _command_end(usb_handle *usb)
  2. {
  3. int r;
  4. r = check_response(usb, 0, 0);
  5. if(r < 0) {
  6. return -1;
  7. }
  8. return 0;
  9. }
前面两个函数最终都调用了 usb_write将数据写下去,该函数实现如下:
  1. int usb_write(usb_handle *h, const void *_data, int len)
  2. {
  3. unsigned char *data = (unsigned char*) _data;
  4. unsigned count = 0;
  5. struct usbdevfs_bulktransfer bulk;
  6. int n;
  7. if(h->ep_out == 0) {
  8. return -1;
  9. }
  10. if(len == 0) {
  11. bulk.ep = h->ep_out;
  12. bulk.len = 0;
  13. bulk.data = data;
  14. bulk.timeout = 0;
  15. n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
  16. if(n != 0) {
  17. fprintf(stderr,"ERROR: n = %d, errno = %d (%s)\n",
  18. n, errno, strerror(errno));
  19. return -1;
  20. }
  21. return 0;
  22. }
  23. while(len > 0) {
  24. int xfer;
  25. xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
  26. bulk.ep = h->ep_out;
  27. bulk.len = xfer;
  28. bulk.data = data;
  29. bulk.timeout = 0;
  30. n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
  31. if(n != xfer) {
  32. DBG("ERROR: n = %d, errno = %d (%s)\n",
  33. n, errno, strerror(errno));
  34. return -1;
  35. }
  36. count += xfer;
  37. len -= xfer;
  38. data += xfer;
  39. }
  40. return count;
  41. }
第36行:调用ioctl将数据写到usb设备上。



























声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/298933
推荐阅读
相关标签
  

闽ICP备14008679号