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 <string.h> 31 32 #include <usb.h> 33 34 #include "csr.h" 35 36 #ifdef NEED_USB_GET_BUSSES 37 static inline struct usb_bus *usb_get_busses(void) 38 { 39 return usb_busses; 40 } 41 #endif 42 43 #ifdef NEED_USB_INTERRUPT_READ 44 static inline int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) 45 { 46 return usb_bulk_read(dev, ep, bytes, size, timeout); 47 } 48 #endif 49 50 #ifndef USB_DIR_OUT 51 #define USB_DIR_OUT 0x00 52 #endif 53 54 static uint16_t seqnum = 0x0000; 55 56 static struct usb_dev_handle *udev = NULL; 57 58 int csr_open_usb(char *device) 59 { 60 struct usb_bus *bus; 61 struct usb_device *dev; 62 63 usb_init(); 64 65 usb_find_busses(); 66 usb_find_devices(); 67 68 for (bus = usb_get_busses(); bus; bus = bus->next) { 69 for (dev = bus->devices; dev; dev = dev->next) { 70 if (dev->descriptor.bDeviceClass == USB_CLASS_HUB) 71 continue; 72 73 if (dev->descriptor.idVendor != 0x0a12 || 74 dev->descriptor.idProduct != 0x0001) 75 continue; 76 77 goto found; 78 } 79 } 80 81 fprintf(stderr, "Device not available\n"); 82 83 return -1; 84 85 found: 86 udev = usb_open(dev); 87 if (!udev) { 88 fprintf(stderr, "Can't open device: %s (%d)\n", 89 strerror(errno), errno); 90 return -1; 91 } 92 93 if (usb_claim_interface(udev, 0) < 0) { 94 fprintf(stderr, "Can't claim interface: %s (%d)\n", 95 strerror(errno), errno); 96 usb_close(udev); 97 return -1; 98 } 99 100 return 0; 101 } 102 103 static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length) 104 { 105 unsigned char cp[254], rp[254]; 106 uint8_t cmd[10]; 107 uint16_t size; 108 int len, offset = 0; 109 110 size = (length < 8) ? 9 : ((length + 1) / 2) + 5; 111 112 cmd[0] = command & 0xff; 113 cmd[1] = command >> 8; 114 cmd[2] = size & 0xff; 115 cmd[3] = size >> 8; 116 cmd[4] = seqnum & 0xff; 117 cmd[5] = seqnum >> 8; 118 cmd[6] = varid & 0xff; 119 cmd[7] = varid >> 8; 120 cmd[8] = 0x00; 121 cmd[9] = 0x00; 122 123 memset(cp, 0, sizeof(cp)); 124 cp[0] = 0x00; 125 cp[1] = 0xfc; 126 cp[2] = (size * 2) + 1; 127 cp[3] = 0xc2; 128 memcpy(cp + 4, cmd, sizeof(cmd)); 129 memcpy(cp + 14, value, length); 130 131 usb_interrupt_read(udev, 0x81, (void *) rp, sizeof(rp), 2); 132 133 if (usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_DEVICE, 134 0, 0, 0, (void *) cp, (size * 2) + 4, 1000) < 0) 135 return -1; 136 137 switch (varid) { 138 case CSR_VARID_COLD_RESET: 139 case CSR_VARID_WARM_RESET: 140 case CSR_VARID_COLD_HALT: 141 case CSR_VARID_WARM_HALT: 142 return 0; 143 } 144 145 do { 146 len = usb_interrupt_read(udev, 0x81, 147 (void *) (rp + offset), sizeof(rp) - offset, 10); 148 offset += len; 149 } while (len > 0); 150 151 if (rp[0] != 0xff || rp[2] != 0xc2) { 152 errno = EIO; 153 return -1; 154 } 155 156 if ((rp[11] + (rp[12] << 8)) != 0) { 157 errno = ENXIO; 158 return -1; 159 } 160 161 memcpy(value, rp + 13, length); 162 163 return 0; 164 } 165 166 int csr_read_usb(uint16_t varid, uint8_t *value, uint16_t length) 167 { 168 return do_command(0x0000, seqnum++, varid, value, length); 169 } 170 171 int csr_write_usb(uint16_t varid, uint8_t *value, uint16_t length) 172 { 173 return do_command(0x0002, seqnum++, varid, value, length); 174 } 175 176 void csr_close_usb(void) 177 { 178 usb_release_interface(udev, 0); 179 usb_close(udev); 180 } 181