Skip to content

Commit a2ae597

Browse files
committed
ftdi_gpio: accept new yaml config
Now local_gpio has landed, also accept a more verbose and cleaner yaml config syntax for ftdi_gpio. For now keep support for the current configuration string. Closes: #42 Signed-off-by: Neil Armstrong <[email protected]>
1 parent 6d95341 commit a2ae597

File tree

3 files changed

+213
-31
lines changed

3 files changed

+213
-31
lines changed

README

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,29 @@ devices:
8484
fastboot: cacafada
8585
fastboot_set_active: true
8686
fastboot_key_timeout: 2
87+
88+
- board: testboard2
89+
console: /dev/serial/by-id/usb-1234-if00-port0
90+
name: FTDI controller board
91+
ftdi_gpio:
92+
vendor: "0x0403"
93+
product: "0x6011"
94+
index: 0
95+
power:
96+
interface: D
97+
line: 7
98+
active_low: true
99+
fastboot_key:
100+
interface: D
101+
line: 8
102+
active_low: true
103+
power_key:
104+
interface: D
105+
line: 3
106+
active_low: true
107+
usb_disconnect:
108+
interface: D
109+
line: 2
110+
fastboot: cacafada
111+
fastboot_set_active: true
112+
fastboot_key_timeout: 2

device_parser.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ static void parse_board(struct device_parser *dp)
134134
if (dev->control_options)
135135
set_control_ops(dev, &local_gpio_ops);
136136
continue;
137+
} else if (!strcmp(key, "ftdi_gpio")) {
138+
dev->control_options = ftdi_gpio_ops.parse_options(dp);
139+
if (dev->control_options)
140+
set_control_ops(dev, &ftdi_gpio_ops);
141+
continue;
137142
}
138143

139144
device_parser_expect(dp, YAML_SCALAR_EVENT, value, TOKEN_LENGTH);
@@ -154,9 +159,6 @@ static void parse_board(struct device_parser *dp)
154159
} else if (!strcmp(key, "alpaca")) {
155160
dev->control_dev = strdup(value);
156161
set_control_ops(dev, &alpaca_ops);
157-
} else if (!strcmp(key, "ftdi_gpio")) {
158-
dev->control_dev = strdup(value);
159-
set_control_ops(dev, &ftdi_gpio_ops);
160162
} else if (!strcmp(key, "external")) {
161163
dev->control_dev = strdup(value);
162164
set_control_ops(dev, &external_ops);

ftdi-gpio.c

Lines changed: 182 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2929
* POSSIBILITY OF SUCH DAMAGE.
3030
*/
31+
#define _GNU_SOURCE
3132
#include <sys/socket.h>
3233
#include <sys/types.h>
3334
#include <arpa/inet.h>
@@ -39,9 +40,14 @@
3940
#include <string.h>
4041
#include <stdlib.h>
4142
#include <unistd.h>
43+
#include <yaml.h>
4244

4345
#include "cdba-server.h"
4446
#include "device.h"
47+
#include "device_parser.h"
48+
49+
#define TOKEN_LENGTH 16384
50+
#define FTDI_INTERFACE_COUNT 4
4551

4652
#include <ftdi.h>
4753

@@ -54,18 +60,27 @@ enum {
5460
GPIO_COUNT
5561
};
5662

57-
struct ftdi_gpio {
63+
struct ftdi_gpio_options {
5864
struct {
5965
char *description;
60-
unsigned int interface;
66+
char *vendor;
67+
char *product;
68+
char *serial;
69+
unsigned int index;
70+
char *devicenode;
6171
} ftdi;
6272
struct {
6373
bool present;
74+
unsigned int interface;
6475
unsigned int offset;
6576
bool active_low;
6677
} gpios[GPIO_COUNT];
67-
struct ftdi_context *gpio;
68-
unsigned char gpio_lines;
78+
};
79+
80+
struct ftdi_gpio {
81+
struct ftdi_gpio_options *options;
82+
struct ftdi_context *interface[FTDI_INTERFACE_COUNT];
83+
unsigned char gpio_lines[FTDI_INTERFACE_COUNT];
6984
};
7085

7186
static int ftdi_gpio_device_power(struct ftdi_gpio *ftdi_gpio, bool on);
@@ -84,8 +99,9 @@ static int ftdi_gpio_toggle_io(struct ftdi_gpio *ftdi_gpio, unsigned int gpio, b
8499
* Example: s:0xVEND:0xPROD:SERIAL;D;POWER,0,ACTIVE_LOW;FASTBOOT_KEY,1,ACTIVE_HIGH;POWER_KEY,2,ACTIVE_HIGH;USB_DISCONNECT,3,ACTIVE_LOW
85100
*/
86101

87-
static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *value)
102+
static void ftdi_gpio_parse_config(struct ftdi_gpio_options *options, char *value)
88103
{
104+
unsigned ftdi_interface = 0;
89105
char *c, *interface;
90106
size_t device_len;
91107

@@ -96,7 +112,7 @@ static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *value)
96112
else
97113
device_len = c - value;
98114

99-
ftdi_gpio->ftdi.description = strndup(value, device_len);
115+
options->ftdi.description = strndup(value, device_len);
100116

101117
if (!c)
102118
return;
@@ -109,7 +125,7 @@ static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *value)
109125
*interface != 'D') {
110126
errx(1, "Invalid interface '%c'", *interface);
111127
}
112-
ftdi_gpio->ftdi.interface = *interface - 'A';
128+
ftdi_interface = *interface - 'A';
113129

114130
c = strchr(interface, ';');
115131

@@ -156,34 +172,167 @@ static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *value)
156172
else
157173
errx(1, "GPIOs polarity invalid: '%s'", pol);
158174

159-
ftdi_gpio->gpios[gpio_type].present = true;
160-
ftdi_gpio->gpios[gpio_type].offset = gpio_offset;
161-
ftdi_gpio->gpios[gpio_type].active_low = active_low;
175+
options->gpios[gpio_type].present = true;
176+
options->gpios[gpio_type].interface = ftdi_interface;
177+
options->gpios[gpio_type].offset = gpio_offset;
178+
options->gpios[gpio_type].active_low = active_low;
162179
}
163180
}
164181

182+
void *ftdi_gpio_parse_options(struct device_parser *dp)
183+
{
184+
struct ftdi_gpio_options *options;
185+
char value[TOKEN_LENGTH];
186+
char key[TOKEN_LENGTH];
187+
188+
options = calloc(1, sizeof(*options));
189+
190+
/* Still accept legacy string */
191+
if (device_parser_accept(dp, YAML_SCALAR_EVENT, value, TOKEN_LENGTH)) {
192+
warnx("Please switch to yaml config for ftdi_gpio configuration");
193+
ftdi_gpio_parse_config(options, value);
194+
return options;
195+
}
196+
197+
device_parser_accept(dp, YAML_MAPPING_START_EVENT, NULL, 0);
198+
199+
while (device_parser_accept(dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH)) {
200+
unsigned int gpio_id;
201+
202+
if (!strcmp(key, "power")) {
203+
gpio_id = GPIO_POWER;
204+
} else if (!strcmp(key, "fastboot_key")) {
205+
gpio_id = GPIO_FASTBOOT_KEY;
206+
} else if (!strcmp(key, "power_key")) {
207+
gpio_id = GPIO_POWER_KEY;
208+
} else if (!strcmp(key, "usb_disconnect")) {
209+
gpio_id = GPIO_USB_DISCONNECT;
210+
} else if (!strcmp(key, "output_enable")) {
211+
gpio_id = GPIO_OUTPUT_ENABLE;
212+
} else {
213+
if (!device_parser_accept(dp, YAML_SCALAR_EVENT, value, TOKEN_LENGTH))
214+
errx(1, "%s: expected value for \"%s\"", __func__, key);
215+
216+
if (!strcmp(key, "vendor")) {
217+
options->ftdi.vendor = strdup(value);
218+
} else if (!strcmp(key, "product")) {
219+
options->ftdi.product = strdup(value);
220+
} else if (!strcmp(key, "index")) {
221+
options->ftdi.index = strtoul(value, NULL, 0);
222+
} else if (!strcmp(key, "serial")) {
223+
options->ftdi.serial = strdup(value);
224+
} else if (!strcmp(key, "devicenode")) {
225+
options->ftdi.devicenode = strdup(value);
226+
} else
227+
errx(1, "%s: unknown type \"%s\"", __func__, key);
228+
229+
continue;
230+
}
231+
232+
device_parser_expect(dp, YAML_MAPPING_START_EVENT, NULL, 0);
233+
234+
while (device_parser_accept(dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH)) {
235+
device_parser_accept(dp, YAML_SCALAR_EVENT, value, TOKEN_LENGTH);
236+
237+
if (!strcmp(key, "line")) {
238+
options->gpios[gpio_id].offset = strtoul(value, NULL, 0);
239+
} else if (!strcmp(key, "interface")) {
240+
if (*value != 'A' &&
241+
*value != 'B' &&
242+
*value != 'C' &&
243+
*value != 'D') {
244+
errx(1, "Invalid interface '%c' for gpio %u",
245+
*value, gpio_id);
246+
}
247+
options->gpios[gpio_id].interface = *value - 'A';
248+
} else if (!strcmp(key, "active_low")) {
249+
if (!strcmp(value, "true"))
250+
options->gpios[gpio_id].active_low = true;
251+
} else {
252+
errx(1, "%s: unknown option \"%s\"", __func__, key);
253+
exit(1);
254+
}
255+
}
256+
257+
device_parser_expect(dp, YAML_MAPPING_END_EVENT, NULL, 0);
258+
259+
options->gpios[gpio_id].present = true;
260+
}
261+
262+
device_parser_expect(dp, YAML_MAPPING_END_EVENT, NULL, 0);
263+
264+
return options;
265+
}
266+
165267
static void *ftdi_gpio_open(struct device *dev)
166268
{
167269
struct ftdi_gpio *ftdi_gpio;
168-
int ret;
270+
int i, ret;
169271

170272
ftdi_gpio = calloc(1, sizeof(*ftdi_gpio));
171273

172-
ftdi_gpio_parse_config(ftdi_gpio, dev->control_dev);
274+
ftdi_gpio->options = dev->control_options;
275+
276+
/* Setup libftdi string */
277+
if (!ftdi_gpio->options->ftdi.description) {
278+
if (ftdi_gpio->options->ftdi.devicenode)
279+
asprintf(&ftdi_gpio->options->ftdi.description,
280+
"d:%s", ftdi_gpio->options->ftdi.devicenode);
281+
else if (ftdi_gpio->options->ftdi.vendor &&
282+
ftdi_gpio->options->ftdi.product &&
283+
ftdi_gpio->options->ftdi.serial)
284+
asprintf(&ftdi_gpio->options->ftdi.description,
285+
"s:%s:%s:%s",
286+
ftdi_gpio->options->ftdi.vendor,
287+
ftdi_gpio->options->ftdi.product,
288+
ftdi_gpio->options->ftdi.serial);
289+
else if (ftdi_gpio->options->ftdi.vendor &&
290+
ftdi_gpio->options->ftdi.product &&
291+
ftdi_gpio->options->ftdi.index > 0)
292+
asprintf(&ftdi_gpio->options->ftdi.description,
293+
"i:%s:%s:%u",
294+
ftdi_gpio->options->ftdi.vendor,
295+
ftdi_gpio->options->ftdi.product,
296+
ftdi_gpio->options->ftdi.index);
297+
else if (ftdi_gpio->options->ftdi.vendor &&
298+
ftdi_gpio->options->ftdi.product)
299+
asprintf(&ftdi_gpio->options->ftdi.description,
300+
"i:%s:%s",
301+
ftdi_gpio->options->ftdi.vendor,
302+
ftdi_gpio->options->ftdi.product);
303+
else
304+
errx(1, "Incomplete FTDI description properties");
305+
}
306+
307+
for (i = 0; i < GPIO_COUNT; ++i) {
308+
unsigned int ftdi_interface;
309+
310+
if (!ftdi_gpio->options->gpios[i].present)
311+
continue;
312+
313+
ftdi_interface = ftdi_gpio->options->gpios[i].interface;
173314

174-
if ((ftdi_gpio->gpio = ftdi_new()) == 0)
175-
errx(1, "failed to allocate ftdi gpio struct");
315+
/* Skip if interface already opened */
316+
if (ftdi_gpio->interface[ftdi_interface])
317+
continue;
176318

177-
ftdi_set_interface(ftdi_gpio->gpio, INTERFACE_A + ftdi_gpio->ftdi.interface);
319+
if ((ftdi_gpio->interface[ftdi_interface] = ftdi_new()) == 0)
320+
errx(1, "failed to allocate ftdi gpio struct");
178321

179-
ret = ftdi_usb_open_string(ftdi_gpio->gpio, ftdi_gpio->ftdi.description);
180-
if (ret < 0)
181-
errx(1, "failed to open ftdi gpio device '%s' (%d)",
182-
ftdi_gpio->ftdi.description, ret);
322+
ftdi_set_interface(ftdi_gpio->interface[ftdi_interface],
323+
INTERFACE_A + ftdi_interface);
183324

184-
ftdi_set_bitmode(ftdi_gpio->gpio, 0xFF, BITMODE_BITBANG);
325+
ret = ftdi_usb_open_string(ftdi_gpio->interface[ftdi_interface],
326+
ftdi_gpio->options->ftdi.description);
327+
if (ret < 0)
328+
errx(1, "failed to open ftdi gpio device '%s' (%d)",
329+
ftdi_gpio->options->ftdi.description, ret);
185330

186-
if (ftdi_gpio->gpios[GPIO_POWER_KEY].present)
331+
ftdi_set_bitmode(ftdi_gpio->interface[ftdi_interface],
332+
0xFF, BITMODE_BITBANG);
333+
}
334+
335+
if (ftdi_gpio->options->gpios[GPIO_POWER_KEY].present)
187336
dev->has_power_key = true;
188337

189338
ftdi_gpio_device_power(ftdi_gpio, 0);
@@ -193,7 +342,7 @@ static void *ftdi_gpio_open(struct device *dev)
193342
else
194343
ftdi_gpio_device_usb(ftdi_gpio, 0);
195344

196-
if (ftdi_gpio->gpio_present[GPIO_OUTPUT_ENABLE])
345+
if (ftdi_gpio->options->gpios[GPIO_OUTPUT_ENABLE].present)
197346
ftdi_gpio_toggle_io(ftdi_gpio, GPIO_OUTPUT_ENABLE, 1);
198347

199348
usleep(500000);
@@ -203,22 +352,26 @@ static void *ftdi_gpio_open(struct device *dev)
203352

204353
static int ftdi_gpio_toggle_io(struct ftdi_gpio *ftdi_gpio, unsigned int gpio, bool on)
205354
{
355+
unsigned int ftdi_interface;
206356
unsigned int bit;
207357

208-
if (!ftdi_gpio->gpios[gpio].present)
358+
if (!ftdi_gpio->options->gpios[gpio].present)
209359
return -EINVAL;
210360

211-
bit = ftdi_gpio->gpios[gpio].offset;
361+
ftdi_interface = ftdi_gpio->options->gpios[gpio].interface;
362+
363+
bit = ftdi_gpio->options->gpios[gpio].offset;
212364

213-
if (ftdi_gpio->gpios[gpio].active_low)
365+
if (ftdi_gpio->options->gpios[gpio].active_low)
214366
on = !on;
215367

216368
if (on)
217-
ftdi_gpio->gpio_lines |= (1 << bit);
369+
ftdi_gpio->gpio_lines[ftdi_interface] |= (1 << bit);
218370
else
219-
ftdi_gpio->gpio_lines &= ~(1 << bit);
371+
ftdi_gpio->gpio_lines[ftdi_interface] &= ~(1 << bit);
220372

221-
return ftdi_write_data(ftdi_gpio->gpio, &ftdi_gpio->gpio_lines, 1);
373+
return ftdi_write_data(ftdi_gpio->interface[ftdi_interface],
374+
&ftdi_gpio->gpio_lines[ftdi_interface], 1);
222375
}
223376

224377
static int ftdi_gpio_device_power(struct ftdi_gpio *ftdi_gpio, bool on)
@@ -260,6 +413,7 @@ static void ftdi_gpio_key(struct device *dev, int key, bool asserted)
260413
}
261414

262415
const struct control_ops ftdi_gpio_ops = {
416+
.parse_options = ftdi_gpio_parse_options,
263417
.open = ftdi_gpio_open,
264418
.power = ftdi_gpio_power,
265419
.usb = ftdi_gpio_usb,

0 commit comments

Comments
 (0)