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 #include <sys/socket.h>
     32 
     33 #include <bluetooth/bluetooth.h>
     34 #include <bluetooth/hci.h>
     35 #include <bluetooth/hci_lib.h>
     36 
     37 #include "csr.h"
     38 
     39 static uint16_t seqnum = 0x0000;
     40 
     41 static int dd = -1;
     42 
     43 int csr_open_hci(char *device)
     44 {
     45 	struct hci_dev_info di;
     46 	struct hci_version ver;
     47 	int dev = 0;
     48 
     49 	if (device) {
     50 		dev = hci_devid(device);
     51 		if (dev < 0) {
     52 			fprintf(stderr, "Device not available\n");
     53 			return -1;
     54 		}
     55 	}
     56 
     57 	dd = hci_open_dev(dev);
     58 	if (dd < 0) {
     59 		fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
     60 						dev, strerror(errno), errno);
     61 		return -1;
     62 	}
     63 
     64 	if (hci_devinfo(dev, &di) < 0) {
     65 		fprintf(stderr, "Can't get device info for hci%d: %s (%d)\n",
     66 						dev, strerror(errno), errno);
     67 		hci_close_dev(dd);
     68 		return -1;
     69 	}
     70 
     71 	if (hci_read_local_version(dd, &ver, 1000) < 0) {
     72 		fprintf(stderr, "Can't read version info for hci%d: %s (%d)\n",
     73 						dev, strerror(errno), errno);
     74 		hci_close_dev(dd);
     75 		return -1;
     76 	}
     77 
     78 	if (ver.manufacturer != 10) {
     79 		fprintf(stderr, "Unsupported manufacturer\n");
     80 		hci_close_dev(dd);
     81 		return -1;
     82 	}
     83 
     84 	return 0;
     85 }
     86 
     87 static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
     88 {
     89 	unsigned char cp[254], rp[254];
     90 	struct hci_request rq;
     91 	uint8_t cmd[10];
     92 	uint16_t size;
     93 
     94 	size = (length < 8) ? 9 : ((length + 1) / 2) + 5;
     95 
     96 	cmd[0] = command & 0xff;
     97 	cmd[1] = command >> 8;
     98 	cmd[2] = size & 0xff;
     99 	cmd[3] = size >> 8;
    100 	cmd[4] = seqnum & 0xff;
    101 	cmd[5] = seqnum >> 8;
    102 	cmd[6] = varid & 0xff;
    103 	cmd[7] = varid >> 8;
    104 	cmd[8] = 0x00;
    105 	cmd[9] = 0x00;
    106 
    107 	memset(cp, 0, sizeof(cp));
    108 	cp[0] = 0xc2;
    109 	memcpy(cp + 1, cmd, sizeof(cmd));
    110 	memcpy(cp + 11, value, length);
    111 
    112 	switch (varid) {
    113 	case CSR_VARID_COLD_RESET:
    114 	case CSR_VARID_WARM_RESET:
    115 	case CSR_VARID_COLD_HALT:
    116 	case CSR_VARID_WARM_HALT:
    117 		return hci_send_cmd(dd, OGF_VENDOR_CMD, 0x00, (size * 2) + 1, cp);
    118 	}
    119 
    120 	memset(&rq, 0, sizeof(rq));
    121 	rq.ogf    = OGF_VENDOR_CMD;
    122 	rq.ocf    = 0x00;
    123 	rq.event  = EVT_VENDOR;
    124 	rq.cparam = cp;
    125 	rq.clen   = (size * 2) + 1;
    126 	rq.rparam = rp;
    127 	rq.rlen   = sizeof(rp);
    128 
    129 	if (hci_send_req(dd, &rq, 2000) < 0)
    130 		return -1;
    131 
    132 	if (rp[0] != 0xc2) {
    133 		errno = EIO;
    134 		return -1;
    135 	}
    136 
    137 	if ((rp[9] + (rp[10] << 8)) != 0) {
    138 		errno = ENXIO;
    139 		return -1;
    140 	}
    141 
    142 	memcpy(value, rp + 11, length);
    143 
    144 	return 0;
    145 }
    146 
    147 int csr_read_hci(uint16_t varid, uint8_t *value, uint16_t length)
    148 {
    149 	return do_command(0x0000, seqnum++, varid, value, length);
    150 }
    151 
    152 int csr_write_hci(uint16_t varid, uint8_t *value, uint16_t length)
    153 {
    154 	return do_command(0x0002, seqnum++, varid, value, length);
    155 }
    156 
    157 void csr_close_hci(void)
    158 {
    159 	hci_close_dev(dd);
    160 }
    161