1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@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 39static uint16_t seqnum = 0x0000; 40 41static int dd = -1; 42 43int 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 87static 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 147int csr_read_hci(uint16_t varid, uint8_t *value, uint16_t length) 148{ 149 return do_command(0x0000, seqnum++, varid, value, length); 150} 151 152int csr_write_hci(uint16_t varid, uint8_t *value, uint16_t length) 153{ 154 return do_command(0x0002, seqnum++, varid, value, length); 155} 156 157void csr_close_hci(void) 158{ 159 hci_close_dev(dd); 160} 161