赞
踩
说明:本流程基于Android4.4.2中的fastboot源代码讲解,该代码路径在"/system/core/fastboot"下。
- int main(int argc, char **argv)
- {
- int wants_wipe = 0;
- int wants_reboot = 0;
- int wants_reboot_bootloader = 0;
- int erase_first = 1;
- void *data;
- unsigned sz;
- int status;
- int c;
- int r;
-
- const struct option longopts[] = {
- {"base", required_argument, 0, 'b'},
- {"kernel_offset", required_argument, 0, 'k'},
- {"page_size", required_argument, 0, 'n'},
- {"ramdisk_offset", required_argument, 0, 'r'},
- {"help", 0, 0, 'h'},
- {0, 0, 0, 0}
- };
-
- serial = getenv("ANDROID_SERIAL");
-
- while (1) {
- int option_index = 0;
- c = getopt_long(argc, argv, "wub:k:n:r:s:S:lp:c:i:m:h", longopts, NULL);
- if (c < 0) {
- break;
- }
- /* Alphabetical cases */
- switch (c) {
- case 'b':
- base_addr = strtoul(optarg, 0, 16);
- break;
- case 'c':
- cmdline = optarg;
- break;
- case 'h':
- usage();
- return 1;
- case 'i': {
- char *endptr = NULL;
- unsigned long val;
-
- val = strtoul(optarg, &endptr, 0);
- if (!endptr || *endptr != '\0' || (val & ~0xffff))
- die("invalid vendor id '%s'", optarg);
- vendor_id = (unsigned short)val;
- break;
- }
- case 'k':
- kernel_offset = strtoul(optarg, 0, 16);
- break;
- case 'l':
- long_listing = 1;
- break;
- case 'n':
- page_size = (unsigned)strtoul(optarg, NULL, 0);
- if (!page_size) die("invalid page size");
- break;
- case 'p':
- product = optarg;
- break;
- case 'r':
- ramdisk_offset = strtoul(optarg, 0, 16);
- break;
- case 's':
- serial = optarg;
- break;
- case 'S':
- sparse_limit = parse_num(optarg);
- if (sparse_limit < 0) {
- die("invalid sparse limit");
- }
- break;
- case 'u':
- erase_first = 0;
- break;
- case 'w':
- wants_wipe = 1;
- break;
- case '?':
- return 1;
- default:
- abort();
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc == 0 && !wants_wipe) {
- usage();
- return 1;
- }
-
- if (argc > 0 && !strcmp(*argv, "devices")) {
- skip(1);
- list_devices();
- return 0;
- }
-
- if (argc > 0 && !strcmp(*argv, "help")) {
- usage();
- return 0;
- }
-
- usb = open_device();
-
- while (argc > 0) {
- if(!strcmp(*argv, "getvar")) {
- require(2);
- fb_queue_display(argv[1], argv[1]);
- skip(2);
- } else if(!strcmp(*argv, "erase")) {
- require(2);
-
- if (fb_format_supported(usb, argv[1])) {
- fprintf(stderr, "******** Did you mean to fastboot format this partition?\n");
- }
-
- fb_queue_erase(argv[1]);
- skip(2);
- } else if(!strcmp(*argv, "format")) {
- require(2);
- if (erase_first && needs_erase(argv[1])) {
- fb_queue_erase(argv[1]);
- }
- fb_queue_format(argv[1], 0);
- skip(2);
- } else if(!strcmp(*argv, "signature")) {
- require(2);
- data = load_file(argv[1], &sz);
- if (data == 0) die("could not load '%s': %s", argv[1], strerror(errno));
- if (sz != 256) die("signature must be 256 bytes");
- fb_queue_download("signature", data, sz);
- fb_queue_command("signature", "installing signature");
- skip(2);
- } else if(!strcmp(*argv, "reboot")) {
- wants_reboot = 1;
- skip(1);
- } else if(!strcmp(*argv, "reboot-bootloader")) {
- wants_reboot_bootloader = 1;
- skip(1);
- } else if (!strcmp(*argv, "continue")) {
- fb_queue_command("continue", "resuming boot");
- skip(1);
- } else if(!strcmp(*argv, "boot")) {
- char *kname = 0;
- char *rname = 0;
- skip(1);
- if (argc > 0) {
- kname = argv[0];
- skip(1);
- }
- if (argc > 0) {
- rname = argv[0];
- skip(1);
- }
- data = load_bootable_image(kname, rname, &sz, cmdline);
- if (data == 0) return 1;
- fb_queue_download("boot.img", data, sz);
- fb_queue_command("boot", "booting");
- } else if(!strcmp(*argv, "flash")) {
- char *pname = argv[1];
- char *fname = 0;
- require(2);
- if (argc > 2) {
- fname = argv[2];
- skip(3);
- } else {
- fname = find_item(pname, product);
- skip(2);
- }
- if (fname == 0) die("cannot determine image filename for '%s'", pname);
- if (erase_first && needs_erase(pname)) {
- fb_queue_erase(pname);
- }
- do_flash(usb, pname, fname);
- } else if(!strcmp(*argv, "flash:raw")) {
- char *pname = argv[1];
- char *kname = argv[2];
- char *rname = 0;
- require(3);
- if(argc > 3) {
- rname = argv[3];
- skip(4);
- } else {
- skip(3);
- }
- data = load_bootable_image(kname, rname, &sz, cmdline);
- if (data == 0) die("cannot load bootable image");
- fb_queue_flash(pname, data, sz);
- } else if(!strcmp(*argv, "flashall")) {
- skip(1);
- do_flashall(usb, erase_first);
- wants_reboot = 1;
- } else if(!strcmp(*argv, "update")) {
- if (argc > 1) {
- do_update(usb, argv[1], erase_first);
- skip(2);
- } else {
- do_update(usb, "update.zip", erase_first);
- skip(1);
- }
- wants_reboot = 1;
- } else if(!strcmp(*argv, "oem")) {
- argc = do_oem_command(argc, argv);
- } else {
- usage();
- return 1;
- }
- }
-
- if (wants_wipe) {
- fb_queue_erase("userdata");
- fb_queue_format("userdata", 1);
- fb_queue_erase("cache");
- fb_queue_format("cache", 1);
- }
- if (wants_reboot) {
- fb_queue_reboot();
- } else if (wants_reboot_bootloader) {
- fb_queue_command("reboot-bootloader", "rebooting into bootloader");
- }
-
- if (fb_queue_is_empty())
- return 0;
-
- status = fb_execute_queue(usb);
- return (status) ? 1 : 0;
- }
第108行:usb = open_device(); //打开单板设备对应的usb设备
- usb_handle *open_device(void)
- {
- static usb_handle *usb = 0;
- int announce = 1;
-
- if(usb) return usb;
-
- for(;;) {
- usb = usb_open(match_fastboot);
- if(usb) return usb;
- if(announce) {
- announce = 0;
- fprintf(stderr,"< waiting for device >\n");
- }
- sleep(1);
- }
- }
第8行到第15行是一个循环结构,如果没有找到可用的usb设备,则一直循环,并在第一次没有找到设备时打印“waiting for devece”;
第9行,使用usb_open函数打开usb设备,该函数针对不同的操作系统(windows,linux,os)有三种不同的实现,本文以linux为例。
- usb_handle *usb_open(ifc_match_func callback)
- {
- return find_usb_device("/dev/bus/usb", callback);
- }
usb_open函数的第三行,它调用了find_usb_device函数,并以"/dev/bus/usb"作为第一个参数,以callback作为第二个参数。
1.1.1 find_usb_device
- static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
- {
- usb_handle *usb = 0;
- char busname[64], devname[64];
- char desc[1024];
- int n, in, out, ifc;
-
- DIR *busdir, *devdir;
- struct dirent *de;
- int fd;
- int writable;
-
- busdir = opendir(base);
- if(busdir == 0) return 0;
-
- while((de = readdir(busdir)) && (usb == 0)) {
- if(badname(de->d_name)) continue;
-
- sprintf(busname, "%s/%s", base, de->d_name);
- devdir = opendir(busname);
- if(devdir == 0) continue;
-
- // DBG("[ scanning %s ]\n", busname);
- while((de = readdir(devdir)) && (usb == 0)) {
-
- if(badname(de->d_name)) continue;
- sprintf(devname, "%s/%s", busname, de->d_name);
-
- // DBG("[ scanning %s ]\n", devname);
- writable = 1;
- if((fd = open(devname, O_RDWR)) < 0) {
- // Check if we have read-only access, so we can give a helpful
- // diagnostic like "adb devices" does.
- writable = 0;
- if((fd = open(devname, O_RDONLY)) < 0) {
- continue;
- }
- }
-
- n = read(fd, desc, sizeof(desc));
-
- if(filter_usb_device(fd, desc, n, writable, callback,
- &in, &out, &ifc) == 0) {
- usb = calloc(1, sizeof(usb_handle));
- strcpy(usb->fname, devname);
- usb->ep_in = in;
- usb->ep_out = out;
- usb->desc = fd;
-
- n = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &ifc);
- if(n != 0) {
- close(fd);
- free(usb);
- usb = 0;
- continue;
- }
- } else {
- close(fd);
- }
- }
- closedir(devdir);
- }
- closedir(busdir);
-
- return usb;
- }
先来看一下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设备,代码如下
- static int filter_usb_device(int fd, char *ptr, int len, int writable,
- ifc_match_func callback,
- int *ept_in_id, int *ept_out_id, int *ifc_id)
- {
- struct usb_device_descriptor *dev;
- struct usb_config_descriptor *cfg;
- struct usb_interface_descriptor *ifc;
- struct usb_endpoint_descriptor *ept;
- struct usb_ifc_info info;
-
- int in, out;
- unsigned i;
- unsigned e;
-
- struct stat st;
- int result;
-
- if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
- return -1;
- dev = (void*) ptr;
- len -= dev->bLength;
- ptr += dev->bLength;
-
- if(check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
- return -1;
- cfg = (void*) ptr;
- len -= cfg->bLength;
- ptr += cfg->bLength;
-
- info.dev_vendor = dev->idVendor;
- info.dev_product = dev->idProduct;
- info.dev_class = dev->bDeviceClass;
- info.dev_subclass = dev->bDeviceSubClass;
- info.dev_protocol = dev->bDeviceProtocol;
- info.writable = writable;
-
- // read device serial number (if there is one)
- info.serial_number[0] = 0;
- if (dev->iSerialNumber) {
- struct usbdevfs_ctrltransfer ctrl;
- // Keep it short enough because some bootloaders are borked if the URB len is > 255
- // 128 is too big by 1.
- __u16 buffer[127];
-
- memset(buffer, 0, sizeof(buffer));
-
- ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
- ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
- ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
- //language ID (en-us) for serial number string
- ctrl.wIndex = 0x0409;
- ctrl.wLength = sizeof(buffer);
- ctrl.data = buffer;
- ctrl.timeout = 50;
-
- result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
- if (result > 0) {
- int i;
- // skip first word, and copy the rest to the serial string, changing shorts to bytes.
- result /= 2;
- for (i = 1; i < result; i++)
- info.serial_number[i - 1] = buffer[i];
- info.serial_number[i - 1] = 0;
- }
- }
-
- /* We need to get a path that represents a particular port on a particular
- * hub. We are passed an fd that was obtained by opening an entry under
- * /dev/bus/usb. Unfortunately, the names of those entries change each
- * time devices are plugged and unplugged. So how to get a repeatable
- * path? udevadm provided the inspiration. We can get the major and
- * minor of the device file, read the symlink that can be found here:
- * /sys/dev/char/<major>:<minor>
- * and then use the last element of that path. As a concrete example, I
- * have an Android device at /dev/bus/usb/001/027 so working with bash:
- * $ ls -l /dev/bus/usb/001/027
- * crw-rw-r-- 1 root plugdev 189, 26 Apr 9 11:03 /dev/bus/usb/001/027
- * $ ls -l /sys/dev/char/189:26
- * lrwxrwxrwx 1 root root 0 Apr 9 11:03 /sys/dev/char/189:26 ->
- * ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3
- * So our device_path would be 1-4.2.3 which says my device is connected
- * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per
- * http://www.linux-usb.org/FAQ.html).
- */
- info.device_path[0] = '\0';
- result = fstat(fd, &st);
- if (!result && S_ISCHR(st.st_mode)) {
- char cdev[128];
- char link[256];
- char *slash;
- ssize_t link_len;
- snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d",
- major(st.st_rdev), minor(st.st_rdev));
- link_len = readlink(cdev, link, sizeof(link) - 1);
- if (link_len > 0) {
- link[link_len] = '\0';
- slash = strrchr(link, '/');
- if (slash)
- snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1);
- }
- }
-
- for(i = 0; i < cfg->bNumInterfaces; i++) {
- if(check(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE))
- return -1;
- ifc = (void*) ptr;
- len -= ifc->bLength;
- ptr += ifc->bLength;
-
- in = -1;
- out = -1;
- info.ifc_class = ifc->bInterfaceClass;
- info.ifc_subclass = ifc->bInterfaceSubClass;
- info.ifc_protocol = ifc->bInterfaceProtocol;
-
- for(e = 0; e < ifc->bNumEndpoints; e++) {
- if(check(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE))
- return -1;
- ept = (void*) ptr;
- len -= ept->bLength;
- ptr += ept->bLength;
-
- if((ept->bmAttributes & 0x03) != 0x02)
- continue;
-
- if(ept->bEndpointAddress & 0x80) {
- in = ept->bEndpointAddress;
- } else {
- out = ept->bEndpointAddress;
- }
- }
-
- info.has_bulk_in = (in != -1);
- info.has_bulk_out = (out != -1);
-
- if(callback(&info) == 0) {
- *ept_in_id = in;
- *ept_out_id = out;
- *ifc_id = ifc->bInterfaceNumber;
- return 0;
- }
- }
-
- return -1;
- }
第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函数,代码如下所示:
- int match_fastboot(usb_ifc_info *info)
- {
- return match_fastboot_with_serial(info, serial);
- }
- int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
- {
- if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
- (info->dev_vendor != 0x18d1) && // Google
- (info->dev_vendor != 0x8087) && // Intel
- (info->dev_vendor != 0x0451) &&
- (info->dev_vendor != 0x0502) &&
- (info->dev_vendor != 0x0fce) && // Sony Ericsson
- (info->dev_vendor != 0x05c6) && // Qualcomm
- (info->dev_vendor != 0x22b8) && // Motorola
- (info->dev_vendor != 0x0955) && // Nvidia
- (info->dev_vendor != 0x413c) && // DELL
- (info->dev_vendor != 0x2314) && // INQ Mobile
- (info->dev_vendor != 0x0b05) && // Asus
- (info->dev_vendor != 0x0bb4)) // HTC
- return -1;
- if(info->ifc_class != 0xff) return -1;
- if(info->ifc_subclass != 0x42) return -1;
- if(info->ifc_protocol != 0x03) return -1;
- // require matching serial number or device path if requested
- // at the command line with the -s option.
- if (local_serial && (strcmp(local_serial, info->serial_number) != 0 &&
- strcmp(local_serial, info->device_path) != 0)) return -1;
- return 0;
- }
回到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写到设备上,下面我们分析该函数。
- void do_flash(usb_handle *usb, const char *pname, const char *fname)
- {
- struct fastboot_buffer buf;
-
- if (load_buf(usb, fname, &buf)) {
- die("cannot load '%s'", fname);
- }
- flash_buf(pname, &buf);
- }
- static int load_buf(usb_handle *usb, const char *fname,
- struct fastboot_buffer *buf)
- {
- int fd;
-
- fd = open(fname, O_RDONLY | O_BINARY);
- if (fd < 0) {
- die("cannot open '%s'\n", fname);
- }
-
- return load_buf_fd(usb, fd, buf);
- }
- static int load_buf_fd(usb_handle *usb, int fd,
- struct fastboot_buffer *buf)
- {
- int64_t sz64;
- void *data;
- int64_t limit;
-
- sz64 = file_size(fd);
- if (sz64 < 0) {
- return -1;
- }
- limit = get_sparse_limit(usb, sz64);
- if (limit) {
- struct sparse_file **s = load_sparse_files(fd, limit);
- if (s == NULL) {
- return -1;
- }
- buf->type = FB_BUFFER_SPARSE;
- buf->data = s;
- } else {
- unsigned int sz;
- data = load_fd(fd, &sz);
- if (data == 0) return -1;
- buf->type = FB_BUFFER;
- buf->data = data;
- buf->sz = sz;
- }
-
- return 0;
- }
将数据加载到了buf。
- static void flash_buf(const char *pname, struct fastboot_buffer *buf)
- {
- struct sparse_file **s;
-
- switch (buf->type) {
- case FB_BUFFER_SPARSE:
- s = buf->data;
- while (*s) {
- int64_t sz64 = sparse_file_len(*s, true, false);
- fb_queue_flash_sparse(pname, *s++, sz64);
- }
- break;
- case FB_BUFFER:
- fb_queue_flash(pname, buf->data, buf->sz);
- break;
- default:
- die("unknown buffer type: %d", buf->type);
- }
- }
2.2.1、fb_queue_flash
- void fb_queue_flash(const char *ptn, void *data, unsigned sz)
- {
- Action *a;
-
- a = queue_action(OP_DOWNLOAD, "");
- a->data = data;
- a->size = sz;
- a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
-
- a = queue_action(OP_COMMAND, "flash:%s", ptn);
- a->msg = mkmsg("writing '%s'", ptn);
- }
这个函数看似将数据放到了变量a里面,我们来看一下queue_action函数
- static Action *queue_action(unsigned op, const char *fmt, ...)
- {
- Action *a;
- va_list ap;
- size_t cmdsize;
-
- a = calloc(1, sizeof(Action));
- if (a == 0) die("out of memory");
-
- va_start(ap, fmt);
- cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
- va_end(ap);
-
- if (cmdsize >= sizeof(a->cmd)) {
- free(a);
- die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd));
- }
-
- if (action_last) {
- action_last->next = a;
- } else {
- action_list = a;
- }
- action_last = a;
- a->op = op;
- a->func = cb_default;
-
- a->start = -1;
-
- return a;
- }
原来a是action_list链表中的一个元素,也就是将要写的数据保存到了链表
action_list中。
- int fb_execute_queue(usb_handle *usb)
- {
- Action *a;
- char resp[FB_RESPONSE_SZ+1];
- int status = 0;
-
- a = action_list;
- if (!a)
- return status;
- resp[FB_RESPONSE_SZ] = 0;
-
- double start = -1;
- for (a = action_list; a; a = a->next) {
- a->start = now();
- if (start < 0) start = a->start;
- if (a->msg) {
- // fprintf(stderr,"%30s... ",a->msg);
- fprintf(stderr,"%s...\n",a->msg);
- }
- if (a->op == OP_DOWNLOAD) {
- status = fb_download_data(usb, a->data, a->size);
- status = a->func(a, status, status ? fb_get_error() : "");
- if (status) break;
- } else if (a->op == OP_COMMAND) {
- status = fb_command(usb, a->cmd);
- status = a->func(a, status, status ? fb_get_error() : "");
- if (status) break;
- } else if (a->op == OP_QUERY) {
- status = fb_command_response(usb, a->cmd, resp);
- status = a->func(a, status, status ? fb_get_error() : resp);
- if (status) break;
- } else if (a->op == OP_NOTICE) {
- fprintf(stderr,"%s\n",(char*)a->data);
- } else if (a->op == OP_FORMAT) {
- status = fb_format(a, usb, (int)a->data);
- status = a->func(a, status, status ? fb_get_error() : "");
- if (status) break;
- } else if (a->op == OP_DOWNLOAD_SPARSE) {
- status = fb_download_data_sparse(usb, a->data);
- status = a->func(a, status, status ? fb_get_error() : "");
- if (status) break;
- } else {
- die("bogus action");
- }
- }
-
- fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
- return status;
- }
这里,我们只分析OP_DOWNLOAD分支,请看:
- int fb_download_data(usb_handle *usb, const void *data, unsigned size)
- {
- char cmd[64];
- int r;
-
- sprintf(cmd, "download:%08x", size);
- r = _command_send(usb, cmd, data, size, 0);
-
- if(r < 0) {
- return -1;
- } else {
- return 0;
- }
- }
再看_command_send:
- static int _command_send(usb_handle *usb, const char *cmd,
- const void *data, unsigned size,
- char *response)
- {
- int r;
- if (size == 0) {
- return -1;
- }
-
- r = _command_start(usb, cmd, size, response);
- if (r < 0) {
- return -1;
- }
-
- r = _command_data(usb, data, size);
- if (r < 0) {
- return -1;
- }
-
- r = _command_end(usb);
- if(r < 0) {
- return -1;
- }
-
- return size;
- }
这里调用了三个函数:_command_start、_command_data与_command_end,如下:
- static int _command_start(usb_handle *usb, const char *cmd, unsigned size,
- char *response)
- {
- int cmdsize = strlen(cmd);
- int r;
-
- if(response) {
- response[0] = 0;
- }
-
- if(cmdsize > 64) {
- sprintf(ERROR,"command too large");
- return -1;
- }
-
- if(usb_write(usb, cmd, cmdsize) != cmdsize) {
- sprintf(ERROR,"command write failed (%s)", strerror(errno));
- usb_close(usb);
- return -1;
- }
-
- return check_response(usb, size, response);
- }
- static int _command_data(usb_handle *usb, const void *data, unsigned size)
- {
- int r;
-
- r = usb_write(usb, data, size);
- if(r < 0) {
- sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
- usb_close(usb);
- return -1;
- }
- if(r != ((int) size)) {
- sprintf(ERROR, "data transfer failure (short transfer)");
- usb_close(usb);
- return -1;
- }
-
- return r;
- }
- static int _command_end(usb_handle *usb)
- {
- int r;
- r = check_response(usb, 0, 0);
- if(r < 0) {
- return -1;
- }
- return 0;
- }
前面两个函数最终都调用了
usb_write将数据写下去,该函数实现如下:
- int usb_write(usb_handle *h, const void *_data, int len)
- {
- unsigned char *data = (unsigned char*) _data;
- unsigned count = 0;
- struct usbdevfs_bulktransfer bulk;
- int n;
-
- if(h->ep_out == 0) {
- return -1;
- }
-
- if(len == 0) {
- bulk.ep = h->ep_out;
- bulk.len = 0;
- bulk.data = data;
- bulk.timeout = 0;
-
- n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
- if(n != 0) {
- fprintf(stderr,"ERROR: n = %d, errno = %d (%s)\n",
- n, errno, strerror(errno));
- return -1;
- }
- return 0;
- }
-
- while(len > 0) {
- int xfer;
- xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
-
- bulk.ep = h->ep_out;
- bulk.len = xfer;
- bulk.data = data;
- bulk.timeout = 0;
-
- n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
- if(n != xfer) {
- DBG("ERROR: n = %d, errno = %d (%s)\n",
- n, errno, strerror(errno));
- return -1;
- }
-
- count += xfer;
- len -= xfer;
- data += xfer;
- }
-
- return count;
- }
第36行:调用ioctl将数据写到usb设备上。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。