1016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann/* 2016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * 3016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * BlueZ - Bluetooth protocol stack for Linux 4016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * 59184e2eeb7b97371c6b83b747c8984e2340d2b47Marcel Holtmann * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org> 6016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * 7016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * 8016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * This program is free software; you can redistribute it and/or modify 9016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * it under the terms of the GNU General Public License as published by 10016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * the Free Software Foundation; either version 2 of the License, or 11016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * (at your option) any later version. 12016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * 13016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * This program is distributed in the hope that it will be useful, 14016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 15016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * GNU General Public License for more details. 17016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * 18016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * You should have received a copy of the GNU General Public License 19016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * along with this program; if not, write to the Free Software 20016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann * 22016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann */ 23016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 24016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann#ifdef HAVE_CONFIG_H 25016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann#include <config.h> 26016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann#endif 27016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 28016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann#include <stdio.h> 29016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann#include <errno.h> 30a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann#include <fcntl.h> 31a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann#include <unistd.h> 32a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann#include <string.h> 33016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann#include <stdint.h> 34a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann#include <termios.h> 35a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 36a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann#include "csr.h" 37016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 38016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmannstatic uint16_t seqnum = 0x0000; 39016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 40a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmannstatic int fd = -1; 41a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 42016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmannint csr_open_h4(char *device) 43016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann{ 44a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann struct termios ti; 45a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 46a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann if (!device) 47a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann device = "/dev/ttyS0"; 48a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 49a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann fd = open(device, O_RDWR | O_NOCTTY); 50a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann if (fd < 0) { 51a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann fprintf(stderr, "Can't open serial port: %s (%d)\n", 52a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann strerror(errno), errno); 53a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return -1; 54a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann } 55a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 56a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann tcflush(fd, TCIOFLUSH); 57a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 58a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann if (tcgetattr(fd, &ti) < 0) { 59a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann fprintf(stderr, "Can't get port settings: %s (%d)\n", 60a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann strerror(errno), errno); 61a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann close(fd); 62a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return -1; 63a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann } 64a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 65a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cfmakeraw(&ti); 66a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 67a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann ti.c_cflag |= CLOCAL; 68a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann ti.c_cflag |= CRTSCTS; 69a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 70a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cfsetospeed(&ti, B38400); 71a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 72a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann if (tcsetattr(fd, TCSANOW, &ti) < 0) { 73a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann fprintf(stderr, "Can't change port settings: %s (%d)\n", 74a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann strerror(errno), errno); 75a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann close(fd); 76a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return -1; 77a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann } 78a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 79a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann tcflush(fd, TCIOFLUSH); 80016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 81a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return 0; 82016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann} 83016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 84016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmannstatic int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length) 85016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann{ 86a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann unsigned char cp[254], rp[254]; 87a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann uint8_t cmd[10]; 88a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann uint16_t size; 89a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann int len, offset = 3; 90a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 91a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann size = (length < 8) ? 9 : ((length + 1) / 2) + 5; 92a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 93a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[0] = command & 0xff; 94a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[1] = command >> 8; 95a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[2] = size & 0xff; 96a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[3] = size >> 8; 97a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[4] = seqnum & 0xff; 98a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[5] = seqnum >> 8; 99a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[6] = varid & 0xff; 100a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[7] = varid >> 8; 101a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[8] = 0x00; 102a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cmd[9] = 0x00; 103a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 104a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann memset(cp, 0, sizeof(cp)); 105a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cp[0] = 0x01; 106a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cp[1] = 0x00; 107a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cp[2] = 0xfc; 108a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cp[3] = (size * 2) + 1; 109a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann cp[4] = 0xc2; 110a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann memcpy(cp + 5, cmd, sizeof(cmd)); 111a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann memcpy(cp + 15, value, length); 112a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 113a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann if (write(fd, cp, (size * 2) + 5) < 0) 114a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return -1; 115a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 116a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann switch (varid) { 117a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann case CSR_VARID_COLD_RESET: 118a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann case CSR_VARID_WARM_RESET: 119a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann case CSR_VARID_COLD_HALT: 120a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann case CSR_VARID_WARM_HALT: 121a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return 0; 122a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann } 123a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 124a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann do { 125a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann if (read(fd, rp, 1) < 1) 126a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return -1; 127a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann } while (rp[0] != 0x04); 128a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 129a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann if (read(fd, rp + 1, 2) < 2) 130a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return -1; 131a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 132a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann do { 133a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann len = read(fd, rp + offset, sizeof(rp) - offset); 134a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann offset += len; 135a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann } while (offset < rp[2] + 3); 136a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 137a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann if (rp[0] != 0x04 || rp[1] != 0xff || rp[3] != 0xc2) { 138a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann errno = EIO; 139a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return -1; 140a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann } 141a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 142a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann if ((rp[12] + (rp[13] << 8)) != 0) { 143a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann errno = ENXIO; 144a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return -1; 145a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann } 146a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann 147a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann memcpy(value, rp + 14, length); 148016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 149a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann return 0; 150016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann} 151016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 152016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmannint csr_read_h4(uint16_t varid, uint8_t *value, uint16_t length) 153016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann{ 154016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann return do_command(0x0000, seqnum++, varid, value, length); 155016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann} 156016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 157016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmannint csr_write_h4(uint16_t varid, uint8_t *value, uint16_t length) 158016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann{ 159016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann return do_command(0x0002, seqnum++, varid, value, length); 160016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann} 161016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann 162016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmannvoid csr_close_h4(void) 163016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann{ 164a61c4d6cd0882acb8d76f9a59f7847d7027ff539Marcel Holtmann close(fd); 165016c7033f4b73e35ebd66ada66093f3c5fe9fbffMarcel Holtmann} 166