Home | History | Annotate | Download | only in tools
      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 <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