source: avrstuff/starkadroid/usbbootloader/main.c@ 4b06930

main
Last change on this file since 4b06930 was 4b06930, checked in by Adrien Destugues <pulkomandy@…>, 14 years ago

Copie de ak2usbpour faire starkadroid: usb hid pour borne d'arcade (jusqu'à 36 boutons)

git-svn-id: svn://pulkomandy.tk/avrstuff@22 c6672c3c-f6b6-47f9-9001-1fd6b12fecbe

  • Property mode set to 100644
File size: 9.8 KB
Line 
1/* Name: main.c
2 * Project: USBaspLoader
3 * Author: Christian Starkjohann
4 * Creation Date: 2007-12-08
5 * Tabsize: 4
6 * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
7 * License: GNU GPL v2 (see License.txt)
8 * This Revision: $Id: main.c 730 2009-03-20 09:05:11Z cs $
9 */
10
11#include <avr/io.h>
12#include <avr/interrupt.h>
13#include <avr/pgmspace.h>
14#include <avr/wdt.h>
15#include <avr/boot.h>
16#include <avr/eeprom.h>
17#include <util/delay.h>
18#include <string.h>
19
20static void leaveBootloader() __attribute__((__noreturn__));
21
22#include "bootloaderconfig.h"
23#include "usbdrv/usbdrv.c"
24
25/* ------------------------------------------------------------------------ */
26
27/* Request constants used by USBasp */
28#define USBASP_FUNC_CONNECT 1
29#define USBASP_FUNC_DISCONNECT 2
30#define USBASP_FUNC_TRANSMIT 3
31#define USBASP_FUNC_READFLASH 4
32#define USBASP_FUNC_ENABLEPROG 5
33#define USBASP_FUNC_WRITEFLASH 6
34#define USBASP_FUNC_READEEPROM 7
35#define USBASP_FUNC_WRITEEEPROM 8
36#define USBASP_FUNC_SETLONGADDRESS 9
37
38/* ------------------------------------------------------------------------ */
39
40#ifndef ulong
41# define ulong unsigned long
42#endif
43#ifndef uint
44# define uint unsigned int
45#endif
46
47/* defaults if not in config file: */
48#ifndef HAVE_EEPROM_PAGED_ACCESS
49# define HAVE_EEPROM_PAGED_ACCESS 0
50#endif
51#ifndef HAVE_EEPROM_BYTE_ACCESS
52# define HAVE_EEPROM_BYTE_ACCESS 0
53#endif
54#ifndef BOOTLOADER_CAN_EXIT
55# define BOOTLOADER_CAN_EXIT 0
56#endif
57
58/* allow compatibility with avrusbboot's bootloaderconfig.h: */
59#ifdef BOOTLOADER_INIT
60# define bootLoaderInit() BOOTLOADER_INIT
61# define bootLoaderExit()
62#endif
63#ifdef BOOTLOADER_CONDITION
64# define bootLoaderCondition() BOOTLOADER_CONDITION
65#endif
66
67/* device compatibility: */
68#ifndef GICR /* ATMega*8 don't have GICR, use MCUCR instead */
69# define GICR MCUCR
70#endif
71
72/* ------------------------------------------------------------------------ */
73
74#if (FLASHEND) > 0xffff /* we need long addressing */
75# define CURRENT_ADDRESS currentAddress.l
76# define addr_t ulong
77#else
78# define CURRENT_ADDRESS currentAddress.w[0]
79# define addr_t uint
80#endif
81
82typedef union longConverter{
83 addr_t l;
84 uint w[sizeof(addr_t)/2];
85 uchar b[sizeof(addr_t)];
86}longConverter_t;
87
88static uchar requestBootLoaderExit;
89static longConverter_t currentAddress; /* in bytes */
90static uchar bytesRemaining;
91static uchar isLastPage;
92#if HAVE_EEPROM_PAGED_ACCESS
93static uchar currentRequest;
94#else
95static const uchar currentRequest = 0;
96#endif
97
98static const uchar signatureBytes[4] = {
99#ifdef SIGNATURE_BYTES
100 SIGNATURE_BYTES
101#elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega8HVA__)
102 0x1e, 0x93, 0x07, 0
103#elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48P__)
104 0x1e, 0x92, 0x05, 0
105#elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__)
106 0x1e, 0x93, 0x0a, 0
107#elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__)
108 0x1e, 0x94, 0x06, 0
109#elif defined (__AVR_ATmega328P__)
110 0x1e, 0x95, 0x0f, 0
111#else
112# error "Device signature is not known, please edit main.c!"
113#endif
114};
115
116/* ------------------------------------------------------------------------ */
117
118static void (*nullVector)(void) __attribute__((__noreturn__));
119
120static void leaveBootloader()
121{
122#define OBDEBUG 1DBG1(0x01, 0, 0);
123 bootLoaderExit();
124 cli();
125 USB_INTR_ENABLE = 0;
126 USB_INTR_CFG = 0; /* also reset config bits */
127 GICR = (1 << IVCE); /* enable change of interrupt vectors */
128 GICR = (0 << IVSEL); /* move interrupts to application flash section */
129/* We must go through a global function pointer variable instead of writing
130 * ((void (*)(void))0)();
131 * because the compiler optimizes a constant 0 to "rcall 0" which is not
132 * handled correctly by the assembler.
133 */
134 nullVector();
135}
136
137/* ------------------------------------------------------------------------ */
138
139uchar usbFunctionSetup(uchar data[8])
140{
141usbRequest_t *rq = (void *)data;
142uchar len = 0;
143static uchar replyBuffer[4];
144
145 usbMsgPtr = replyBuffer;
146 if(rq->bRequest == USBASP_FUNC_TRANSMIT){ /* emulate parts of ISP protocol */
147 uchar rval = 0;
148 usbWord_t address;
149 address.bytes[1] = rq->wValue.bytes[1];
150 address.bytes[0] = rq->wIndex.bytes[0];
151 if(rq->wValue.bytes[0] == 0x30){ /* read signature */
152 rval = rq->wIndex.bytes[0] & 3;
153 rval = signatureBytes[rval];
154#if HAVE_EEPROM_BYTE_ACCESS
155 }else if(rq->wValue.bytes[0] == 0xa0){ /* read EEPROM byte */
156 rval = eeprom_read_byte((void *)address.word);
157 }else if(rq->wValue.bytes[0] == 0xc0){ /* write EEPROM byte */
158 eeprom_write_byte((void *)address.word, rq->wIndex.bytes[1]);
159#endif
160#if HAVE_CHIP_ERASE
161 }else if(rq->wValue.bytes[0] == 0xac && rq->wValue.bytes[1] == 0x80){ /* chip erase */
162 addr_t addr;
163 for(addr = 0; addr < FLASHEND + 1 - 2048; addr += SPM_PAGESIZE) {
164 /* wait and erase page */
165 //DBG1(0x33, 0, 0);
166# ifndef NO_FLASH_WRITE
167 boot_spm_busy_wait();
168 cli();
169 boot_page_erase(addr);
170 sei();
171# endif
172 }
173#endif
174 }else{
175 /* ignore all others, return default value == 0 */
176 }
177 replyBuffer[3] = rval;
178 len = 4;
179 }else if(rq->bRequest == USBASP_FUNC_ENABLEPROG){
180 /* replyBuffer[0] = 0; is never touched and thus always 0 which means success */
181 len = 1;
182 }else if(rq->bRequest >= USBASP_FUNC_READFLASH && rq->bRequest <= USBASP_FUNC_SETLONGADDRESS){
183 currentAddress.w[0] = rq->wValue.word;
184 if(rq->bRequest == USBASP_FUNC_SETLONGADDRESS){
185#if (FLASHEND) > 0xffff
186 currentAddress.w[1] = rq->wIndex.word;
187#endif
188 }else{
189 bytesRemaining = rq->wLength.bytes[0];
190 /* if(rq->bRequest == USBASP_FUNC_WRITEFLASH) only evaluated during writeFlash anyway */
191 isLastPage = rq->wIndex.bytes[1] & 0x02;
192#if HAVE_EEPROM_PAGED_ACCESS
193 currentRequest = rq->bRequest;
194#endif
195 len = 0xff; /* hand over to usbFunctionRead() / usbFunctionWrite() */
196 }
197#if BOOTLOADER_CAN_EXIT
198 }else if(rq->bRequest == USBASP_FUNC_DISCONNECT){
199 requestBootLoaderExit = 1; /* allow proper shutdown/close of connection */
200#endif
201 }else{
202 /* ignore: USBASP_FUNC_CONNECT */
203 }
204 return len;
205}
206
207uchar usbFunctionWrite(uchar *data, uchar len)
208{
209uchar isLast;
210
211 //DBG1(0x31, (void *)&currentAddress.l, 4);
212 if(len > bytesRemaining)
213 len = bytesRemaining;
214 bytesRemaining -= len;
215 isLast = bytesRemaining == 0;
216 if(currentRequest >= USBASP_FUNC_READEEPROM){
217 uchar i;
218 for(i = 0; i < len; i++){
219 eeprom_write_byte((void *)(currentAddress.w[0]++), *data++);
220 }
221 }else{
222 uchar i;
223 for(i = 0; i < len;){
224#if !HAVE_CHIP_ERASE
225 if((currentAddress.w[0] & (SPM_PAGESIZE - 1)) == 0){ /* if page start: erase */
226 //DBG1(0x33, 0, 0);
227# ifndef NO_FLASH_WRITE
228 cli();
229 boot_page_erase(CURRENT_ADDRESS); /* erase page */
230 sei();
231 boot_spm_busy_wait(); /* wait until page is erased */
232# endif
233 }
234#endif
235 i += 2;
236 //DBG1(0x32, 0, 0);
237 cli();
238 boot_page_fill(CURRENT_ADDRESS, *(short *)data);
239 sei();
240 CURRENT_ADDRESS += 2;
241 data += 2;
242 /* write page when we cross page boundary or we have the last partial page */
243 if((currentAddress.w[0] & (SPM_PAGESIZE - 1)) == 0 || (isLast && i >= len && isLastPage)){
244 //DBG1(0x34, 0, 0);
245#ifndef NO_FLASH_WRITE
246 cli();
247 boot_page_write(CURRENT_ADDRESS - 2);
248 sei();
249 boot_spm_busy_wait();
250 cli();
251 boot_rww_enable();
252 sei();
253#endif
254 }
255 }
256 //DBG1(0x35, (void *)&currentAddress.l, 4);
257 }
258 return isLast;
259}
260
261uchar usbFunctionRead(uchar *data, uchar len)
262{
263uchar i;
264
265 if(len > bytesRemaining)
266 len = bytesRemaining;
267 bytesRemaining -= len;
268 for(i = 0; i < len; i++){
269 if(currentRequest >= USBASP_FUNC_READEEPROM){
270 *data = eeprom_read_byte((void *)currentAddress.w[0]);
271 }else{
272 *data = pgm_read_byte((void *)CURRENT_ADDRESS);
273 }
274 data++;
275 CURRENT_ADDRESS++;
276 }
277 return len;
278}
279
280/* ------------------------------------------------------------------------ */
281
282static void initForUsbConnectivity(void)
283{
284uchar i = 0;
285
286 usbInit();
287 /* enforce USB re-enumerate: */
288#if 0
289 usbDeviceDisconnect(); /* do this while interrupts are disabled */
290 while(--i){ /* fake USB disconnect for > 250 ms */
291 wdt_reset();
292 _delay_ms(1);
293 }
294#endif
295 usbDeviceConnect();
296 sei();
297}
298
299int main(void)
300{
301 /* initialize */
302 wdt_disable(); /* main app may have enabled watchdog */
303 bootLoaderInit();
304 odDebugInit();
305 DBG1(0x00, 0, 0);
306#ifndef NO_FLASH_WRITE
307 GICR = (1 << IVCE); /* enable change of interrupt vectors */
308 GICR = (1 << IVSEL); /* move interrupts to boot flash section */
309#endif
310 if(bootLoaderCondition()){
311#if BOOTLOADER_CAN_EXIT
312 uchar i = 0, j = 0;
313#endif
314 initForUsbConnectivity();
315 do{
316 usbPoll();
317#if BOOTLOADER_CAN_EXIT
318 if(requestBootLoaderExit){
319 if(--i == 0){
320 if(--j == 0)
321 break;
322 }
323 }
324#endif
325 }while(bootLoaderCondition()); /* main event loop */
326 }
327 leaveBootloader();
328 return 0;
329}
330
331/* ------------------------------------------------------------------------ */
Note: See TracBrowser for help on using the repository browser.