1 /*
2 * avrdude - A Downloader/Uploader for AVR device programmers
3 * Support for bitbanging GPIO pins using the /sys/class/gpio interface
4 *
5 * Copyright (C) 2013 Radoslav Kolev <radoslav@kolev.info>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "ac_cfg.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <errno.h>
30
31 #include "avrdude.h"
32 #include "libavrdude.h"
33
34 #include "bitbang.h"
35
36 #if HAVE_LINUXGPIO
37
38 /*
39 * GPIO user space helpers
40 *
41 * Copyright 2009 Analog Devices Inc.
42 * Michael Hennerich (hennerich@blackfin.uclinux.org)
43 *
44 * Licensed under the GPL-2 or later
45 */
46
47 /*
48 * GPIO user space helpers
49 * The following functions are acting on an "unsigned gpio" argument, which corresponds to the
50 * gpio numbering scheme in the kernel (starting from 0).
51 * The higher level functions use "int pin" to specify the pins with an offset of 1:
52 * gpio = pin - 1;
53 */
54
55 #define GPIO_DIR_IN 0
56 #define GPIO_DIR_OUT 1
57
linuxgpio_export(unsigned int gpio)58 static int linuxgpio_export(unsigned int gpio)
59 {
60 int fd, len, r;
61 char buf[11];
62
63 fd = open("/sys/class/gpio/export", O_WRONLY);
64 if (fd < 0) {
65 perror("Can't open /sys/class/gpio/export");
66 return fd;
67 }
68
69 len = snprintf(buf, sizeof(buf), "%ud", gpio);
70 r = write(fd, buf, len);
71 close(fd);
72
73 return r;
74 }
75
linuxgpio_unexport(unsigned int gpio)76 static int linuxgpio_unexport(unsigned int gpio)
77 {
78 int fd, len, r;
79 char buf[11];
80
81 fd = open("/sys/class/gpio/unexport", O_WRONLY);
82 if (fd < 0) {
83 perror("Can't open /sys/class/gpio/unexport");
84 return fd;
85 }
86
87 len = snprintf(buf, sizeof(buf), "%ud", gpio);
88 r = write(fd, buf, len);
89 close(fd);
90
91 return r;
92 }
93
linuxgpio_openfd(unsigned int gpio)94 static int linuxgpio_openfd(unsigned int gpio)
95 {
96 char filepath[60];
97
98 snprintf(filepath, sizeof(filepath), "/sys/class/gpio/gpio%ud/value", gpio);
99 return (open(filepath, O_RDWR));
100 }
101
linuxgpio_dir(unsigned int gpio,unsigned int dir)102 static int linuxgpio_dir(unsigned int gpio, unsigned int dir)
103 {
104 int fd, r;
105 char buf[60];
106
107 snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%ud/direction", gpio);
108
109 fd = open(buf, O_WRONLY);
110 if (fd < 0) {
111 perror("Can't open gpioX/direction");
112 return fd;
113 }
114
115 if (dir == GPIO_DIR_OUT)
116 r = write(fd, "out", 4);
117 else
118 r = write(fd, "in", 3);
119
120 close(fd);
121
122 return r;
123 }
124
linuxgpio_dir_out(unsigned int gpio)125 static int linuxgpio_dir_out(unsigned int gpio)
126 {
127 return linuxgpio_dir(gpio, GPIO_DIR_OUT);
128 }
129
linuxgpio_dir_in(unsigned int gpio)130 static int linuxgpio_dir_in(unsigned int gpio)
131 {
132 return linuxgpio_dir(gpio, GPIO_DIR_IN);
133 }
134
135 /*
136 * End of GPIO user space helpers
137 */
138
139 #define N_GPIO (PIN_MAX + 1)
140
141 /*
142 * an array which holds open FDs to /sys/class/gpio/gpioXX/value for all needed pins
143 */
144 static int linuxgpio_fds[N_GPIO] ;
145
146
linuxgpio_setpin(PROGRAMMER * pgm,int pinfunc,int value)147 static int linuxgpio_setpin(PROGRAMMER * pgm, int pinfunc, int value)
148 {
149 int r;
150 int pin = pgm->pinno[pinfunc]; // TODO
151
152 if (pin & PIN_INVERSE)
153 {
154 value = !value;
155 pin &= PIN_MASK;
156 }
157
158 if ( linuxgpio_fds[pin] < 0 )
159 return -1;
160
161 if (value)
162 r = write(linuxgpio_fds[pin], "1", 1);
163 else
164 r = write(linuxgpio_fds[pin], "0", 1);
165
166 if (r!=1) return -1;
167
168 if (pgm->ispdelay > 1)
169 bitbang_delay(pgm->ispdelay);
170
171 return 0;
172 }
173
linuxgpio_getpin(PROGRAMMER * pgm,int pinfunc)174 static int linuxgpio_getpin(PROGRAMMER * pgm, int pinfunc)
175 {
176 unsigned char invert=0;
177 char c;
178 int pin = pgm->pinno[pinfunc]; // TODO
179
180 if (pin & PIN_INVERSE)
181 {
182 invert = 1;
183 pin &= PIN_MASK;
184 }
185
186 if ( linuxgpio_fds[pin] < 0 )
187 return -1;
188
189 if (lseek(linuxgpio_fds[pin], 0, SEEK_SET)<0)
190 return -1;
191
192 if (read(linuxgpio_fds[pin], &c, 1)!=1)
193 return -1;
194
195 if (c=='0')
196 return 0+invert;
197 else if (c=='1')
198 return 1-invert;
199 else
200 return -1;
201
202 }
203
linuxgpio_highpulsepin(PROGRAMMER * pgm,int pinfunc)204 static int linuxgpio_highpulsepin(PROGRAMMER * pgm, int pinfunc)
205 {
206 int pin = pgm->pinno[pinfunc]; // TODO
207
208 if ( linuxgpio_fds[pin & PIN_MASK] < 0 )
209 return -1;
210
211 linuxgpio_setpin(pgm, pinfunc, 1);
212 linuxgpio_setpin(pgm, pinfunc, 0);
213
214 return 0;
215 }
216
217
218
linuxgpio_display(PROGRAMMER * pgm,const char * p)219 static void linuxgpio_display(PROGRAMMER *pgm, const char *p)
220 {
221 avrdude_message(MSG_INFO, "%sPin assignment : /sys/class/gpio/gpio{n}\n",p);
222 pgm_display_generic_mask(pgm, p, SHOW_AVR_PINS);
223 }
224
linuxgpio_enable(PROGRAMMER * pgm)225 static void linuxgpio_enable(PROGRAMMER *pgm)
226 {
227 /* nothing */
228 }
229
linuxgpio_disable(PROGRAMMER * pgm)230 static void linuxgpio_disable(PROGRAMMER *pgm)
231 {
232 /* nothing */
233 }
234
linuxgpio_powerup(PROGRAMMER * pgm)235 static void linuxgpio_powerup(PROGRAMMER *pgm)
236 {
237 /* nothing */
238 }
239
linuxgpio_powerdown(PROGRAMMER * pgm)240 static void linuxgpio_powerdown(PROGRAMMER *pgm)
241 {
242 /* nothing */
243 }
244
linuxgpio_open(PROGRAMMER * pgm,char * port)245 static int linuxgpio_open(PROGRAMMER *pgm, char *port)
246 {
247 int r, i, pin;
248
249 if (bitbang_check_prerequisites(pgm) < 0)
250 return -1;
251
252
253 for (i=0; i<N_GPIO; i++)
254 linuxgpio_fds[i] = -1;
255 //Avrdude assumes that if a pin number is 0 it means not used/available
256 //this causes a problem because 0 is a valid GPIO number in Linux sysfs.
257 //To avoid annoying off by one pin numbering we assume SCK, MOSI, MISO
258 //and RESET pins are always defined in avrdude.conf, even as 0. If they're
259 //not programming will not work anyway. The drawbacks of this approach are
260 //that unwanted toggling of GPIO0 can occur and that other optional pins
261 //mostry LED status, can't be set to GPIO0. It can be fixed when a better
262 //solution exists.
263 for (i=0; i<N_PINS; i++) {
264 if ( (pgm->pinno[i] & PIN_MASK) != 0 ||
265 i == PIN_AVR_RESET ||
266 i == PIN_AVR_SCK ||
267 i == PIN_AVR_MOSI ||
268 i == PIN_AVR_MISO ) {
269 pin = pgm->pinno[i] & PIN_MASK;
270 if ((r=linuxgpio_export(pin)) < 0) {
271 avrdude_message(MSG_INFO, "Can't export GPIO %d, already exported/busy?: %s",
272 pin, strerror(errno));
273 return r;
274 }
275 if (i == PIN_AVR_MISO)
276 r=linuxgpio_dir_in(pin);
277 else
278 r=linuxgpio_dir_out(pin);
279
280 if (r < 0)
281 return r;
282
283 if ((linuxgpio_fds[pin]=linuxgpio_openfd(pin)) < 0)
284 return linuxgpio_fds[pin];
285 }
286 }
287
288 return(0);
289 }
290
linuxgpio_close(PROGRAMMER * pgm)291 static void linuxgpio_close(PROGRAMMER *pgm)
292 {
293 int i, reset_pin;
294
295 reset_pin = pgm->pinno[PIN_AVR_RESET] & PIN_MASK;
296
297 //first configure all pins as input, except RESET
298 //this should avoid possible conflicts when AVR firmware starts
299 for (i=0; i<N_GPIO; i++) {
300 if (linuxgpio_fds[i] >= 0 && i != reset_pin) {
301 close(linuxgpio_fds[i]);
302 linuxgpio_dir_in(i);
303 linuxgpio_unexport(i);
304 }
305 }
306 //configure RESET as input, if there's external pull up it will go high
307 if (linuxgpio_fds[reset_pin] >= 0) {
308 close(linuxgpio_fds[reset_pin]);
309 linuxgpio_dir_in(reset_pin);
310 linuxgpio_unexport(reset_pin);
311 }
312 }
313
linuxgpio_initpgm(PROGRAMMER * pgm)314 void linuxgpio_initpgm(PROGRAMMER *pgm)
315 {
316 strcpy(pgm->type, "linuxgpio");
317
318 pgm_fill_old_pins(pgm); // TODO to be removed if old pin data no longer needed
319
320 pgm->rdy_led = bitbang_rdy_led;
321 pgm->err_led = bitbang_err_led;
322 pgm->pgm_led = bitbang_pgm_led;
323 pgm->vfy_led = bitbang_vfy_led;
324 pgm->initialize = bitbang_initialize;
325 pgm->display = linuxgpio_display;
326 pgm->enable = linuxgpio_enable;
327 pgm->disable = linuxgpio_disable;
328 pgm->powerup = linuxgpio_powerup;
329 pgm->powerdown = linuxgpio_powerdown;
330 pgm->program_enable = bitbang_program_enable;
331 pgm->chip_erase = bitbang_chip_erase;
332 pgm->cmd = bitbang_cmd;
333 pgm->open = linuxgpio_open;
334 pgm->close = linuxgpio_close;
335 pgm->setpin = linuxgpio_setpin;
336 pgm->getpin = linuxgpio_getpin;
337 pgm->highpulsepin = linuxgpio_highpulsepin;
338 pgm->read_byte = avr_read_byte_default;
339 pgm->write_byte = avr_write_byte_default;
340 }
341
342 const char linuxgpio_desc[] = "GPIO bitbanging using the Linux sysfs interface";
343
344 #else /* !HAVE_LINUXGPIO */
345
linuxgpio_initpgm(PROGRAMMER * pgm)346 void linuxgpio_initpgm(PROGRAMMER * pgm)
347 {
348 avrdude_message(MSG_INFO, "%s: Linux sysfs GPIO support not available in this configuration\n",
349 progname);
350 }
351
352 const char linuxgpio_desc[] = "GPIO bitbanging using the Linux sysfs interface (not available)";
353
354 #endif /* HAVE_LINUXGPIO */
355