blob: b4f819a0ca231392f9601de6950daae3d6edb794 [file] [log] [blame]
Todd Brochd4b00c12011-02-08 16:57:33 -08001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <assert.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <ftdi.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <termios.h>
14#include <unistd.h>
15#include <usb.h>
16
17#include "ftdi_common.h"
18#include "ftdiuart.h"
19
20// TODO(tbroch) Where are these protos and under what conditions do they
21// exist across lin/mac/win
22int grantpt(int fd);
23int unlockpt(int fd);
24int ptsname_r(int fd, char *buf, size_t buflen);
25int posix_openpt(int flags);
26
27#ifdef DARWIN
28int ptsname_r(int fd, char *buf, size_t buflen) {
29 buf = ptsname(fd);
30 if (buf == NULL) {
31 return -1;
32 } else {
33 return 0;
34 }
35}
36#endif
37
38int fuart_init(struct fuart_context *fuartc, struct ftdi_context *fc) {
39 assert(fuartc);
40 memset(fuartc, 0, sizeof(*fuartc));
41
42 fuartc->fc = fc;
43 // init all inputs
44 fuartc->gpio.direction = 0;
45 fuartc->gpio.value = 0;
46 // TODO(tbroch) NO OOB signal support (CTS,RTS,DCR,DTR)
47 fuartc->gpio.mask = ~(TX_POS | RX_POS);
48
49 fuartc->error = FUART_ERR_NONE;
50 return FUART_ERR_NONE;
51}
52
53int fuart_open(struct fuart_context *fuartc,
54 struct ftdi_common_args *fargs) {
55 int rv;
56
57 struct ftdi_context *fc = fuartc->fc;
58
59 if (!IS_FTDI_OPEN(fc)) {
60 rv = ftdi_usb_open(fc, fargs->vendor_id, fargs->product_id);
61 if (rv < 0) {
62 ERROR_FTDI("Opening usb connection", fc);
63 return FUART_ERR_FTDI;
64 }
65 }
66 assert(fuartc->fc);
67 if (fcom_num_interfaces(fc) > 1) {
68 if ((rv = ftdi_set_interface(fc, fargs->interface))) {
69 ERROR_FTDI("setting interface", fc);
70 return FUART_ERR_FTDI;
71 }
72 }
73 CHECK_FTDI(ftdi_set_bitmode(fc, TX_POS, BITMODE_RESET),
74 "uart mode", fc);
75
76 // TODO(tbroch) Do some checking of reasonable cfg/buadrate
77 CHECK_FTDI(ftdi_set_line_property(fc, fargs->bits, fargs->sbits,
78 fargs->parity), "line props", fc);
79 CHECK_FTDI(ftdi_set_baudrate(fc, fargs->speed), "baudrate", fc);
80
81 if (fc->type == TYPE_R) {
82 int gpio_cfg = fargs->direction<<4 | fargs->value;
83 CHECK_FTDI(ftdi_set_bitmode(fc, gpio_cfg, BITMODE_CBUS),
84 "uart mode", fc);
85 }
86
87 int fd;
88 if ((fd = posix_openpt(O_RDWR | O_NOCTTY)) == -1) {
89 perror("opening pty master");
90 return FUART_ERR_OPEN;
91 }
92 if (grantpt(fd) == -1) {
93 perror("grantpt");
94 return FUART_ERR_OPEN;
95 }
96 if (unlockpt(fd) == -1) {
97 perror("unlockpt");
98 return FUART_ERR_OPEN;
99 }
100 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
101 perror("fcntl setfl -> nonblock");
102 return FUART_ERR_OPEN;
103 }
104 if (ptsname_r(fd, fuartc->name, PATH_MAX) != 0) {
105 perror("getting name of pty");
106 return FUART_ERR_OPEN;
107 }
108 if (!isatty(fd)) {
109 prn_error("Not a TTY device.\n");
110 return FUART_ERR_OPEN;
111 }
112 struct termios tty_cfg;
113 cfmakeraw(&tty_cfg);
114 tcsetattr(fd, TCSANOW, &tty_cfg);
115
116 fuartc->fd = fd;
117 return FUART_ERR_NONE;
118}
119
120int fuart_wr_rd(struct fuart_context *fuartc, int nsecs) {
121
122 int rv;
123 int bytes;
124 struct ftdi_context *fc = fuartc->fc;
125 if ((bytes = read(fuartc->fd, fuartc->buf, sizeof(fuartc->buf))) > 0) {
126#ifdef DEBUG
127 fuartc->buf[bytes] = '\0';
128 printf("about to write %d bytes to ftdi %s\n", bytes, fuartc->buf);
129#endif
130 rv = ftdi_write_data(fc, fuartc->buf, bytes);
131 /*
132 retry = 0;
133 while ((rv < 0) && (retry < 1000)) {
134 rv = ftdi_write_data(fc, fuartc->buf, bytes);
135 retry++;
136 }
137 */
138 if (rv != bytes) {
139 ERROR_FTDI("writing to uart", fc);
140 return FUART_ERR_WR;
141 }
142 }
143 usleep(nsecs);
144 // TODO(tbroch) is there a lower cost way to interrogate ftdi for data. How
145 // does the event/error_char factor into things?
146 bytes = ftdi_read_data(fc, fuartc->buf, sizeof(fuartc->buf));
147 if (bytes > 0) {
148 int bytes_remaining = bytes;
149 while ((bytes = write(fuartc->fd, fuartc->buf, bytes_remaining)) > 0) {
150 bytes_remaining -= bytes;
151 }
152 if (bytes == -1) {
153 perror("writing ftdi data to pty");
154 }
155
156 } else if (bytes < 0) {
157 perror("failed ftdi_read_data");
158 ERROR_FTDI("reading ftdi data", fuartc->fc);
159 return FUART_ERR_RD;
160 }
161 // TODO(tbroch) How do we guarantee no data loss for tx/rx
162 return FUART_ERR_NONE;
163}
164
165int fuart_close(struct fuart_context *fuartc) {
166 int rv = FUART_ERR_NONE;
167 close(fuartc->fd);
168 CHECK_FTDI(ftdi_usb_close(fuartc->fc), "fuart close", fuartc->fc);
169 ftdi_deinit(fuartc->fc);
170 return rv;
171}
172