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 <fcntl.h>
     31 #include <unistd.h>
     32 #include <string.h>
     33 #include <stdint.h>
     34 #include <termios.h>
     35 
     36 #include "csr.h"
     37 
     38 static uint16_t seqnum = 0x0000;
     39 
     40 static int fd = -1;
     41 
     42 int csr_open_h4(char *device)
     43 {
     44 	struct termios ti;
     45 
     46 	if (!device)
     47 		device = "/dev/ttyS0";
     48 
     49 	fd = open(device, O_RDWR | O_NOCTTY);
     50 	if (fd < 0) {
     51 		fprintf(stderr, "Can't open serial port: %s (%d)\n",
     52 						strerror(errno), errno);
     53 		return -1;
     54 	}
     55 
     56 	tcflush(fd, TCIOFLUSH);
     57 
     58 	if (tcgetattr(fd, &ti) < 0) {
     59 		fprintf(stderr, "Can't get port settings: %s (%d)\n",
     60 						strerror(errno), errno);
     61 		close(fd);
     62 		return -1;
     63 	}
     64 
     65 	cfmakeraw(&ti);
     66 
     67 	ti.c_cflag |= CLOCAL;
     68 	ti.c_cflag |= CRTSCTS;
     69 
     70 	cfsetospeed(&ti, B38400);
     71 
     72 	if (tcsetattr(fd, TCSANOW, &ti) < 0) {
     73 		fprintf(stderr, "Can't change port settings: %s (%d)\n",
     74 						strerror(errno), errno);
     75 		close(fd);
     76 		return -1;
     77 	}
     78 
     79 	tcflush(fd, TCIOFLUSH);
     80 
     81 	return 0;
     82 }
     83 
     84 static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
     85 {
     86 	unsigned char cp[254], rp[254];
     87 	uint8_t cmd[10];
     88 	uint16_t size;
     89 	int len, offset = 3;
     90 
     91 	size = (length < 8) ? 9 : ((length + 1) / 2) + 5;
     92 
     93 	cmd[0] = command & 0xff;
     94 	cmd[1] = command >> 8;
     95 	cmd[2] = size & 0xff;
     96 	cmd[3] = size >> 8;
     97 	cmd[4] = seqnum & 0xff;
     98 	cmd[5] = seqnum >> 8;
     99 	cmd[6] = varid & 0xff;
    100 	cmd[7] = varid >> 8;
    101 	cmd[8] = 0x00;
    102 	cmd[9] = 0x00;
    103 
    104 	memset(cp, 0, sizeof(cp));
    105 	cp[0] = 0x01;
    106 	cp[1] = 0x00;
    107 	cp[2] = 0xfc;
    108 	cp[3] = (size * 2) + 1;
    109 	cp[4] = 0xc2;
    110 	memcpy(cp + 5, cmd, sizeof(cmd));
    111 	memcpy(cp + 15, value, length);
    112 
    113 	if (write(fd, cp, (size * 2) + 5) < 0)
    114 		return -1;
    115 
    116 	switch (varid) {
    117 	case CSR_VARID_COLD_RESET:
    118 	case CSR_VARID_WARM_RESET:
    119 	case CSR_VARID_COLD_HALT:
    120 	case CSR_VARID_WARM_HALT:
    121 		return 0;
    122 	}
    123 
    124 	do {
    125 		if (read(fd, rp, 1) < 1)
    126 			return -1;
    127 	} while (rp[0] != 0x04);
    128 
    129 	if (read(fd, rp + 1, 2) < 2)
    130 		return -1;
    131 
    132 	do {
    133 		len = read(fd, rp + offset, sizeof(rp) - offset);
    134 		offset += len;
    135 	} while (offset < rp[2] + 3);
    136 
    137 	if (rp[0] != 0x04 || rp[1] != 0xff || rp[3] != 0xc2) {
    138 		errno = EIO;
    139 		return -1;
    140 	}
    141 
    142 	if ((rp[12] + (rp[13] << 8)) != 0) {
    143 		errno = ENXIO;
    144 		return -1;
    145 	}
    146 
    147 	memcpy(value, rp + 14, length);
    148 
    149 	return 0;
    150 }
    151 
    152 int csr_read_h4(uint16_t varid, uint8_t *value, uint16_t length)
    153 {
    154 	return do_command(0x0000, seqnum++, varid, value, length);
    155 }
    156 
    157 int csr_write_h4(uint16_t varid, uint8_t *value, uint16_t length)
    158 {
    159 	return do_command(0x0002, seqnum++, varid, value, length);
    160 }
    161 
    162 void csr_close_h4(void)
    163 {
    164 	close(fd);
    165 }
    166