1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include <stdio.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <stdint.h> 32 #include <string.h> 33 #include <getopt.h> 34 35 #include <usb.h> 36 37 #ifdef NEED_USB_GET_BUSSES 38 static inline struct usb_bus *usb_get_busses(void) 39 { 40 return usb_busses; 41 } 42 #endif 43 44 struct device_info; 45 46 struct device_id { 47 uint16_t vendor; 48 uint16_t product; 49 int (*func)(struct device_info *dev, int argc, char *argv[]); 50 }; 51 52 struct device_info { 53 struct usb_device *dev; 54 struct device_id *id; 55 }; 56 57 static int switch_babel(struct device_info *devinfo, int argc, char *argv[]) 58 { 59 char buf[3]; 60 struct usb_dev_handle *udev; 61 int err; 62 63 memset(buf, 0, sizeof(buf)); 64 65 buf[0] = 0x00; 66 buf[1] = 0x06; 67 buf[2] = 0x00; 68 69 udev = usb_open(devinfo->dev); 70 if (!udev) 71 return -errno; 72 73 if (usb_claim_interface(udev, 0) < 0) { 74 err = -errno; 75 usb_close(udev); 76 return err; 77 } 78 79 err = usb_bulk_write(udev, 0x02, buf, sizeof(buf), 10000); 80 81 if (err == 0) { 82 err = -1; 83 errno = EALREADY; 84 } else { 85 if (errno == ETIMEDOUT) 86 err = 0; 87 } 88 89 usb_release_interface(udev, 0); 90 usb_close(udev); 91 92 return err; 93 } 94 95 static struct device_id device_list[] = { 96 { 0x0a12, 0x0042, switch_babel }, 97 { -1 } 98 }; 99 100 static struct device_id *match_device(uint16_t vendor, uint16_t product) 101 { 102 int i; 103 104 for (i = 0; device_list[i].func; i++) { 105 if (vendor == device_list[i].vendor && 106 product == device_list[i].product) 107 return &device_list[i]; 108 } 109 110 return NULL; 111 } 112 113 static int find_devices(struct device_info *devinfo, size_t size) 114 { 115 struct usb_bus *bus; 116 struct usb_device *dev; 117 struct device_id *id; 118 unsigned int count = 0; 119 120 usb_find_busses(); 121 usb_find_devices(); 122 123 for (bus = usb_get_busses(); bus; bus = bus->next) 124 for (dev = bus->devices; dev; dev = dev->next) { 125 id = match_device(dev->descriptor.idVendor, 126 dev->descriptor.idProduct); 127 if (!id) 128 continue; 129 130 if (count < size) { 131 devinfo[count].dev = dev; 132 devinfo[count].id = id; 133 count++; 134 } 135 } 136 137 return count; 138 } 139 140 static void usage(void) 141 { 142 printf("dfubabel - Babel DFU mode switching utility\n\n"); 143 144 printf("Usage:\n" 145 "\tdfubabel [options]\n" 146 "\n"); 147 148 printf("Options:\n" 149 "\t-h, --help Display help\n" 150 "\t-q, --quiet Don't display any messages\n" 151 "\n"); 152 } 153 154 static struct option main_options[] = { 155 { "help", 0, 0, 'h' }, 156 { "quiet", 0, 0, 'q' }, 157 { 0, 0, 0, 0 } 158 }; 159 160 int main(int argc, char *argv[]) 161 { 162 struct device_info dev[16]; 163 int i, opt, num, quiet = 0; 164 165 while ((opt = getopt_long(argc, argv, "+qh", main_options, NULL)) != -1) { 166 switch (opt) { 167 case 'q': 168 quiet = 1; 169 break; 170 case 'h': 171 usage(); 172 exit(0); 173 default: 174 exit(0); 175 } 176 } 177 178 argc -= optind; 179 argv += optind; 180 optind = 0; 181 182 usb_init(); 183 184 num = find_devices(dev, sizeof(dev) / sizeof(dev[0])); 185 if (num <= 0) { 186 if (!quiet) 187 fprintf(stderr, "No Babel devices found\n"); 188 exit(1); 189 } 190 191 for (i = 0; i < num; i++) { 192 struct device_id *id = dev[i].id; 193 int err; 194 195 if (!quiet) 196 printf("Switching device %04x:%04x ", 197 id->vendor, id->product); 198 fflush(stdout); 199 200 err = id->func(&dev[i], argc, argv); 201 if (err < 0) { 202 if (!quiet) 203 printf("failed (%s)\n", strerror(-err)); 204 } else { 205 if (!quiet) 206 printf("was successful\n"); 207 } 208 } 209 210 return 0; 211 } 212