| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #define _GNU_SOURCE |
| #include <stdio.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <signal.h> |
| #include <syslog.h> |
| #include <termios.h> |
| #include <time.h> |
| #include <sys/time.h> |
| #include <sys/poll.h> |
| #include <sys/param.h> |
| #include <sys/ioctl.h> |
| #include <sys/socket.h> |
| #include <sys/uio.h> |
| |
| #include "hciattach.h" |
| |
| #ifdef NEED_PPOLL |
| #include "ppoll.h" |
| #endif |
| |
| struct uart_t { |
| <------>char *type; |
| <------>int m_id; |
| <------>int p_id; |
| <------>int proto; |
| <------>int init_speed; |
| <------>int speed; |
| <------>int flags; |
| <------>int pm; |
| <------>char *bdaddr; |
| <------>int (*init) (int fd, struct uart_t *u, struct termios *ti); |
| <------>int (*post) (int fd, struct uart_t *u, struct termios *ti); |
| }; |
| |
| #define FLOW_CTL 0x0001 |
| #define ENABLE_PM 1 |
| #define DISABLE_PM 0 |
| |
| static volatile sig_atomic_t __io_canceled = 0; |
| |
| static void sig_hup(int sig) |
| { |
| <------>printf("sig hup.\n"); |
| } |
| |
| static void sig_term(int sig) |
| { |
| <------>switch (sig) { |
| <------>case SIGINT: |
| <------><------>printf("sig int.\n"); |
| <------><------>break; |
| <------>case SIGTERM: |
| <------><------>printf("sig term.\n"); |
| <------><------>break; |
| <------>} |
| <------>__io_canceled = 1; |
| } |
| |
| static void sig_alarm(int sig) |
| { |
| <------>fprintf(stderr, "Initialization timed out.\n"); |
| <------>exit(1); |
| } |
| |
| static int uart_speed(int s) |
| { |
| <------>switch (s) { |
| <------>case 9600: |
| <------><------>return B9600; |
| <------>case 19200: |
| <------><------>return B19200; |
| <------>case 38400: |
| <------><------>return B38400; |
| <------>case 57600: |
| <------><------>return B57600; |
| <------>case 115200: |
| <------><------>return B115200; |
| <------>case 230400: |
| <------><------>return B230400; |
| <------>case 460800: |
| <------><------>return B460800; |
| <------>case 500000: |
| <------><------>return B500000; |
| <------>case 576000: |
| <------><------>return B576000; |
| <------>case 921600: |
| <------><------>return B921600; |
| <------>case 1000000: |
| <------><------>return B1000000; |
| <------>case 1152000: |
| <------><------>return B1152000; |
| <------>case 1500000: |
| <------><------>return B1500000; |
| <------>case 2000000: |
| <------><------>return B2000000; |
| #ifdef B2500000 |
| <------>case 2500000: |
| <------><------>return B2500000; |
| #endif |
| #ifdef B3000000 |
| <------>case 3000000: |
| <------><------>return B3000000; |
| #endif |
| #ifdef B3500000 |
| <------>case 3500000: |
| <------><------>return B3500000; |
| #endif |
| #ifdef B4000000 |
| <------>case 4000000: |
| <------><------>return B4000000; |
| #endif |
| <------>default: |
| <------><------>return B57600; |
| <------>} |
| } |
| |
| int set_speed(int fd, struct termios *ti, int speed) |
| { |
| <------>if (cfsetospeed(ti, uart_speed(speed)) < 0) |
| <------><------>return -errno; |
| |
| <------>if (cfsetispeed(ti, uart_speed(speed)) < 0) |
| <------><------>return -errno; |
| |
| <------>if (tcsetattr(fd, TCSANOW, ti) < 0) |
| <------><------>return -errno; |
| |
| <------>return 0; |
| } |
| |
| |
| |
| |
| int read_hci_event(int fd, unsigned char* buf, int size) |
| { |
| <------>int remain, r; |
| <------>int count = 0; |
| |
| <------>if (size <= 0) |
| <------><------>return -1; |
| |
| <------> |
| <------> * should be 0x04, so we read until we get to the 0x04. */ |
| <------>while (1) { |
| <------><------>r = read(fd, buf, 1); |
| <------><------>if (r <= 0) |
| <------><------><------>return -1; |
| <------><------>if (buf[0] == 0x04) |
| <------><------><------>break; |
| <------>} |
| <------>count++; |
| |
| <------> |
| <------>while (count < 3) { |
| <------><------>r = read(fd, buf + count, 3 - count); |
| <------><------>if (r <= 0) |
| <------><------><------>return -1; |
| <------><------>count += r; |
| <------>} |
| |
| <------> |
| <------>if (buf[2] < (size - 3)) |
| <------><------>remain = buf[2]; |
| <------>else |
| <------><------>remain = size - 3; |
| |
| <------>while ((count - 3) < remain) { |
| <------><------>r = read(fd, buf + count, remain - (count - 3)); |
| <------><------>if (r <= 0) |
| <------><------><------>return -1; |
| <------><------>count += r; |
| <------>} |
| |
| <------>return count; |
| } |
| |
| #if 0 |
| |
| |
| |
| static int ericsson(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>struct timespec tm = {0, 50000}; |
| <------>char cmd[5]; |
| |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x09; |
| <------>cmd[2] = 0xfc; |
| <------>cmd[3] = 0x01; |
| |
| <------>switch (u->speed) { |
| <------>case 57600: |
| <------><------>cmd[4] = 0x03; |
| <------><------>break; |
| <------>case 115200: |
| <------><------>cmd[4] = 0x02; |
| <------><------>break; |
| <------>case 230400: |
| <------><------>cmd[4] = 0x01; |
| <------><------>break; |
| <------>case 460800: |
| <------><------>cmd[4] = 0x00; |
| <------><------>break; |
| <------>case 921600: |
| <------><------>cmd[4] = 0x20; |
| <------><------>break; |
| <------>case 2000000: |
| <------><------>cmd[4] = 0x25; |
| <------><------>break; |
| <------>case 3000000: |
| <------><------>cmd[4] = 0x27; |
| <------><------>break; |
| <------>case 4000000: |
| <------><------>cmd[4] = 0x2B; |
| <------><------>break; |
| <------>default: |
| <------><------>cmd[4] = 0x03; |
| <------><------>u->speed = 57600; |
| <------><------>fprintf(stderr, "Invalid speed requested, using %d bps instead\n", u->speed); |
| <------><------>break; |
| <------>} |
| |
| <------> |
| <------>if (write(fd, cmd, 5) != 5) { |
| <------><------>perror("Failed to write init command"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>nanosleep(&tm, NULL); |
| <------>return 0; |
| } |
| |
| |
| |
| |
| static int digi(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>struct timespec tm = {0, 50000}; |
| <------>char cmd[5]; |
| |
| <------> |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x07; |
| <------>cmd[2] = 0xfc; |
| <------>cmd[3] = 0x01; |
| |
| <------>switch (u->speed) { |
| <------>case 57600: |
| <------><------>cmd[4] = 0x08; |
| <------><------>break; |
| <------>case 115200: |
| <------><------>cmd[4] = 0x09; |
| <------><------>break; |
| <------>default: |
| <------><------>cmd[4] = 0x09; |
| <------><------>u->speed = 115200; |
| <------><------>break; |
| <------>} |
| |
| <------> |
| <------>if (write(fd, cmd, 5) != 5) { |
| <------><------>perror("Failed to write init command"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>nanosleep(&tm, NULL); |
| <------>return 0; |
| } |
| |
| static int texas(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>return texas_init(fd, ti); |
| } |
| |
| static int texas2(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>return texas_post(fd, ti); |
| } |
| |
| static int texasalt(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>return texasalt_init(fd, u->speed, ti); |
| } |
| #endif |
| |
| |
| |
| static int read_check(int fd, void *buf, int count) |
| { |
| <------>int res; |
| |
| <------>do { |
| <------><------>res = read(fd, buf, count); |
| <------><------>if (res != -1) { |
| <------><------><------>buf += res; |
| <------><------><------>count -= res; |
| <------><------>} |
| <------>} while (count && (errno == 0 || errno == EINTR)); |
| |
| <------>if (count) |
| <------><------>return -1; |
| |
| <------>return 0; |
| } |
| |
| |
| |
| |
| static int serial_fd; |
| static int bcsp_max_retries = 10; |
| |
| static void bcsp_tshy_sig_alarm(int sig) |
| { |
| <------>unsigned char bcsp_sync_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xda,0xdc,0xed,0xed,0xc0}; |
| <------>static int retries = 0; |
| |
| <------>if (retries < bcsp_max_retries) { |
| <------><------>retries++; |
| <------><------>if (write(serial_fd, &bcsp_sync_pkt, 10) < 0) |
| <------><------><------>return; |
| <------><------>alarm(1); |
| <------><------>return; |
| <------>} |
| |
| <------>tcflush(serial_fd, TCIOFLUSH); |
| <------>fprintf(stderr, "BCSP initialization timed out\n"); |
| <------>exit(1); |
| } |
| |
| static void bcsp_tconf_sig_alarm(int sig) |
| { |
| <------>unsigned char bcsp_conf_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xad,0xef,0xac,0xed,0xc0}; |
| <------>static int retries = 0; |
| |
| <------>if (retries < bcsp_max_retries){ |
| <------><------>retries++; |
| <------><------>if (write(serial_fd, &bcsp_conf_pkt, 10) < 0) |
| <------><------><------>return; |
| <------><------>alarm(1); |
| <------><------>return; |
| <------>} |
| |
| <------>tcflush(serial_fd, TCIOFLUSH); |
| <------>fprintf(stderr, "BCSP initialization timed out\n"); |
| <------>exit(1); |
| } |
| |
| static int bcsp(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>unsigned char byte, bcsph[4], bcspp[4], |
| <------><------>bcsp_sync_resp_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xac,0xaf,0xef,0xee,0xc0}, |
| <------><------>bcsp_conf_resp_pkt[10] = {0xc0,0x00,0x41,0x00,0xbe,0xde,0xad,0xd0,0xd0,0xc0}, |
| <------><------>bcspsync[4] = {0xda, 0xdc, 0xed, 0xed}, |
| <------><------>bcspsyncresp[4] = {0xac,0xaf,0xef,0xee}, |
| <------><------>bcspconf[4] = {0xad,0xef,0xac,0xed}, |
| <------><------>bcspconfresp[4] = {0xde,0xad,0xd0,0xd0}; |
| <------>struct sigaction sa; |
| <------>int len; |
| |
| <------>if (set_speed(fd, ti, u->speed) < 0) { |
| <------><------>perror("Can't set default baud rate"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>ti->c_cflag |= PARENB; |
| <------>ti->c_cflag &= ~(PARODD); |
| |
| <------>if (tcsetattr(fd, TCSANOW, ti) < 0) { |
| <------><------>perror("Can't set port settings"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>alarm(0); |
| |
| <------>serial_fd = fd; |
| <------>memset(&sa, 0, sizeof(sa)); |
| <------>sa.sa_flags = SA_NOCLDSTOP; |
| <------>sa.sa_handler = bcsp_tshy_sig_alarm; |
| <------>sigaction(SIGALRM, &sa, NULL); |
| |
| <------> |
| |
| <------>bcsp_tshy_sig_alarm(0); |
| <------>while (1) { |
| <------><------>do { |
| <------><------><------>if (read_check(fd, &byte, 1) == -1){ |
| <------><------><------><------>perror("Failed to read"); |
| <------><------><------><------>return -1; |
| <------><------><------>} |
| <------><------>} while (byte != 0xC0); |
| |
| <------><------>do { |
| <------><------><------>if ( read_check(fd, &bcsph[0], 1) == -1){ |
| <------><------><------><------>perror("Failed to read"); |
| <------><------><------><------>return -1; |
| <------><------><------>} |
| <------><------>} while (bcsph[0] == 0xC0); |
| |
| <------><------>if ( read_check(fd, &bcsph[1], 3) == -1){ |
| <------><------><------>perror("Failed to read"); |
| <------><------><------>return -1; |
| <------><------>} |
| |
| <------><------>if (((bcsph[0] + bcsph[1] + bcsph[2]) & 0xFF) != (unsigned char)~bcsph[3]) |
| <------><------><------>continue; |
| <------><------>if (bcsph[1] != 0x41 || bcsph[2] != 0x00) |
| <------><------><------>continue; |
| |
| <------><------>if (read_check(fd, &bcspp, 4) == -1){ |
| <------><------><------>perror("Failed to read"); |
| <------><------><------>return -1; |
| <------><------>} |
| |
| <------><------>if (!memcmp(bcspp, bcspsync, 4)) { |
| <------><------><------>if (write(fd, &bcsp_sync_resp_pkt,10) < 0) |
| <------><------><------><------>return -1; |
| <------><------>} else if (!memcmp(bcspp, bcspsyncresp, 4)) |
| <------><------><------>break; |
| <------>} |
| |
| <------> |
| |
| <------>alarm(0); |
| <------>sa.sa_handler = bcsp_tconf_sig_alarm; |
| <------>sigaction(SIGALRM, &sa, NULL); |
| <------>alarm(1); |
| |
| <------>while (1) { |
| <------><------>do { |
| <------><------><------>if (read_check(fd, &byte, 1) == -1){ |
| <------><------><------><------>perror("Failed to read"); |
| <------><------><------><------>return -1; |
| <------><------><------>} |
| <------><------>} while (byte != 0xC0); |
| |
| <------><------>do { |
| <------><------><------>if (read_check(fd, &bcsph[0], 1) == -1){ |
| <------><------><------><------>perror("Failed to read"); |
| <------><------><------><------>return -1; |
| <------><------><------>} |
| <------><------>} while (bcsph[0] == 0xC0); |
| |
| <------><------>if (read_check(fd, &bcsph[1], 3) == -1){ |
| <------><------><------>perror("Failed to read"); |
| <------><------><------>return -1; |
| <------><------>} |
| |
| <------><------>if (((bcsph[0] + bcsph[1] + bcsph[2]) & 0xFF) != (unsigned char)~bcsph[3]) |
| <------><------><------>continue; |
| |
| <------><------>if (bcsph[1] != 0x41 || bcsph[2] != 0x00) |
| <------><------><------>continue; |
| |
| <------><------>if (read_check(fd, &bcspp, 4) == -1){ |
| <------><------><------>perror("Failed to read"); |
| <------><------><------>return -1; |
| <------><------>} |
| |
| <------><------>if (!memcmp(bcspp, bcspsync, 4)) |
| <------><------><------>len = write(fd, &bcsp_sync_resp_pkt, 10); |
| <------><------>else if (!memcmp(bcspp, bcspconf, 4)) |
| <------><------><------>len = write(fd, &bcsp_conf_resp_pkt, 10); |
| <------><------>else if (!memcmp(bcspp, bcspconfresp, 4)) |
| <------><------><------>break; |
| <------><------>else |
| <------><------><------>continue; |
| |
| <------><------>if (len < 0) |
| <------><------><------>return -errno; |
| <------>} |
| |
| <------> |
| |
| <------>return 0; |
| } |
| |
| #if 0 |
| |
| |
| |
| |
| |
| |
| static int csr(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>struct timespec tm = {0, 10000000}; |
| <------>unsigned char cmd[30]; |
| <------>unsigned char resp[30]; |
| <------>int clen = 0; |
| <------>static int csr_seq = 0; |
| <------>int divisor; |
| |
| <------> |
| <------> * won't work, the CSR UART gets into a state where we can't talk |
| <------> * to it anymore. |
| <------> * On the other hand, doing a read before setting the CSR speed |
| <------> * seems to be ok. |
| <------> * Therefore, the strategy is to read the build ID (useful for |
| <------> * debugging) and only then set the CSR UART speed. Doing like |
| <------> * this is more complex but at least it works ;-) |
| <------> * The CSR UART control may be slow to wake up or something because |
| <------> * every time I read its speed, its bogus... |
| <------> * Jean II */ |
| |
| <------> |
| <------>clen = 5 + (5 + 6) * 2; |
| <------> |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x00; |
| <------>cmd[2] = 0xfc; |
| <------>cmd[3] = 1 + (5 + 6) * 2; |
| <------> |
| <------>cmd[4] = 0xC2; |
| <------> |
| <------>cmd[5] = 0x00; |
| <------>cmd[6] = 0x00; |
| <------>cmd[7] = 5 + 4; |
| <------>cmd[8] = 0x00; |
| <------>cmd[9] = csr_seq & 0xFF; |
| <------>cmd[10] = (csr_seq >> 8) & 0xFF; |
| <------>csr_seq++; |
| <------>cmd[11] = 0x19; |
| <------>cmd[12] = 0x28; |
| <------>cmd[13] = 0x00; |
| <------>cmd[14] = 0x00; |
| <------> |
| <------>memset(cmd + 15, 0, 6 * 2); |
| |
| <------> |
| <------>do { |
| <------><------>if (write(fd, cmd, clen) != clen) { |
| <------><------><------>perror("Failed to write init command (GET_BUILD_ID)"); |
| <------><------><------>return -1; |
| <------><------>} |
| |
| <------><------> |
| <------><------>if (read_hci_event(fd, resp, 100) < 0) { |
| <------><------><------>perror("Failed to read init response (GET_BUILD_ID)"); |
| <------><------><------>return -1; |
| <------><------>} |
| |
| <------> |
| <------> * what we're looking for. */ |
| <------>} while (resp[1] != 0xFF); |
| |
| #ifdef CSR_DEBUG |
| <------>{ |
| <------>char temp[512]; |
| <------>int i; |
| <------>for (i=0; i < rlen; i++) |
| <------><------>sprintf(temp + (i*3), "-%02X", resp[i]); |
| <------>fprintf(stderr, "Reading CSR build ID %d [%s]\n", rlen, temp + 1); |
| <------> |
| <------> |
| <------>} |
| #endif |
| <------> |
| <------>fprintf(stderr, "CSR build ID 0x%02X-0x%02X\n", |
| <------><------>resp[15] & 0xFF, resp[14] & 0xFF); |
| |
| <------> |
| <------>clen = 5 + (5 + 4)*2; |
| <------> |
| <------>cmd[3] = 1 + (5 + 4)*2; |
| <------> |
| <------>cmd[9] = csr_seq & 0xFF; |
| <------>cmd[10] = (csr_seq >> 8) & 0xFF; |
| <------>csr_seq++; |
| <------>cmd[11] = 0x02; |
| <------>cmd[12] = 0x68; |
| |
| #ifdef CSR_DEBUG |
| <------> |
| <------>do { |
| <------><------>if (write(fd, cmd, clen) != clen) { |
| <------><------><------>perror("Failed to write init command (GET_BUILD_ID)"); |
| <------><------><------>return -1; |
| <------><------>} |
| |
| <------><------> |
| <------><------>if (read_hci_event(fd, resp, 100) < 0) { |
| <------><------><------>perror("Failed to read init response (GET_BUILD_ID)"); |
| <------><------><------>return -1; |
| <------><------>} |
| |
| <------> |
| <------> * what we're looking for. */ |
| <------>} while (resp[1] != 0xFF); |
| |
| <------>{ |
| <------>char temp[512]; |
| <------>int i; |
| <------>for (i=0; i < rlen; i++) |
| <------><------>sprintf(temp + (i*3), "-%02X", resp[i]); |
| <------>fprintf(stderr, "Reading CSR UART speed %d [%s]\n", rlen, temp+1); |
| <------>} |
| #endif |
| |
| <------>if (u->speed > 1500000) { |
| <------><------>fprintf(stderr, "Speed %d too high. Remaining at %d baud\n", |
| <------><------><------>u->speed, u->init_speed); |
| <------><------>u->speed = u->init_speed; |
| <------>} else if (u->speed != 57600 && uart_speed(u->speed) == B57600) { |
| <------><------> |
| <------><------>fprintf(stderr, "Speed %d unrecognised. Remaining at %d baud\n", |
| <------><------><------>u->speed, u->init_speed); |
| <------><------>u->speed = u->init_speed; |
| <------>} |
| <------>if (u->speed == u->init_speed) |
| <------><------>return 0; |
| |
| <------> |
| <------> |
| <------>cmd[5] = 0x02; |
| <------>cmd[6] = 0x00; |
| <------>cmd[9] = csr_seq & 0xFF; |
| <------>cmd[10] = (csr_seq >> 8) & 0xFF; |
| <------>csr_seq++; |
| |
| <------>divisor = (u->speed*64+7812)/15625; |
| |
| <------> |
| <------>cmd[15] = (divisor) & 0xFF; |
| <------>cmd[16] = (divisor >> 8) & 0xFF; |
| <------> |
| |
| #ifdef CSR_DEBUG |
| <------>{ |
| <------>char temp[512]; |
| <------>int i; |
| <------>for(i = 0; i < clen; i++) |
| <------><------>sprintf(temp + (i*3), "-%02X", cmd[i]); |
| <------>fprintf(stderr, "Writing CSR UART speed %d [%s]\n", clen, temp + 1); |
| <------> |
| <------> |
| <------> |
| <------>} |
| #endif |
| |
| <------> |
| <------>if (write(fd, cmd, clen) != clen) { |
| <------><------>perror("Failed to write init command (SET_UART_SPEED)"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>nanosleep(&tm, NULL); |
| <------>return 0; |
| } |
| |
| |
| |
| |
| |
| static int swave(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>struct timespec tm = { 0, 500000 }; |
| <------>char cmd[10], rsp[100]; |
| <------>int r; |
| |
| <------> |
| <------> |
| <------> |
| <------> |
| <------> |
| |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x0B; |
| <------>cmd[2] = 0xfc; |
| <------>cmd[3] = 0x06; |
| <------>cmd[4] = 0x01; |
| <------>cmd[5] = 0x11; |
| <------>cmd[6] = 0x03; |
| <------>cmd[7] = 0x01; |
| <------>cmd[8] = 0x01; |
| |
| <------>switch (u->speed) { |
| <------>case 19200: |
| <------><------>cmd[9] = 0x03; |
| <------><------>break; |
| <------>case 38400: |
| <------><------>cmd[9] = 0x02; |
| <------><------>break; |
| <------>case 57600: |
| <------><------>cmd[9] = 0x01; |
| <------><------>break; |
| <------>case 115200: |
| <------><------>cmd[9] = 0x00; |
| <------><------>break; |
| <------>default: |
| <------><------>u->speed = 115200; |
| <------><------>cmd[9] = 0x00; |
| <------><------>break; |
| <------>} |
| |
| <------> |
| <------>if (write(fd, cmd, 10) != 10) { |
| <------><------>perror("Failed to write init command"); |
| <------><------>return -1; |
| <------>} |
| |
| <------> |
| <------> |
| <------> |
| <------> |
| |
| <------>nanosleep(&tm, NULL); |
| |
| <------>r = read(fd, rsp, sizeof(rsp)); |
| <------>if (r > 0) { |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------><------> |
| <------>} else { |
| <------><------> |
| <------><------>return -1; |
| <------>} |
| |
| <------> |
| <------> |
| |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x03; |
| <------>cmd[2] = 0x0c; |
| <------>cmd[3] = 0x00; |
| |
| <------> |
| <------>if (write(fd, cmd, 4) != 4) { |
| <------><------>perror("Can't write Silicon Wave reset cmd."); |
| <------><------>return -1; |
| <------>} |
| |
| <------>nanosleep(&tm, NULL); |
| |
| <------> |
| <------> |
| |
| <------> |
| <------> |
| <------> |
| <------> |
| |
| <------>return 0; |
| } |
| |
| |
| |
| |
| |
| static int st(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>struct timespec tm = {0, 50000}; |
| <------>char cmd[5]; |
| |
| <------> |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x46; |
| <------>cmd[2] = 0xfc; |
| <------>cmd[3] = 0x01; |
| |
| <------>switch (u->speed) { |
| <------>case 9600: |
| <------><------>cmd[4] = 0x09; |
| <------><------>break; |
| <------>case 19200: |
| <------><------>cmd[4] = 0x0b; |
| <------><------>break; |
| <------>case 38400: |
| <------><------>cmd[4] = 0x0d; |
| <------><------>break; |
| <------>case 57600: |
| <------><------>cmd[4] = 0x0e; |
| <------><------>break; |
| <------>case 115200: |
| <------><------>cmd[4] = 0x10; |
| <------><------>break; |
| <------>case 230400: |
| <------><------>cmd[4] = 0x12; |
| <------><------>break; |
| <------>case 460800: |
| <------><------>cmd[4] = 0x13; |
| <------><------>break; |
| <------>case 921600: |
| <------><------>cmd[4] = 0x14; |
| <------><------>break; |
| <------>default: |
| <------><------>cmd[4] = 0x10; |
| <------><------>u->speed = 115200; |
| <------><------>break; |
| <------>} |
| |
| <------> |
| <------>if (write(fd, cmd, 5) != 5) { |
| <------><------>perror("Failed to write init command"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>nanosleep(&tm, NULL); |
| <------>return 0; |
| } |
| |
| static int stlc2500(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>bdaddr_t bdaddr; |
| <------>unsigned char resp[10]; |
| <------>int n; |
| <------>int rvalue; |
| |
| <------> |
| <------>rvalue = ericsson(fd, u, ti); |
| <------>if (rvalue != 0) |
| <------><------>return rvalue; |
| |
| #ifdef STLC2500_DEBUG |
| <------>fprintf(stderr, "Setting speed\n"); |
| #endif |
| <------>if (set_speed(fd, ti, u->speed) < 0) { |
| <------><------>perror("Can't set baud rate"); |
| <------><------>return -1; |
| <------>} |
| |
| #ifdef STLC2500_DEBUG |
| <------>fprintf(stderr, "Speed set...\n"); |
| #endif |
| |
| <------> |
| <------>if ((n = read_hci_event(fd, resp, 10)) < 0) { |
| <------><------>fprintf(stderr, "Failed to set baud rate on chip\n"); |
| <------><------>return -1; |
| <------>} |
| |
| #ifdef STLC2500_DEBUG |
| <------>for (i = 0; i < n; i++) { |
| <------><------>fprintf(stderr, "resp[%d] = %02x\n", i, resp[i]); |
| <------>} |
| #endif |
| |
| <------>str2ba(u->bdaddr, &bdaddr); |
| <------>return stlc2500_init(fd, &bdaddr); |
| } |
| |
| static int bgb2xx(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>bdaddr_t bdaddr; |
| |
| <------>str2ba(u->bdaddr, &bdaddr); |
| |
| <------>return bgb2xx_init(fd, &bdaddr); |
| } |
| |
| |
| |
| |
| |
| static int bcm2035(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>int n; |
| <------>unsigned char cmd[30], resp[30]; |
| |
| <------> |
| <------>memset(cmd, 0, sizeof(cmd)); |
| <------>memset(resp, 0, sizeof(resp)); |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x03; |
| <------>cmd[2] = 0x0c; |
| <------>cmd[3] = 0x00; |
| |
| <------> |
| <------>if (write(fd, cmd, 4) != 4) { |
| <------><------>fprintf(stderr, "Failed to write reset command\n"); |
| <------><------>return -1; |
| <------>} |
| |
| <------> |
| <------>if ((n = read_hci_event(fd, resp, 4)) < 0) { |
| <------><------>fprintf(stderr, "Failed to reset chip\n"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>if (u->bdaddr != NULL) { |
| <------><------> |
| <------><------>memset(cmd, 0, sizeof(cmd)); |
| <------><------>memset(resp, 0, sizeof(resp)); |
| <------><------>cmd[0] = HCI_COMMAND_PKT; |
| <------><------>cmd[1] = 0x01; |
| <------><------>cmd[2] = 0xfc; |
| <------><------>cmd[3] = 0x06; |
| <------><------>str2ba(u->bdaddr, (bdaddr_t *) (cmd + 4)); |
| |
| <------><------> |
| <------><------>if (write(fd, cmd, 10) != 10) { |
| <------><------><------>fprintf(stderr, "Failed to write BD_ADDR command\n"); |
| <------><------><------>return -1; |
| <------><------>} |
| |
| <------><------> |
| <------><------>if ((n = read_hci_event(fd, resp, 10)) < 0) { |
| <------><------><------>fprintf(stderr, "Failed to set BD_ADDR\n"); |
| <------><------><------>return -1; |
| <------><------>} |
| <------>} |
| |
| <------> |
| <------>memset(cmd, 0, sizeof(cmd)); |
| <------>memset(resp, 0, sizeof(resp)); |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x01; |
| <------>cmd[2] = 0x10; |
| <------>cmd[3] = 0x00; |
| |
| <------> |
| <------>if (write(fd, cmd, 4) != 4) { |
| <------><------>fprintf(stderr, "Failed to write \"read local version\" " |
| <------><------><------>"command\n"); |
| <------><------>return -1; |
| <------>} |
| |
| <------> |
| <------>if ((n = read_hci_event(fd, resp, 4)) < 0) { |
| <------><------>fprintf(stderr, "Failed to read local version\n"); |
| <------><------>return -1; |
| <------>} |
| |
| <------> |
| <------>memset(cmd, 0, sizeof(cmd)); |
| <------>memset(resp, 0, sizeof(resp)); |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x02; |
| <------>cmd[2] = 0x10; |
| <------>cmd[3] = 0x00; |
| |
| <------> |
| <------>if (write(fd, cmd, 4) != 4) { |
| <------><------>fprintf(stderr, "Failed to write \"read local supported " |
| <------><------><------><------><------><------>"commands\" command\n"); |
| <------><------>return -1; |
| <------>} |
| |
| <------> |
| <------>if ((n = read_hci_event(fd, resp, 4)) < 0) { |
| <------><------>fprintf(stderr, "Failed to read local supported commands\n"); |
| <------><------>return -1; |
| <------>} |
| |
| <------> |
| <------>memset(cmd, 0, sizeof(cmd)); |
| <------>memset(resp, 0, sizeof(resp)); |
| <------>cmd[0] = HCI_COMMAND_PKT; |
| <------>cmd[1] = 0x18; |
| <------>cmd[2] = 0xfc; |
| <------>cmd[3] = 0x02; |
| <------>switch (u->speed) { |
| <------>case 57600: |
| <------><------>cmd[4] = 0x00; |
| <------><------>cmd[5] = 0xe6; |
| <------><------>break; |
| <------>case 230400: |
| <------><------>cmd[4] = 0x22; |
| <------><------>cmd[5] = 0xfa; |
| <------><------>break; |
| <------>case 460800: |
| <------><------>cmd[4] = 0x22; |
| <------><------>cmd[5] = 0xfd; |
| <------><------>break; |
| <------>case 921600: |
| <------><------>cmd[4] = 0x55; |
| <------><------>cmd[5] = 0xff; |
| <------><------>break; |
| <------>default: |
| <------><------> |
| <------><------>cmd[4] = 0x00; |
| <------><------>cmd[5] = 0xf3; |
| <------><------>break; |
| <------>} |
| <------>fprintf(stderr, "Baud rate parameters: DHBR=0x%2x,DLBR=0x%2x\n", |
| <------><------>cmd[4], cmd[5]); |
| |
| <------> |
| <------>if (write(fd, cmd, 6) != 6) { |
| <------><------>fprintf(stderr, "Failed to write \"set baud rate\" command\n"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>if ((n = read_hci_event(fd, resp, 6)) < 0) { |
| <------><------>fprintf(stderr, "Failed to set baud rate\n"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>return 0; |
| } |
| #endif |
| |
| static int realtek_init(int fd, struct uart_t *u, struct termios *ti) |
| { |
| |
| <------>fprintf(stderr, "Realtek Bluetooth init uart with init speed:%d, final_speed:%d, type:HCI UART %s\n", u->init_speed, u->speed, (u->proto == HCI_UART_H4)? "H4":"H5" ); |
| <------>return rtk_init(fd, u->proto, u->speed, ti); |
| } |
| |
| static int realtek_post(int fd, struct uart_t *u, struct termios *ti) |
| { |
| <------>fprintf(stderr, "Realtek Bluetooth post process\n"); |
| <------>return rtk_post(fd, u->proto, ti); |
| } |
| |
| struct uart_t uart[] = { |
| <------>{ "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, DISABLE_PM, NULL, NULL }, |
| <------>{ "bcsp", 0x0000, 0x0000, HCI_UART_BCSP, 115200, 115200, 0, DISABLE_PM, NULL, bcsp }, |
| |
| #if 0 |
| <------>{ "ericsson", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, ericsson }, |
| <------>{ "digi", 0x0000, 0x0000, HCI_UART_H4, 9600, 115200, FLOW_CTL, NULL, digi }, |
| |
| |
| <------> |
| <------>{ "xircom", 0x0105, 0x080a, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL }, |
| |
| <------> |
| <------>{ "csr", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr }, |
| |
| <------> |
| <------>{ "bboxes", 0x0160, 0x0002, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, csr }, |
| |
| <------> |
| <------>{ "swave", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, swave }, |
| |
| <------> |
| <------>{ "texas", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, FLOW_CTL, NULL, texas, texas2 }, |
| <------>{ "texasalt", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, FLOW_CTL, NULL, texasalt, NULL }, |
| |
| <------> |
| <------>{ "st", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, st }, |
| |
| <------> |
| <------>{ "stlc2500", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "00:80:E1:00:AB:BA", stlc2500 }, |
| |
| <------> |
| <------>{ "philips", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL }, |
| |
| <------> |
| <------>{ "bgb2xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "BD:B2:10:00:AB:BA", bgb2xx }, |
| |
| <------> |
| <------>{ "picocard", 0x025e, 0x1000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL }, |
| |
| <------> |
| <------>{ "inventel", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL }, |
| |
| <------> |
| <------>{ "comone", 0xffff, 0x0101, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp }, |
| |
| <------> |
| <------>{ "tdk", 0x0105, 0x4254, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp }, |
| |
| <------> |
| <------>{ "socket", 0x0104, 0x0096, HCI_UART_BCSP, 230400, 230400, 0, NULL, bcsp }, |
| |
| <------> |
| <------>{ "3com", 0x0101, 0x0041, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr }, |
| |
| <------> |
| <------>{ "bt2000c", 0x022d, 0x2000, HCI_UART_H4, 57600, 460800, FLOW_CTL, NULL, csr }, |
| |
| <------> |
| <------>{ "zoom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp }, |
| |
| <------> |
| <------>{ "sitecom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp }, |
| |
| <------> |
| <------>{ "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp }, |
| |
| <------> |
| <------>{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 }, |
| |
| #endif |
| |
| <------> |
| <------> |
| <------>{ "rtk_h4", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, 0, DISABLE_PM, NULL, realtek_init, realtek_post}, |
| |
| |
| <------> |
| <------>{ "rtk_h5", 0x0000, 0x0000, HCI_UART_3WIRE, 115200,115200, 0, DISABLE_PM, NULL, realtek_init, realtek_post}, |
| |
| <------>{ NULL, 0 } |
| }; |
| |
| static struct uart_t * get_by_id(int m_id, int p_id) |
| { |
| <------>int i; |
| <------>for (i = 0; uart[i].type; i++) { |
| <------><------>if (uart[i].m_id == m_id && uart[i].p_id == p_id) |
| <------><------><------>return &uart[i]; |
| <------>} |
| <------>return NULL; |
| } |
| |
| static struct uart_t * get_by_type(char *type) |
| { |
| <------>int i; |
| <------>for (i = 0; uart[i].type; i++) { |
| <------><------>if (!strcmp(uart[i].type, type)) |
| <------><------><------>return &uart[i]; |
| <------>} |
| <------>return NULL; |
| } |
| |
| |
| static int init_uart(char *dev, struct uart_t *u, int send_break, int raw) |
| { |
| <------>struct termios ti; |
| <------>int fd, i; |
| <------>unsigned long flags = 0; |
| |
| <------>if (raw) |
| <------><------>flags |= 1 << HCI_UART_RAW_DEVICE; |
| |
| <------>fd = open(dev, O_RDWR | O_NOCTTY); |
| <------>if (fd < 0) { |
| <------><------>perror("Can't open serial port"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>tcflush(fd, TCIOFLUSH); |
| |
| <------>if (tcgetattr(fd, &ti) < 0) { |
| <------><------>perror("Can't get port settings"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>cfmakeraw(&ti); |
| |
| <------>ti.c_cflag |= CLOCAL; |
| <------>if (u->flags & FLOW_CTL) |
| <------><------>ti.c_cflag |= CRTSCTS; |
| <------>else |
| <------><------>ti.c_cflag &= ~CRTSCTS; |
| |
| <------>if (tcsetattr(fd, TCSANOW, &ti) < 0) { |
| <------><------>perror("Can't set port settings"); |
| <------><------>return -1; |
| <------>} |
| |
| <------> |
| <------>if (set_speed(fd, &ti, u->init_speed) < 0) { |
| <------><------>perror("Can't set initial baud rate"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>tcflush(fd, TCIOFLUSH); |
| |
| <------>if (send_break) { |
| <------><------>tcsendbreak(fd, 0); |
| <------><------>usleep(500000); |
| <------>} |
| |
| <------>if (u->init && u->init(fd, u, &ti) < 0) |
| <------><------>return -1; |
| |
| <------>tcflush(fd, TCIOFLUSH); |
| |
| <------> |
| <------>if (set_speed(fd, &ti, u->speed) < 0) { |
| <------><------>perror("Can't set baud rate"); |
| <------><------>return -1; |
| <------>} |
| |
| <------> |
| <------>i = N_HCI; |
| <------>if (ioctl(fd, TIOCSETD, &i) < 0) { |
| <------><------>perror("Can't set line discipline"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) { |
| <------><------>perror("Can't set UART flags"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) { |
| <------><------>perror("Can't set device"); |
| <------><------>return -1; |
| <------>} |
| |
| <------>if (u->post && u->post(fd, u, &ti) < 0) |
| <------><------>return -1; |
| |
| <------>return fd; |
| } |
| |
| static void usage(void) |
| { |
| <------>printf("hciattach - HCI UART driver initialization utility\n"); |
| <------>printf("Usage:\n"); |
| <------>printf("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]\n"); |
| <------>printf("\thciattach -l\n"); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| <------>struct uart_t *u = NULL; |
| <------>int detach, printpid, raw, opt, i, n, ld, err; |
| <------>int to = 10; |
| <------>int init_speed = 0; |
| <------>int send_break = 0; |
| <------>pid_t pid; |
| <------>struct sigaction sa; |
| <------>struct pollfd p; |
| <------>sigset_t sigs; |
| <------>char dev[PATH_MAX]; |
| |
| <------>detach = 1; |
| <------>printpid = 0; |
| <------>raw = 0; |
| |
| <------>while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) { |
| <------><------>switch(opt) { |
| <------><------>case 'b': |
| <------><------><------>send_break = 1; |
| <------><------><------>break; |
| |
| <------><------>case 'n': |
| <------><------><------>detach = 0; |
| <------><------><------>break; |
| |
| <------><------>case 'p': |
| <------><------><------>printpid = 1; |
| <------><------><------>break; |
| |
| <------><------>case 't': |
| <------><------><------>to = atoi(optarg); |
| <------><------><------>break; |
| |
| <------><------>case 's': |
| <------><------><------>init_speed = atoi(optarg); |
| <------><------><------>break; |
| |
| <------><------>case 'l': |
| <------><------><------>for (i = 0; uart[i].type; i++) { |
| <------><------><------><------>printf("%-10s0x%04x,0x%04x\n", uart[i].type, |
| <------><------><------><------><------><------><------>uart[i].m_id, uart[i].p_id); |
| <------><------><------>} |
| <------><------><------>exit(0); |
| |
| <------><------>case 'r': |
| <------><------><------>raw = 1; |
| <------><------><------>break; |
| |
| <------><------>default: |
| <------><------><------>usage(); |
| <------><------><------>exit(1); |
| <------><------>} |
| <------>} |
| |
| <------>n = argc - optind; |
| <------>if (n < 2) { |
| <------><------>usage(); |
| <------><------>exit(1); |
| <------>} |
| |
| <------>for (n = 0; optind < argc; n++, optind++) { |
| <------><------>char *opt; |
| |
| <------><------>opt = argv[optind]; |
| |
| <------><------>switch(n) { |
| <------><------>case 0: |
| <------><------><------>dev[0] = 0; |
| <------><------><------>if (!strchr(opt, '/')) |
| <------><------><------><------>strcpy(dev, "/dev/"); |
| <------><------><------>strcat(dev, opt); |
| <------><------><------>break; |
| |
| <------><------>case 1: |
| <------><------><------>if (strchr(argv[optind], ',')) { |
| <------><------><------><------>int m_id, p_id; |
| <------><------><------><------>sscanf(argv[optind], "%x,%x", &m_id, &p_id); |
| <------><------><------><------>u = get_by_id(m_id, p_id); |
| <------><------><------>} else { |
| <------><------><------><------>u = get_by_type(opt); |
| <------><------><------>} |
| |
| <------><------><------>if (!u) { |
| <------><------><------><------>fprintf(stderr, "Unknown device type or id\n"); |
| <------><------><------><------>exit(1); |
| <------><------><------>} |
| <------><------><------> |
| <------><------><------>break; |
| |
| <------><------>case 2: |
| <------><------><------>u->speed = atoi(argv[optind]); |
| <------><------><------>break; |
| |
| <------><------>case 3: |
| <------><------><------>if (!strcmp("flow", argv[optind])) |
| <------><------><------><------>u->flags |= FLOW_CTL; |
| <------><------><------>else |
| <------><------><------><------>u->flags &= ~FLOW_CTL; |
| <------><------><------>break; |
| |
| <------><------>case 4: |
| <------><------><------>if (!strcmp("sleep", argv[optind])) |
| <------><------><------><------>u->pm = ENABLE_PM; |
| <------><------><------>else |
| <------><------><------><------>u->pm = DISABLE_PM; |
| <------><------><------>break; |
| |
| <------><------>case 5: |
| <------><------><------>u->bdaddr = argv[optind]; |
| <------><------><------>break; |
| <------><------>} |
| <------>} |
| |
| <------>if (!u) { |
| <------><------>fprintf(stderr, "Unknown device type or id\n"); |
| <------><------>exit(1); |
| <------>} |
| |
| <------> |
| <------> the hardware's default */ |
| <------>if (init_speed) |
| <------><------>u->init_speed = init_speed; |
| |
| <------>memset(&sa, 0, sizeof(sa)); |
| <------>sa.sa_flags = SA_NOCLDSTOP; |
| <------>sa.sa_handler = sig_alarm; |
| <------>sigaction(SIGALRM, &sa, NULL); |
| |
| <------> |
| <------>alarm(to); |
| <------>bcsp_max_retries = to; |
| |
| <------>n = init_uart(dev, u, send_break, raw); |
| <------>if (n < 0) { |
| <------><------>perror("Can't initialize device"); |
| <------><------>exit(1); |
| <------>} |
| |
| <------>printf("Device setup complete\n"); |
| |
| <------>alarm(0); |
| |
| <------>memset(&sa, 0, sizeof(sa)); |
| <------>sa.sa_flags = SA_NOCLDSTOP; |
| <------>sa.sa_handler = SIG_IGN; |
| <------>sigaction(SIGCHLD, &sa, NULL); |
| <------>sigaction(SIGPIPE, &sa, NULL); |
| |
| <------>sa.sa_handler = sig_term; |
| <------>sigaction(SIGTERM, &sa, NULL); |
| <------>sigaction(SIGINT, &sa, NULL); |
| |
| <------>sa.sa_handler = sig_hup; |
| <------>sigaction(SIGHUP, &sa, NULL); |
| |
| <------>if (detach) { |
| <------><------>if ((pid = fork())) { |
| <------><------><------>if (printpid) |
| <------><------><------><------>printf("%d\n", pid); |
| <------><------><------>return 0; |
| <------><------>} |
| |
| <------><------>for (i = 0; i < 20; i++) |
| <------><------><------>if (i != n) |
| <------><------><------><------>close(i); |
| <------>} |
| |
| <------>p.fd = n; |
| <------>p.events = POLLERR | POLLHUP; |
| |
| <------>sigfillset(&sigs); |
| <------>sigdelset(&sigs, SIGCHLD); |
| <------>sigdelset(&sigs, SIGPIPE); |
| <------>sigdelset(&sigs, SIGTERM); |
| <------>sigdelset(&sigs, SIGINT); |
| <------>sigdelset(&sigs, SIGHUP); |
| |
| <------>while (!__io_canceled) { |
| <------><------>p.revents = 0; |
| <------><------>err = ppoll(&p, 1, NULL, &sigs); |
| <------><------>if (err < 0 && errno == EINTR) { |
| <------><------><------>printf("Got EINTR.\n"); |
| <------><------><------>continue; |
| <------><------>} if (err) |
| <------><------><------>break; |
| <------>} |
| |
| <------> |
| <------>printf("Restore TTY line discipline\n"); |
| <------>ld = N_TTY; |
| <------>if (ioctl(n, TIOCSETD, &ld) < 0) { |
| <------><------>perror("Can't restore line discipline"); |
| <------><------>exit(1); |
| <------>} |
| |
| <------>return 0; |
| } |
| |