1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2009 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 #ifndef USB_DIR_OUT 45 #define USB_DIR_OUT 0x00 46 #endif 47 48 #ifndef USB_DIR_IN 49 #define USB_DIR_IN 0x80 50 #endif 51 52 #define HID_REQ_GET_REPORT 0x01 53 #define HID_REQ_GET_IDLE 0x02 54 #define HID_REQ_GET_PROTOCOL 0x03 55 #define HID_REQ_SET_REPORT 0x09 56 #define HID_REQ_SET_IDLE 0x0a 57 #define HID_REQ_SET_PROTOCOL 0x0b 58 59 struct device_info; 60 61 struct device_id { 62 uint16_t vendor; 63 uint16_t product; 64 int (*func)(struct device_info *dev, int argc, char *argv[]); 65 }; 66 67 struct device_info { 68 struct usb_device *dev; 69 struct device_id *id; 70 }; 71 72 #define GET_STATE 0x01 73 #define GET_REMOTE_BDADDR 0x02 74 #define DISCOVER 0x03 75 #define SWITCH_TO_DFU 0x04 76 #define READ_CODEC 0x05 77 78 static int dongle_csr(struct device_info *devinfo, int argc, char *argv[]) 79 { 80 char buf[8]; 81 struct usb_dev_handle *udev; 82 int err, intf = 2; 83 84 memset(buf, 0, sizeof(buf)); 85 86 if (!strncasecmp(argv[0], "discover", 4)) 87 buf[0] = DISCOVER; 88 else if (!strncasecmp(argv[0], "switch", 3)) 89 buf[0] = SWITCH_TO_DFU; 90 else if (!strncasecmp(argv[0], "dfu", 3)) 91 buf[0] = SWITCH_TO_DFU; 92 else 93 return -EINVAL; 94 95 udev = usb_open(devinfo->dev); 96 if (!udev) 97 return -errno; 98 99 if (usb_claim_interface(udev, intf) < 0) { 100 err = -errno; 101 usb_close(udev); 102 return err; 103 } 104 105 err = usb_control_msg(udev, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 106 HID_REQ_SET_REPORT, 0x03 << 8, intf, buf, sizeof(buf), 10000); 107 108 if (err == 0) { 109 err = -1; 110 errno = EALREADY; 111 } else { 112 if (errno == ETIMEDOUT) 113 err = 0; 114 } 115 116 usb_release_interface(udev, intf); 117 usb_close(udev); 118 119 return err; 120 } 121 122 static struct device_id device_list[] = { 123 { 0x0a12, 0x1004, dongle_csr }, 124 { -1 } 125 }; 126 127 static struct device_id *match_device(uint16_t vendor, uint16_t product) 128 { 129 int i; 130 131 for (i = 0; device_list[i].func; i++) { 132 if (vendor == device_list[i].vendor && 133 product == device_list[i].product) 134 return &device_list[i]; 135 } 136 137 return NULL; 138 } 139 140 static int find_devices(struct device_info *devinfo, size_t size) 141 { 142 struct usb_bus *bus; 143 struct usb_device *dev; 144 struct device_id *id; 145 unsigned int count = 0; 146 147 usb_find_busses(); 148 usb_find_devices(); 149 150 for (bus = usb_get_busses(); bus; bus = bus->next) 151 for (dev = bus->devices; dev; dev = dev->next) { 152 id = match_device(dev->descriptor.idVendor, 153 dev->descriptor.idProduct); 154 if (!id) 155 continue; 156 157 if (count < size) { 158 devinfo[count].dev = dev; 159 devinfo[count].id = id; 160 count++; 161 } 162 } 163 164 return count; 165 } 166 167 static void usage(void) 168 { 169 printf("avctrl - Bluetooth Audio/Video control utility\n\n"); 170 171 printf("Usage:\n" 172 "\tavctrl [options] <command>\n" 173 "\n"); 174 175 printf("Options:\n" 176 "\t-h, --help Display help\n" 177 "\t-q, --quiet Don't display any messages\n" 178 "\n"); 179 180 printf("Commands:\n" 181 "\tdiscover Simulate pressing the discover button\n" 182 "\tswitch Switch the dongle to DFU mode\n" 183 "\n"); 184 } 185 186 static struct option main_options[] = { 187 { "help", 0, 0, 'h' }, 188 { "quiet", 0, 0, 'q' }, 189 { 0, 0, 0, 0 } 190 }; 191 192 int main(int argc, char *argv[]) 193 { 194 struct device_info dev[16]; 195 int i, opt, num, quiet = 0; 196 197 while ((opt = getopt_long(argc, argv, "+qh", main_options, NULL)) != -1) { 198 switch (opt) { 199 case 'q': 200 quiet = 1; 201 break; 202 case 'h': 203 usage(); 204 exit(0); 205 default: 206 exit(0); 207 } 208 } 209 210 argc -= optind; 211 argv += optind; 212 optind = 0; 213 214 if (argc < 1) { 215 usage(); 216 exit(1); 217 } 218 219 usb_init(); 220 221 num = find_devices(dev, sizeof(dev) / sizeof(dev[0])); 222 if (num <= 0) { 223 if (!quiet) 224 fprintf(stderr, "No Audio/Video devices found\n"); 225 exit(1); 226 } 227 228 for (i = 0; i < num; i++) { 229 struct device_id *id = dev[i].id; 230 int err; 231 232 if (!quiet) 233 printf("Selecting device %04x:%04x ", 234 id->vendor, id->product); 235 fflush(stdout); 236 237 err = id->func(&dev[i], argc, argv); 238 if (err < 0) { 239 if (!quiet) 240 printf("failed (%s)\n", strerror(-err)); 241 } else { 242 if (!quiet) 243 printf("was successful\n"); 244 } 245 } 246 247 return 0; 248 } 249