Skip to content

Commit 01ebafc

Browse files
authored
Merge pull request #44 from superna9999/ftdi-gpio-yaml-parsing
Ftdi gpio yaml parsing
2 parents abcf427 + a2ae597 commit 01ebafc

File tree

3 files changed

+224
-42
lines changed

3 files changed

+224
-42
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: 193 additions & 39 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,19 +60,27 @@ enum {
5460
GPIO_COUNT
5561
};
5662

57-
enum {
58-
GPIO_ACTIVE_HIGH = 0,
59-
GPIO_ACTIVE_LOW,
63+
struct ftdi_gpio_options {
64+
struct {
65+
char *description;
66+
char *vendor;
67+
char *product;
68+
char *serial;
69+
unsigned int index;
70+
char *devicenode;
71+
} ftdi;
72+
struct {
73+
bool present;
74+
unsigned int interface;
75+
unsigned int offset;
76+
bool active_low;
77+
} gpios[GPIO_COUNT];
6078
};
6179

6280
struct ftdi_gpio {
63-
struct ftdi_context *gpio;
64-
char *ftdi_device;
65-
unsigned int ftdi_interface;
66-
unsigned int gpio_present[GPIO_COUNT];
67-
unsigned int gpio_offset[GPIO_COUNT];
68-
unsigned int gpio_polarity[GPIO_COUNT];
69-
unsigned char gpio_lines;
81+
struct ftdi_gpio_options *options;
82+
struct ftdi_context *interface[FTDI_INTERFACE_COUNT];
83+
unsigned char gpio_lines[FTDI_INTERFACE_COUNT];
7084
};
7185

7286
static int ftdi_gpio_device_power(struct ftdi_gpio *ftdi_gpio, bool on);
@@ -85,19 +99,20 @@ static int ftdi_gpio_toggle_io(struct ftdi_gpio *ftdi_gpio, unsigned int gpio, b
8599
* 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
86100
*/
87101

88-
static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *control_dev)
102+
static void ftdi_gpio_parse_config(struct ftdi_gpio_options *options, char *value)
89103
{
104+
unsigned ftdi_interface = 0;
90105
char *c, *interface;
91106
size_t device_len;
92107

93108
// First libftdi description
94-
c = strchr(control_dev, ';');
109+
c = strchr(value, ';');
95110
if (!c)
96-
device_len = strlen(control_dev);
111+
device_len = strlen(value);
97112
else
98-
device_len = c - control_dev;
113+
device_len = c - value;
99114

100-
ftdi_gpio->ftdi_device = strndup(control_dev, device_len);
115+
options->ftdi.description = strndup(value, device_len);
101116

102117
if (!c)
103118
return;
@@ -110,7 +125,7 @@ static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *control_de
110125
*interface != 'D') {
111126
errx(1, "Invalid interface '%c'", *interface);
112127
}
113-
ftdi_gpio->ftdi_interface = *interface - 'A';
128+
ftdi_interface = *interface - 'A';
114129

115130
c = strchr(interface, ';');
116131

@@ -119,7 +134,7 @@ static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *control_de
119134
char *name, *off, *pol;
120135
unsigned gpio_type;
121136
unsigned gpio_offset;
122-
unsigned gpio_polarity;
137+
bool active_low;
123138

124139
name = c + 1;
125140
off = strchr(name, ',');
@@ -151,39 +166,173 @@ static void ftdi_gpio_parse_config(struct ftdi_gpio *ftdi_gpio, char *control_de
151166
errx(1, "GPIOs offset invalid: '%u'", gpio_offset);
152167

153168
if (strncmp("ACTIVE_HIGH", pol, c - pol - 1) == 0)
154-
gpio_polarity = GPIO_ACTIVE_HIGH;
169+
active_low = false;
155170
else if (strncmp("ACTIVE_LOW", pol, c - pol - 1) == 0)
156-
gpio_polarity = GPIO_ACTIVE_LOW;
171+
active_low = true;
157172
else
158173
errx(1, "GPIOs polarity invalid: '%s'", pol);
159174

160-
ftdi_gpio->gpio_present[gpio_type] = 1;
161-
ftdi_gpio->gpio_offset[gpio_type] = gpio_offset;
162-
ftdi_gpio->gpio_polarity[gpio_type] = gpio_polarity;
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;
179+
}
180+
}
181+
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;
163260
}
261+
262+
device_parser_expect(dp, YAML_MAPPING_END_EVENT, NULL, 0);
263+
264+
return options;
164265
}
165266

166267
static void *ftdi_gpio_open(struct device *dev)
167268
{
168269
struct ftdi_gpio *ftdi_gpio;
169-
int ret;
270+
int i, ret;
170271

171272
ftdi_gpio = calloc(1, sizeof(*ftdi_gpio));
172273

173-
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;
174312

175-
if ((ftdi_gpio->gpio = ftdi_new()) == 0)
176-
errx(1, "failed to allocate ftdi gpio struct");
313+
ftdi_interface = ftdi_gpio->options->gpios[i].interface;
177314

178-
ftdi_set_interface(ftdi_gpio->gpio, INTERFACE_A + ftdi_gpio->ftdi_interface);
315+
/* Skip if interface already opened */
316+
if (ftdi_gpio->interface[ftdi_interface])
317+
continue;
179318

180-
ret = ftdi_usb_open_string(ftdi_gpio->gpio, ftdi_gpio->ftdi_device);
181-
if (ret < 0)
182-
errx(1, "failed to open ftdi gpio device '%s' (%d)", ftdi_gpio->ftdi_device, ret);
319+
if ((ftdi_gpio->interface[ftdi_interface] = ftdi_new()) == 0)
320+
errx(1, "failed to allocate ftdi gpio struct");
183321

184-
ftdi_set_bitmode(ftdi_gpio->gpio, 0xFF, BITMODE_BITBANG);
322+
ftdi_set_interface(ftdi_gpio->interface[ftdi_interface],
323+
INTERFACE_A + ftdi_interface);
185324

186-
if (ftdi_gpio->gpio_present[GPIO_POWER_KEY])
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);
330+
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->gpio_present[gpio])
358+
if (!ftdi_gpio->options->gpios[gpio].present)
209359
return -EINVAL;
210360

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

213-
if (ftdi_gpio->gpio_polarity[gpio])
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)