Add firmware for the ATUSB IEEE 802.15.4 USB Adapter
[linux-libre-firmware.git] / atusb / ep0.c
1 /*
2  * fw/ep0.c - EP0 extension protocol
3  *
4  * Written 2008-2011, 2013 by Werner Almesberger
5  * Copyright 2008-2011, 2013 Werner Almesberger
6  * Copyright 2015-2016 Stefan Schmidt
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13
14
15 #include <stdbool.h>
16 #include <stdint.h>
17 #include <string.h>
18
19 #include <avr/io.h>
20 #include <avr/eeprom.h>
21
22 #define F_CPU   8000000UL
23 #include <util/delay.h>
24
25 #ifndef NULL
26 #define NULL 0
27 #endif
28
29 #include "usb.h"
30 #include "dfu.h"
31
32 #include "at86rf230.h"
33 #include "atusb/ep0.h"
34 #include "version.h"
35 #include "board.h"
36 #include "sernum.h"
37 #include "spi.h"
38 #include "mac.h"
39
40 #ifdef ATUSB
41 #define HW_TYPE         ATUSB_HW_TYPE_110131
42 #endif
43
44 #ifdef RZUSB
45 #define HW_TYPE         ATUSB_HW_TYPE_RZUSB
46 #endif
47
48 #ifdef HULUSB
49 #define HW_TYPE         ATUSB_HW_TYPE_HULUSB
50 #endif
51
52 #ifdef DEBUG
53 #include "uart.h"
54 #include <stdio.h>
55 #define debug(FORMAT,args...) printf(FORMAT,##args)
56 #define error(FORMAT,args...) printf(FORMAT,##args)
57 #else
58 #define debug(...)
59 #define error(...)
60 #endif
61
62
63 static const uint8_t id[] = { EP0ATUSB_MAJOR, EP0ATUSB_MINOR, HW_TYPE };
64 static uint8_t buf[MAX_PSDU+3]; /* command, PHDR, and LQI */
65 static uint8_t size;
66
67
68 static void do_eeprom_write(void *user)
69 {
70         int i;
71
72         for (i = 0; i < size; i++)
73                 eeprom_update_byte((uint8_t*)i, buf[i]);
74 }
75
76 static void do_buf_write(void *user)
77 {
78         uint8_t i;
79
80         spi_begin();
81         for (i = 0; i != size; i++)
82                 spi_send(buf[i]);
83         spi_end();
84 }
85
86
87 #define BUILD_OFFSET    7       /* '#' plus "65535" plus ' ' */
88
89
90 static bool my_setup(const struct setup_request *setup)
91 {
92         uint16_t req = setup->bmRequestType | setup->bRequest << 8;
93         unsigned tmp;
94         uint8_t i;
95         uint64_t tmp64;
96
97         switch (req) {
98         case ATUSB_FROM_DEV(ATUSB_ID):
99                 debug("ATUSB_ID\n");
100                 if (setup->wLength > 3)
101                         return 0;
102                 usb_send(&eps[0], id, setup->wLength, NULL, NULL);
103                 return 1;
104         case ATUSB_FROM_DEV(ATUSB_BUILD):
105                 debug("ATUSB_BUILD\n");
106                 tmp = build_number;
107                 for (i = BUILD_OFFSET-2; tmp; i--) {
108                         buf[i] = (tmp % 10)+'0';
109                         tmp /= 10;
110                 }
111                 buf[i] = '#';
112                 buf[BUILD_OFFSET-1] = ' ';
113                 for (size = 0; build_date[size]; size++)
114                         buf[BUILD_OFFSET+size] = build_date[size];
115                 size += BUILD_OFFSET-i;
116                 if (size > setup->wLength)
117                         return 0;
118                 usb_send(&eps[0], buf+i, size, NULL, NULL);
119                 return 1;
120
121         case ATUSB_TO_DEV(ATUSB_RESET):
122                 debug("ATUSB_RESET\n");
123                 reset_cpu();
124                 while (1);
125
126         case ATUSB_TO_DEV(ATUSB_RF_RESET):
127                 debug("ATUSB_RF_RESET\n");
128                 reset_rf();
129                 mac_reset();
130                 //ep_send_zlp(EP_CTRL);
131                 return 1;
132
133         case ATUSB_FROM_DEV(ATUSB_POLL_INT):
134                 debug("ATUSB_POLL_INT\n");
135                 if (setup->wLength < 1)
136                         return 0;
137                 *buf = read_irq();
138                 usb_send(&eps[0], buf, 1, NULL, NULL);
139                 return 1;
140
141         case ATUSB_FROM_DEV(ATUSB_TIMER):
142                 debug("ATUSB_TIMER\n");
143                 size = setup->wLength;
144                 if (size > sizeof(tmp64))
145                         size = sizeof(tmp64);
146                 tmp64 = timer_read();
147                 memcpy(buf, &tmp64, sizeof(tmp64));
148                 usb_send(&eps[0], buf, size, NULL, NULL);
149                 return 1;
150
151         case ATUSB_FROM_DEV(ATUSB_GPIO):
152                 debug("ATUSB_GPIO\n");
153                 if (setup->wLength < 3)
154                         return 0;
155                 if (!gpio(setup->wIndex, setup->wValue, setup->wValue >> 8,
156                     setup->wIndex >> 8, buf))
157                         return 0;
158                 usb_send(&eps[0], buf, 3, NULL, NULL);
159                 return 1;
160         case ATUSB_TO_DEV(ATUSB_GPIO_CLEANUP):
161                 gpio_cleanup();
162                 return 1;
163
164         case ATUSB_TO_DEV(ATUSB_SLP_TR):
165                 debug("ATUSB_SLP_TR\n");
166                 slp_tr();
167                 return 1;
168
169         case ATUSB_TO_DEV(ATUSB_REG_WRITE):
170                 debug("ATUSB_REG_WRITE\n");
171                 spi_begin();
172                 spi_send(AT86RF230_REG_WRITE | setup->wIndex);
173                 spi_send(setup->wValue);
174                 spi_end();
175                 //ep_send_zlp(EP_CTRL);
176                 return 1;
177         case ATUSB_FROM_DEV(ATUSB_REG_READ):
178                 debug("ATUSB_REG_READ\n");
179                 spi_begin();
180                 spi_send(AT86RF230_REG_READ | setup->wIndex);
181                 *buf = spi_recv();
182                 spi_end();
183                 usb_send(&eps[0], buf, 1, NULL, NULL);
184                 return 1;
185
186         case ATUSB_TO_DEV(ATUSB_BUF_WRITE):
187                 debug("ATUSB_BUF_WRITE\n");
188                 if (setup->wLength < 1)
189                         return 0;
190                 if (setup->wLength > MAX_PSDU)
191                         return 0;
192                 buf[0] = AT86RF230_BUF_WRITE;
193                 buf[1] = setup->wLength;
194                 size = setup->wLength+2;
195                 usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
196                 return 1;
197         case ATUSB_FROM_DEV(ATUSB_BUF_READ):
198                 debug("ATUSB_BUF_READ\n");
199                 if (setup->wLength < 2)                 /* PHR+LQI */
200                         return 0;
201                 if (setup->wLength > MAX_PSDU+2)        /* PHR+PSDU+LQI */
202                         return 0;
203                 spi_begin();
204                 spi_send(AT86RF230_BUF_READ);
205                 size = spi_recv();
206                 if (size >= setup->wLength)
207                         size = setup->wLength-1;
208                 for (i = 0; i != size+1; i++)
209                         buf[i] = spi_recv();
210                 spi_end();
211                 usb_send(&eps[0], buf, size+1, NULL, NULL);
212                 return 1;
213
214         case ATUSB_TO_DEV(ATUSB_SRAM_WRITE):
215                 debug("ATUSB_SRAM_WRITE\n");
216                 if (setup->wIndex > SRAM_SIZE)
217                         return 0;
218                 if (setup->wIndex+setup->wLength > SRAM_SIZE)
219                         return 0;
220                 buf[0] = AT86RF230_SRAM_WRITE;
221                 buf[1] = setup->wIndex;
222                 size = setup->wLength+2;
223                 usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
224                 return 1;
225         case ATUSB_FROM_DEV(ATUSB_SRAM_READ):
226                 debug("ATUSB_SRAM_READ\n");
227                 if (setup->wIndex > SRAM_SIZE)
228                         return 0;
229                 if (setup->wIndex+setup->wLength > SRAM_SIZE)
230                         return 0;
231                 spi_begin();
232                 spi_send(AT86RF230_SRAM_READ);
233                 spi_send(setup->wIndex);
234                 for (i = 0; i != setup->wLength; i++)
235                         buf[i] = spi_recv();
236                 spi_end();
237                 usb_send(&eps[0], buf, setup->wLength, NULL, NULL);
238                 return 1;
239
240         case ATUSB_TO_DEV(ATUSB_SPI_WRITE):
241                 size = setup->wLength+2;
242                 if (size > sizeof(buf))
243                         return 0;
244                 buf[0] = setup->wValue;
245                 buf[1] = setup->wIndex;
246                 if (setup->wLength)
247                         usb_recv(&eps[0], buf+2, setup->wLength,
248                             do_buf_write, NULL);
249                 else
250                         do_buf_write(NULL);
251                 return 1;
252         case ATUSB_FROM_DEV(ATUSB_SPI_WRITE2_SYNC):
253                 spi_begin();
254                 spi_send(setup->wValue);
255                 spi_send(setup->wIndex);
256                 spi_end();
257                 buf[0] = irq_serial;
258                 if (setup->wLength)
259                         usb_send(&eps[0], buf, 1, NULL, NULL);
260                 return 1;
261
262         case ATUSB_FROM_DEV(ATUSB_SPI_READ1):
263         case ATUSB_FROM_DEV(ATUSB_SPI_READ2):
264                 spi_begin();
265                 spi_send(setup->wValue);
266                 if (req == ATUSB_FROM_DEV(ATUSB_SPI_READ2))
267                         spi_send(setup->wIndex);
268                 for (i = 0; i != setup->wLength; i++)
269                         buf[i] = spi_recv();
270                 spi_end();
271                 usb_send(&eps[0], buf, setup->wLength, NULL, NULL);
272                 return 1;
273
274         case ATUSB_TO_DEV(ATUSB_RX_MODE):
275                 return mac_rx(setup->wValue);
276         case ATUSB_TO_DEV(ATUSB_TX):
277                 return mac_tx(setup->wValue, setup->wIndex, setup->wLength);
278         case ATUSB_TO_DEV(ATUSB_EUI64_WRITE):
279                 debug("ATUSB_EUI64_WRITE\n");
280                 usb_recv(&eps[0], buf, setup->wLength, do_eeprom_write, NULL);
281                 _delay_ms(100);
282                 reset_cpu();
283                 return 1;
284
285         case ATUSB_FROM_DEV(ATUSB_EUI64_READ):
286                 debug("ATUSB_EUI64_READ\n");
287                 eeprom_read_block(buf, (const void*)0, 8);
288                 usb_send(&eps[0], buf, 8, NULL, NULL);
289                 return 1;
290
291         default:
292                 error("Unrecognized SETUP: 0x%02x 0x%02x ...\n",
293                     setup->bmRequestType, setup->bRequest);
294                 return 0;
295         }
296 }
297
298
299 static bool my_dfu_setup(const struct setup_request *setup)
300 {
301         switch (setup->bmRequestType | setup->bRequest << 8) {
302         case DFU_TO_DEV(DFU_DETACH):
303                 /* @@@ should use wTimeout */
304                 dfu.state = appDETACH;
305                 return 1;
306         default:
307                 return dfu_setup_common(setup);
308         }
309 }
310
311
312 static void my_set_interface(int nth)
313 {
314         if (nth) {
315                 user_setup = my_dfu_setup;
316                 user_get_descriptor = dfu_my_descr;
317                 dfu.state = appIDLE;
318         } else {
319                 user_setup = my_setup;
320                 user_get_descriptor = sernum_get_descr;
321         }
322 }
323
324
325 static void my_reset(void)
326 {
327         if (dfu.state == appDETACH)
328                 reset_cpu();
329 }
330
331
332 void ep0_init(void)
333 {
334         user_setup = my_setup;
335         user_set_interface = my_set_interface;
336         my_set_interface(0);
337         user_reset = my_reset;
338 }