Project

General

Profile

Download (26.9 KB) Statistics
| Branch: | Tag: | Revision:
1 43d61cf0 (no author)
/* USB Device Firmware Update Implementation for OpenPCD
2 58d958e6 Harald Welte
 * (C) 2006-2011 by Harald Welte <hwelte@hmw-consulting.de>
3 43d61cf0 (no author)
 *
4
 * This ought to be compliant to the USB DFU Spec 1.0 as available from
5
 * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
6
 *
7 32985a29 laforge
 *  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 43d61cf0 (no author)
 */
22 872a81da (no author)
23 43d61cf0 (no author)
#include <errno.h>
24
#include <usb_ch9.h>
25
#include <usb_dfu.h>
26 569d11d8 laforge
#include <board.h>
27 43d61cf0 (no author)
#include <lib_AT91SAM7.h>
28
29 5872753e laforge
#include <usb_strings_dfu.h>
30
31 a97e460b laforge
#include <dfu/dfu.h>
32 569d11d8 laforge
#include <dfu/dbgu.h>
33 f21e08aa meri
#include <os/flash.h>
34 520784c7 (no author)
#include <os/pcd_enumerate.h>
35
#include "../openpcd.h"
36 43d61cf0 (no author)
37 1c2b1d22 laforge
#include <compile.h>
38
39
#define SAM7DFU_SIZE	0x4000
40 58d958e6 Harald Welte
#define SAM7DFU_RAM_SIZE	0x2000
41 514b0f72 laforge
42 43d61cf0 (no author)
/* If debug is enabled, we need to access debug functions from flash
43
 * and therefore have to omit flashing */
44 cf4d20a6 laforge
//#define DEBUG_DFU_NOFLASH
45 43d61cf0 (no author)
46 6c6b1878 laforge
#ifdef DEBUG
47 cf4d20a6 laforge
#define DEBUG_DFU_EP0
48
//#define DEBUG_DFU_RECV
49 6c6b1878 laforge
#endif
50 43d61cf0 (no author)
51 cf4d20a6 laforge
#ifdef DEBUG_DFU_EP0
52
#define DEBUGE DEBUGP
53
#else
54
#define DEBUGE(x, args ...)
55
#endif
56 569d11d8 laforge
57 cf4d20a6 laforge
#ifdef DEBUG_DFU_RECV
58
#define DEBUGR DEBUGP
59
#else
60
#define DEBUGR(x, args ...)
61
#endif
62 569d11d8 laforge
63 cf4d20a6 laforge
#define RET_NOTHING	0
64
#define RET_ZLP		1
65
#define RET_STALL	2
66 ad18651c (no author)
67 1c2b1d22 laforge
#define led1on()	AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1)
68
#define led1off()	AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1)
69
70
#define led2on()	AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2)
71
#define led2off()	AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2)
72
73 d56bb35e Harald Welte
static int past_manifest = 0;
74 1acaecb4 Harald Welte
static int switch_to_ram = 0; /* IRQ handler requests main to jump to RAM */
75 373c172a Harald Welte
static uint16_t usb_if_nr = 0;	/* last SET_INTERFACE */
76
static uint16_t usb_if_alt_nr = 0; /* last SET_INTERFACE AltSetting */
77
static uint16_t usb_if_alt_nr_dnload = 0; /* AltSetting during last dnload */
78 d56bb35e Harald Welte
79 a97e460b laforge
static void __dfufunc udp_init(void)
80 b0317c72 (no author)
{
81
	/* Set the PLL USB Divider */
82
	AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
83
84
	/* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock */
85
	AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
86
	AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
87
88 514b0f72 laforge
	/* Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the
89
	 * corresponding PIO Set in PIO mode and Configure in Output */
90 6c6b1878 laforge
#if defined(PCD)
91 b0317c72 (no author)
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP);
92 6c6b1878 laforge
#endif
93 d1dd3611 laforge
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUPv4);
94 b0317c72 (no author)
}
95
96 fe88b83e Harald Welte
static void __dfufunc udp_ep0_send_zlp(void);
97
98 b0317c72 (no author)
/* Send Data through the control endpoint */
99 373c172a Harald Welte
static void __dfufunc udp_ep0_send_data(const char *pData, uint32_t length,
100
					uint32_t window_length)
101 b0317c72 (no author)
{
102
	AT91PS_UDP pUdp = AT91C_BASE_UDP;
103 373c172a Harald Welte
	uint32_t cpt = 0, len_remain;
104 b0317c72 (no author)
	AT91_REG csr;
105
106 ebf16b4d Holger Hans Peter Freyther
	len_remain = MIN(length, window_length);
107
	DEBUGE("send_data: %u/%u bytes ", length, window_length);
108 b0317c72 (no author)
109
	do {
110 fe88b83e Harald Welte
		cpt = MIN(len_remain, 8);
111
		len_remain -= cpt;
112 b0317c72 (no author)
113
		while (cpt--)
114
			pUdp->UDP_FDR[0] = *pData++;
115
116
		if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) {
117
			pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP);
118
			while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ;
119
		}
120
121
		pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY;
122
		do {
123
			csr = pUdp->UDP_CSR[0];
124
125
			/* Data IN stage has been stopped by a status OUT */
126
			if (csr & AT91C_UDP_RX_DATA_BK0) {
127
				pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0);
128
				DEBUGE("stopped by status out ");
129
				return;
130
			}
131
		} while (!(csr & AT91C_UDP_TXCOMP));
132
133 fe88b83e Harald Welte
	} while (len_remain);
134 b0317c72 (no author)
135
	if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) {
136
		pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP);
137
		while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ;
138
	}
139 fe88b83e Harald Welte
140 ebf16b4d Holger Hans Peter Freyther
	if ((length % 8) == 0 && length < window_length) {
141 fe88b83e Harald Welte
		/* if the length is a multiple of the EP size, we need
142
		 * to send another ZLP (zero-length packet) to tell the
143
		 * host the transfer has completed.  */
144
		DEBUGE("set_txpktrdy_zlp ");
145
		udp_ep0_send_zlp();
146
	}
147 b0317c72 (no author)
}
148
149 569d11d8 laforge
/* receive data from EP0 */
150 373c172a Harald Welte
static int __dfufunc udp_ep0_recv_data(uint8_t *data, uint16_t len)
151 569d11d8 laforge
{
152
	AT91PS_UDP pUdp = AT91C_BASE_UDP;
153 26bc6a68 laforge
	AT91_REG csr;
154 373c172a Harald Welte
	uint16_t i, num_rcv;
155
	uint32_t num_rcv_total = 0;
156 569d11d8 laforge
157
	do {
158
		/* FIXME: do we need to check whether we've been interrupted
159
		 * by a RX SETUP stage? */
160 26bc6a68 laforge
		do {
161
			csr = pUdp->UDP_CSR[0];
162 cf4d20a6 laforge
			DEBUGR("CSR=%08x ", csr);
163 26bc6a68 laforge
		} while (!(csr & AT91C_UDP_RX_DATA_BK0)) ;
164 569d11d8 laforge
	
165
		num_rcv = pUdp->UDP_CSR[0] >> 16;
166 26bc6a68 laforge
167
		/* make sure we don't read more than requested */
168
		if (num_rcv_total + num_rcv > len)
169
			num_rcv = num_rcv_total - len;
170
171 cf4d20a6 laforge
		DEBUGR("num_rcv = %u ", num_rcv);
172 569d11d8 laforge
		for (i = 0; i < num_rcv; i++)
173
			*data++ = pUdp->UDP_FDR[0];
174
		pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0);
175
176
		num_rcv_total += num_rcv;
177
178
		/* we need to continue to pull data until we either receive 
179
		 * a packet < endpoint size or == 0 */
180 26bc6a68 laforge
	} while (num_rcv == 8 && num_rcv_total < len);
181
182
	DEBUGE("ep0_rcv_returning(%u total) ", num_rcv_total);
183 569d11d8 laforge
184
	return num_rcv_total;
185
}
186
187 b0317c72 (no author)
/* Send zero length packet through the control endpoint */
188
static void __dfufunc udp_ep0_send_zlp(void)
189
{
190
	AT91PS_UDP pUdp = AT91C_BASE_UDP;
191
	pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY;
192
	while (!(pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP)) ;
193
	pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP);
194
	while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ;
195
}
196
197
/* Stall the control endpoint */
198
static void __dfufunc udp_ep0_send_stall(void)
199
{
200
	AT91PS_UDP pUdp = AT91C_BASE_UDP;
201
	pUdp->UDP_CSR[0] |= AT91C_UDP_FORCESTALL;
202
	while (!(pUdp->UDP_CSR[0] & AT91C_UDP_ISOERROR)) ;
203
	pUdp->UDP_CSR[0] &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);
204
	while (pUdp->UDP_CSR[0] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)) ;
205
}
206
207
208 58d958e6 Harald Welte
static int first_download = 1;
209 373c172a Harald Welte
static uint8_t *ptr, *ptr_max;
210
static __dfudata uint8_t dfu_status;
211
__dfudata uint32_t dfu_state = DFU_STATE_appIDLE;
212
static uint32_t pagebuf32[AT91C_IFLASH_PAGE_SIZE/4];
213 569d11d8 laforge
214 58d958e6 Harald Welte
static void chk_first_dnload_set_ptr(void)
215
{
216
	if (!first_download)
217
		return;
218
219
	switch (usb_if_alt_nr) {
220
	case 0:
221 373c172a Harald Welte
		ptr = (uint8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
222 58d958e6 Harald Welte
		ptr_max = AT91C_IFLASH + AT91C_IFLASH_SIZE - ENVIRONMENT_SIZE;
223
		break;
224
	case 1:
225 373c172a Harald Welte
		ptr = (uint8_t *) AT91C_IFLASH;
226 58d958e6 Harald Welte
		ptr_max = AT91C_IFLASH + SAM7DFU_SIZE;
227
		break;
228
	case 2:
229 373c172a Harald Welte
		ptr = (uint8_t *) AT91C_ISRAM + SAM7DFU_RAM_SIZE;
230 58d958e6 Harald Welte
		ptr_max = AT91C_ISRAM + AT91C_ISRAM_SIZE;
231
		break;
232
	}
233
	first_download = 0;
234
}
235
236 373c172a Harald Welte
static int __dfufunc handle_dnload_flash(uint16_t __unused val, uint16_t len)
237 43d61cf0 (no author)
{
238 373c172a Harald Welte
	volatile uint32_t *p;
239
	uint8_t *pagebuf = (uint8_t *) pagebuf32;
240 cf4d20a6 laforge
	int i;
241 43d61cf0 (no author)
242
	DEBUGE("download ");
243
244
	if (len > AT91C_IFLASH_PAGE_SIZE) {
245 514b0f72 laforge
		/* Too big. Not that we'd really care, but it's a
246
		 * DFU protocol violation */
247 cf4d20a6 laforge
		DEBUGP("length exceeds flash page size ");
248 43d61cf0 (no author)
	    	dfu_state = DFU_STATE_dfuERROR;
249 1c2b1d22 laforge
		dfu_status = DFU_STATUS_errADDRESS;
250 cf4d20a6 laforge
		return RET_STALL;
251 43d61cf0 (no author)
	}
252
	if (len & 0x3) {
253 569d11d8 laforge
		/* reject non-four-byte-aligned writes */
254 cf4d20a6 laforge
		DEBUGP("not four-byte-aligned length ");
255 43d61cf0 (no author)
		dfu_state = DFU_STATE_dfuERROR;
256 1c2b1d22 laforge
		dfu_status = DFU_STATUS_errADDRESS;
257 cf4d20a6 laforge
		return RET_STALL;
258 43d61cf0 (no author)
	}
259 58d958e6 Harald Welte
	chk_first_dnload_set_ptr();
260 373c172a Harald Welte
	p = (volatile uint32_t *)ptr;
261 58d958e6 Harald Welte
262 43d61cf0 (no author)
	if (len == 0) {
263 cf4d20a6 laforge
		DEBUGP("zero-size write -> MANIFEST_SYNC ");
264 58d958e6 Harald Welte
		if (((unsigned long)p % AT91C_IFLASH_PAGE_SIZE) != 0)
265
			flash_page(p);
266 43d61cf0 (no author)
		dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
267 58d958e6 Harald Welte
		first_download = 1;
268 cf4d20a6 laforge
		return RET_ZLP;
269 43d61cf0 (no author)
	}
270 58d958e6 Harald Welte
271
	/* check if we would exceed end of memory */
272
	if (ptr + len > ptr_max) {
273 cf4d20a6 laforge
		DEBUGP("end of write exceeds flash end ");
274 514b0f72 laforge
		dfu_state = DFU_STATE_dfuERROR;
275 1c2b1d22 laforge
		dfu_status = DFU_STATUS_errADDRESS;
276 cf4d20a6 laforge
		return RET_STALL;
277 514b0f72 laforge
	}
278 569d11d8 laforge
279 cf4d20a6 laforge
	DEBUGP("try_to_recv=%u ", len);
280
	udp_ep0_recv_data(pagebuf, len);
281 569d11d8 laforge
282 cf4d20a6 laforge
	DEBUGR(hexdump(pagebuf, len));
283 569d11d8 laforge
284 cf4d20a6 laforge
#ifndef DEBUG_DFU_NOFLASH
285
	DEBUGP("copying ");
286 58d958e6 Harald Welte
	/* we can only access the write buffer with correctly aligned
287
	 * 32bit writes ! */
288 26bc6a68 laforge
	for (i = 0; i < len/4; i++) {
289 cf4d20a6 laforge
		*p++ = pagebuf32[i];
290 26bc6a68 laforge
		/* If we have filled a page buffer, flash it */
291 cf4d20a6 laforge
		if (((unsigned long)p % AT91C_IFLASH_PAGE_SIZE) == 0) {
292
			DEBUGP("page_full  ");
293
			flash_page(p-1);
294
		}
295 26bc6a68 laforge
	}
296 373c172a Harald Welte
	ptr = (uint8_t *) p;
297 43d61cf0 (no author)
#endif
298
299 cf4d20a6 laforge
	return RET_ZLP;
300 43d61cf0 (no author)
}
301
302 373c172a Harald Welte
static int __dfufunc handle_dnload_ram(uint16_t __unused val, uint16_t len)
303 58d958e6 Harald Welte
{
304
	DEBUGE("download ");
305
306
	if (len > AT91C_IFLASH_PAGE_SIZE) {
307
		/* Too big. Not that we'd really care, but it's a
308
		 * DFU protocol violation */
309
		DEBUGP("length exceeds flash page size ");
310
		dfu_state = DFU_STATE_dfuERROR;
311
		dfu_status = DFU_STATUS_errADDRESS;
312
		return RET_STALL;
313
	}
314
	chk_first_dnload_set_ptr();
315
316
	if (len == 0) {
317
		DEBUGP("zero-size write -> MANIFEST_SYNC ");
318
		dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
319
		first_download = 1;
320
		return RET_ZLP;
321
	}
322
323
	/* check if we would exceed end of memory */
324
	if (ptr + len >= ptr_max) {
325
		DEBUGP("end of write exceeds RAM end ");
326
		dfu_state = DFU_STATE_dfuERROR;
327
		dfu_status = DFU_STATUS_errADDRESS;
328
		return RET_STALL;
329
	}
330
331
	/* drectly copy into RAM */
332
	DEBUGP("try_to_recv=%u ", len);
333
	udp_ep0_recv_data(ptr, len);
334
335
	DEBUGR(hexdump(ptr, len));
336
337
	ptr += len;
338
339
	return RET_ZLP;
340
}
341
342 373c172a Harald Welte
static int __dfufunc handle_dnload(uint16_t val, uint16_t len)
343 58d958e6 Harald Welte
{
344 1acaecb4 Harald Welte
	usb_if_alt_nr_dnload = usb_if_alt_nr;
345 58d958e6 Harald Welte
	switch (usb_if_alt_nr) {
346
	case 2:
347
		return handle_dnload_ram(val, len);
348
	default:
349
		return handle_dnload_flash(val, len);
350
	}
351
}
352
353 373c172a Harald Welte
#define AT91C_IFLASH_END ((uint8_t *)AT91C_IFLASH + AT91C_IFLASH_SIZE)
354
static __dfufunc int handle_upload(uint16_t __unused val, uint16_t len)
355 43d61cf0 (no author)
{
356
	DEBUGE("upload ");
357 cf4d20a6 laforge
	if (len > AT91C_IFLASH_PAGE_SIZE) {
358 43d61cf0 (no author)
		/* Too big */
359
		dfu_state = DFU_STATE_dfuERROR;
360 1c2b1d22 laforge
		dfu_status = DFU_STATUS_errADDRESS;
361 43d61cf0 (no author)
		udp_ep0_send_stall();
362
		return -EINVAL;
363
	}
364 58d958e6 Harald Welte
	chk_first_dnload_set_ptr();
365 43d61cf0 (no author)
366 58d958e6 Harald Welte
	if (ptr + len > AT91C_IFLASH_END) {
367 373c172a Harald Welte
		len = AT91C_IFLASH_END - (uint8_t *)ptr;
368 58d958e6 Harald Welte
		first_download = 1;
369
	}
370 cf4d20a6 laforge
371 ebf16b4d Holger Hans Peter Freyther
	udp_ep0_send_data((char *)ptr, len, len);
372 43d61cf0 (no author)
	ptr+= len;
373
374
	return len;
375
}
376
377 b0317c72 (no author)
static __dfufunc void handle_getstatus(void)
378 43d61cf0 (no author)
{
379
	struct dfu_status dstat;
380 373c172a Harald Welte
	uint32_t fsr = AT91F_MC_EFC_GetStatus(AT91C_BASE_MC);
381 43d61cf0 (no author)
382 cf4d20a6 laforge
	DEBUGE("getstatus(fsr=0x%08x) ", fsr);
383 43d61cf0 (no author)
384 569d11d8 laforge
	switch (dfu_state) {
385
	case DFU_STATE_dfuDNLOAD_SYNC:
386
	case DFU_STATE_dfuDNBUSY:
387
		if (fsr & AT91C_MC_PROGE) {
388 cf4d20a6 laforge
			DEBUGE("errPROG ");
389 1c2b1d22 laforge
			dfu_status = DFU_STATUS_errPROG;
390 569d11d8 laforge
			dfu_state = DFU_STATE_dfuERROR;
391
		} else if (fsr & AT91C_MC_LOCKE) {
392 cf4d20a6 laforge
			DEBUGE("errWRITE ");
393 1c2b1d22 laforge
			dfu_status = DFU_STATUS_errWRITE;
394 569d11d8 laforge
			dfu_state = DFU_STATE_dfuERROR;
395 cf4d20a6 laforge
		} else if (fsr & AT91C_MC_FRDY) {
396
			DEBUGE("DNLOAD_IDLE ");
397 569d11d8 laforge
			dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
398 cf4d20a6 laforge
		} else {
399
			DEBUGE("DNBUSY ");
400 569d11d8 laforge
			dfu_state = DFU_STATE_dfuDNBUSY;
401 cf4d20a6 laforge
		}
402 569d11d8 laforge
		break;
403
	case DFU_STATE_dfuMANIFEST_SYNC:
404
		dfu_state = DFU_STATE_dfuMANIFEST;
405
		break;
406
	}
407
408 43d61cf0 (no author)
	/* send status response */
409 1c2b1d22 laforge
	dstat.bStatus = dfu_status;
410 43d61cf0 (no author)
	dstat.bState = dfu_state;
411
	dstat.iString = 0;
412 514b0f72 laforge
	/* FIXME: set dstat.bwPollTimeout */
413 569d11d8 laforge
414 ebf16b4d Holger Hans Peter Freyther
	udp_ep0_send_data((char *)&dstat, sizeof(dstat), sizeof(dstat));
415 43d61cf0 (no author)
}
416
417 b0317c72 (no author)
static void __dfufunc handle_getstate(void)
418 43d61cf0 (no author)
{
419 373c172a Harald Welte
	uint8_t u8 = dfu_state;
420 43d61cf0 (no author)
	DEBUGE("getstate ");
421 569d11d8 laforge
422 ebf16b4d Holger Hans Peter Freyther
	udp_ep0_send_data((char *)&u8, sizeof(u8), sizeof(u8));
423 43d61cf0 (no author)
}
424
425
/* callback function for DFU requests */
426 373c172a Harald Welte
int __dfufunc dfu_ep0_handler(uint8_t __unused req_type, uint8_t req,
427
		    uint16_t val, uint16_t len)
428 43d61cf0 (no author)
{
429 cf4d20a6 laforge
	int rc, ret = RET_NOTHING;
430 43d61cf0 (no author)
431
	DEBUGE("old_state = %u ", dfu_state);
432
433
	switch (dfu_state) {
434
	case DFU_STATE_appIDLE:
435 1c2b1d22 laforge
		switch (req) {
436
		case USB_REQ_DFU_GETSTATUS:
437
			handle_getstatus();
438
			break;
439
		case USB_REQ_DFU_GETSTATE:
440
			handle_getstate();
441
			break;
442
		case USB_REQ_DFU_DETACH:
443
			dfu_state = DFU_STATE_appDETACH;
444
			ret = RET_ZLP;
445 cf4d20a6 laforge
			goto out;
446 1c2b1d22 laforge
			break;
447
		default:
448
			ret = RET_STALL;
449 cf4d20a6 laforge
		}
450 43d61cf0 (no author)
		break;
451
	case DFU_STATE_appDETACH:
452
		switch (req) {
453
		case USB_REQ_DFU_GETSTATUS:
454
			handle_getstatus();
455
			break;
456
		case USB_REQ_DFU_GETSTATE:
457
			handle_getstate();
458
			break;
459
		default:
460
			dfu_state = DFU_STATE_appIDLE;
461 cf4d20a6 laforge
			ret = RET_STALL;
462
			goto out;
463 43d61cf0 (no author)
			break;
464
		}
465
		/* FIXME: implement timer to return to appIDLE */
466
		break;
467
	case DFU_STATE_dfuIDLE:
468
		switch (req) {
469
		case USB_REQ_DFU_DNLOAD:
470
			if (len == 0) {
471
				dfu_state = DFU_STATE_dfuERROR;
472 cf4d20a6 laforge
				ret = RET_STALL;
473
				goto out;
474 43d61cf0 (no author)
			}
475 460ece83 laforge
			dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
476 373c172a Harald Welte
			ptr = (uint8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
477 cf4d20a6 laforge
			ret = handle_dnload(val, len);
478 43d61cf0 (no author)
			break;
479
		case USB_REQ_DFU_UPLOAD:
480 373c172a Harald Welte
			ptr = (uint8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
481 43d61cf0 (no author)
			dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
482
			handle_upload(val, len);
483
			break;
484
		case USB_REQ_DFU_ABORT:
485
			/* no zlp? */
486 cf4d20a6 laforge
			ret = RET_ZLP;
487 43d61cf0 (no author)
			break;
488
		case USB_REQ_DFU_GETSTATUS:
489
			handle_getstatus();
490
			break;
491
		case USB_REQ_DFU_GETSTATE:
492
			handle_getstate();
493
			break;
494
		default:
495
			dfu_state = DFU_STATE_dfuERROR;
496 cf4d20a6 laforge
			ret = RET_STALL;
497
			goto out;
498 43d61cf0 (no author)
			break;
499
		}
500
		break;
501
	case DFU_STATE_dfuDNLOAD_SYNC:
502
		switch (req) {
503
		case USB_REQ_DFU_GETSTATUS:
504
			handle_getstatus();
505
			/* FIXME: state transition depending on block completeness */
506
			break;
507
		case USB_REQ_DFU_GETSTATE:
508
			handle_getstate();
509
			break;
510
		default:
511
			dfu_state = DFU_STATE_dfuERROR;
512 cf4d20a6 laforge
			ret = RET_STALL;
513
			goto out;
514 43d61cf0 (no author)
		}
515
		break;
516
	case DFU_STATE_dfuDNBUSY:
517 cf4d20a6 laforge
		switch (req) {
518
		case USB_REQ_DFU_GETSTATUS:
519
			/* FIXME: only accept getstatus if bwPollTimeout
520
			 * has elapsed */
521
			handle_getstatus();
522
			break;
523
		default:
524
			dfu_state = DFU_STATE_dfuERROR;
525
			ret = RET_STALL;
526
			goto out;
527
		}
528 43d61cf0 (no author)
		break;
529
	case DFU_STATE_dfuDNLOAD_IDLE:
530
		switch (req) {
531
		case USB_REQ_DFU_DNLOAD:
532 cf4d20a6 laforge
			dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
533 460ece83 laforge
			ret = handle_dnload(val, len);
534 43d61cf0 (no author)
			break;
535
		case USB_REQ_DFU_ABORT:
536
			dfu_state = DFU_STATE_dfuIDLE;
537 cf4d20a6 laforge
			ret = RET_ZLP;
538 43d61cf0 (no author)
			break;
539
		case USB_REQ_DFU_GETSTATUS:
540
			handle_getstatus();
541
			break;
542
		case USB_REQ_DFU_GETSTATE:
543
			handle_getstate();
544
			break;
545
		default:
546
			dfu_state = DFU_STATE_dfuERROR;
547 cf4d20a6 laforge
			ret = RET_STALL;
548 43d61cf0 (no author)
			break;
549
		}
550
		break;
551
	case DFU_STATE_dfuMANIFEST_SYNC:
552
		switch (req) {
553
		case USB_REQ_DFU_GETSTATUS:
554 569d11d8 laforge
			handle_getstatus();
555 43d61cf0 (no author)
			break;
556
		case USB_REQ_DFU_GETSTATE:
557
			handle_getstate();
558
			break;
559
		default:
560
			dfu_state = DFU_STATE_dfuERROR;
561 cf4d20a6 laforge
			ret = RET_STALL;
562 43d61cf0 (no author)
			break;
563
		}
564
		break;
565
	case DFU_STATE_dfuMANIFEST:
566 dde2f8e0 laforge
		switch (req) {
567
		case USB_REQ_DFU_GETSTATUS:
568 d56bb35e Harald Welte
			/* we don't want to change to WAIT_RST, as it
569
			 * would mean that we can not support another
570
			 * DFU transaction before doing the actual
571
			 * reset.  Instead, we switch to idle and note
572
			 * that we've already been through MANIFST in
573
			 * the global variable 'past_manifest'.
574
			 */
575
			//dfu_state = DFU_STATE_dfuMANIFEST_WAIT_RST;
576 dde2f8e0 laforge
			dfu_state = DFU_STATE_dfuIDLE;
577 d56bb35e Harald Welte
			past_manifest = 1;
578 dde2f8e0 laforge
			handle_getstatus();
579
			break;
580
		case USB_REQ_DFU_GETSTATE:
581
			handle_getstate();
582
			break;
583
		default:
584
			dfu_state = DFU_STATE_dfuERROR;
585
			ret = RET_STALL;
586
			break;
587
		}
588 43d61cf0 (no author)
		break;
589
	case DFU_STATE_dfuMANIFEST_WAIT_RST:
590
		/* we should never go here */
591
		break;
592
	case DFU_STATE_dfuUPLOAD_IDLE:
593
		switch (req) {
594
		case USB_REQ_DFU_UPLOAD:
595
			/* state transition if less data then requested */
596
			rc = handle_upload(val, len);
597
			if (rc >= 0 && rc < len)
598
				dfu_state = DFU_STATE_dfuIDLE;
599
			break;
600
		case USB_REQ_DFU_ABORT:
601
			dfu_state = DFU_STATE_dfuIDLE;
602
			/* no zlp? */
603 cf4d20a6 laforge
			ret = RET_ZLP;
604 43d61cf0 (no author)
			break;
605
		case USB_REQ_DFU_GETSTATUS:
606
			handle_getstatus();
607
			break;
608
		case USB_REQ_DFU_GETSTATE:
609
			handle_getstate();
610
			break;
611
		default:
612
			dfu_state = DFU_STATE_dfuERROR;
613 cf4d20a6 laforge
			ret = RET_STALL;
614 43d61cf0 (no author)
			break;
615
		}
616
		break;
617
	case DFU_STATE_dfuERROR:
618
		switch (req) {
619
		case USB_REQ_DFU_GETSTATUS:
620
			handle_getstatus();
621
			break;
622
		case USB_REQ_DFU_GETSTATE:
623
			handle_getstate();
624
			break;
625
		case USB_REQ_DFU_CLRSTATUS:
626
			dfu_state = DFU_STATE_dfuIDLE;
627 1c2b1d22 laforge
			dfu_status = DFU_STATUS_OK;
628 43d61cf0 (no author)
			/* no zlp? */
629 cf4d20a6 laforge
			ret = RET_ZLP;
630 43d61cf0 (no author)
			break;
631
		default:
632
			dfu_state = DFU_STATE_dfuERROR;
633 cf4d20a6 laforge
			ret = RET_STALL;
634 43d61cf0 (no author)
			break;
635
		}
636
		break;
637
	}
638
639 cf4d20a6 laforge
out:
640
	DEBUGE("new_state = %u\r\n", dfu_state);
641 43d61cf0 (no author)
642 cf4d20a6 laforge
	switch (ret) {
643
	case RET_NOTHING:
644
		break;
645
	case RET_ZLP:
646
		udp_ep0_send_zlp();
647
		break;
648
	case RET_STALL:
649
		udp_ep0_send_stall();
650
		break;
651
	}
652 43d61cf0 (no author)
	return 0;
653
}
654 cf4d20a6 laforge
655 373c172a Harald Welte
static uint8_t cur_config;
656 872a81da (no author)
657
/* USB DFU Device descriptor in DFU mode */
658 83c18361 (no author)
__dfustruct const struct usb_device_descriptor dfu_dev_descriptor = {
659 872a81da (no author)
	.bLength		= USB_DT_DEVICE_SIZE,
660
	.bDescriptorType	= USB_DT_DEVICE,
661
	.bcdUSB			= 0x0100,
662
	.bDeviceClass		= 0x00,
663
	.bDeviceSubClass	= 0x00,
664
	.bDeviceProtocol	= 0x00,
665
	.bMaxPacketSize0	= 8,
666 5872753e laforge
	.idVendor		= USB_VENDOR_ID,
667
	.idProduct		= USB_PRODUCT_ID,
668 872a81da (no author)
	.bcdDevice		= 0x0000,
669 dde2f8e0 laforge
#ifdef CONFIG_USB_STRING
670 5872753e laforge
	.iManufacturer		= 1,
671
	.iProduct		= 2,
672 dde2f8e0 laforge
#else
673
	.iManufacturer		= 0,
674
	.iProduct		= 0,
675
#endif
676 43d61cf0 (no author)
	.iSerialNumber		= 0x00,
677 872a81da (no author)
	.bNumConfigurations	= 0x01,
678
};
679
680 43d61cf0 (no author)
/* USB DFU Config descriptor in DFU mode */
681 83c18361 (no author)
__dfustruct const struct _dfu_desc dfu_cfg_descriptor = {
682 43d61cf0 (no author)
	.ucfg = {
683
		.bLength = USB_DT_CONFIG_SIZE,
684
		.bDescriptorType = USB_DT_CONFIG,
685
		.wTotalLength = USB_DT_CONFIG_SIZE + 
686 58d958e6 Harald Welte
				3* USB_DT_INTERFACE_SIZE +
687 43d61cf0 (no author)
				USB_DT_DFU_SIZE,
688
		.bNumInterfaces = 1,
689
		.bConfigurationValue = 1,
690 28eb4a57 laforge
#ifdef CONFIG_USB_STRING
691 5872753e laforge
		.iConfiguration = 3,
692 28eb4a57 laforge
#else
693
		.iConfiguration = 0,
694
#endif
695 43d61cf0 (no author)
		.bmAttributes = USB_CONFIG_ATT_ONE,
696
		.bMaxPower = 100,
697
		},
698
	.uif[0] = {
699
		.bLength		= USB_DT_INTERFACE_SIZE,
700
		.bDescriptorType	= USB_DT_INTERFACE,
701
		.bInterfaceNumber	= 0x00,
702
		.bAlternateSetting	= 0x00,
703
		.bNumEndpoints		= 0x00,
704
		.bInterfaceClass	= 0xfe,
705
		.bInterfaceSubClass	= 0x01,
706
		.bInterfaceProtocol	= 0x02,
707 28eb4a57 laforge
#ifdef CONFIG_USB_STRING
708 5872753e laforge
		.iInterface		= 4,
709 28eb4a57 laforge
#else
710
		.iInterface		= 0,
711
#endif
712 43d61cf0 (no author)
		}, 
713
	.uif[1] = {
714
		.bLength		= USB_DT_INTERFACE_SIZE,
715
		.bDescriptorType	= USB_DT_INTERFACE,
716
		.bInterfaceNumber	= 0x00,
717
		.bAlternateSetting	= 0x01,
718
		.bNumEndpoints		= 0x00,
719
		.bInterfaceClass	= 0xfe,
720
		.bInterfaceSubClass	= 0x01,
721
		.bInterfaceProtocol	= 0x02,
722 28eb4a57 laforge
#ifdef CONFIG_USB_STRING
723 5872753e laforge
		.iInterface		= 5,
724 28eb4a57 laforge
#else
725
		.iInterface		= 0,
726
#endif
727 43d61cf0 (no author)
		}, 
728 58d958e6 Harald Welte
	.uif[2] = {
729
		.bLength		= USB_DT_INTERFACE_SIZE,
730
		.bDescriptorType	= USB_DT_INTERFACE,
731
		.bInterfaceNumber	= 0x00,
732
		.bAlternateSetting	= 0x02,
733
		.bNumEndpoints		= 0x00,
734
		.bInterfaceClass	= 0xfe,
735
		.bInterfaceSubClass	= 0x01,
736
		.bInterfaceProtocol	= 0x02,
737
#ifdef CONFIG_USB_STRING
738
		.iInterface		= 6,
739
#else
740
		.iInterface		= 0,
741
#endif
742
		},
743 43d61cf0 (no author)
744
	.func_dfu = DFU_FUNC_DESC,
745 872a81da (no author)
};
746
747
748 43d61cf0 (no author)
/* minimal USB EP0 handler in DFU mode */
749 b0317c72 (no author)
static __dfufunc void dfu_udp_ep0_handler(void)
750 872a81da (no author)
{
751 43d61cf0 (no author)
	AT91PS_UDP pUDP = AT91C_BASE_UDP;
752 373c172a Harald Welte
	uint8_t bmRequestType, bRequest;
753
	uint16_t wValue, wIndex, wLength, wStatus;
754
	uint32_t csr = pUDP->UDP_CSR[0];
755 43d61cf0 (no author)
756
	DEBUGE("CSR=0x%04x ", csr);
757
758
	if (csr & AT91C_UDP_STALLSENT) {
759
		DEBUGE("ACK_STALLSENT ");
760
		pUDP->UDP_CSR[0] = ~AT91C_UDP_STALLSENT;
761
	}
762
763
	if (csr & AT91C_UDP_RX_DATA_BK0) {
764
		DEBUGE("ACK_BANK0 ");
765
		pUDP->UDP_CSR[0] &= ~AT91C_UDP_RX_DATA_BK0;
766
	}
767
768
	if (!(csr & AT91C_UDP_RXSETUP)) {
769 cf4d20a6 laforge
		DEBUGE("no setup packet\r\n");
770 43d61cf0 (no author)
		return;
771
	}
772
773
	DEBUGE("len=%d ", csr >> 16);
774
	if (csr >> 16  == 0) {
775 cf4d20a6 laforge
		DEBUGE("empty packet\r\n");
776 43d61cf0 (no author)
		return;
777
	}
778
779
	bmRequestType = pUDP->UDP_FDR[0];
780
	bRequest = pUDP->UDP_FDR[0];
781
	wValue = (pUDP->UDP_FDR[0] & 0xFF);
782
	wValue |= (pUDP->UDP_FDR[0] << 8);
783
	wIndex = (pUDP->UDP_FDR[0] & 0xFF);
784
	wIndex |= (pUDP->UDP_FDR[0] << 8);
785
	wLength = (pUDP->UDP_FDR[0] & 0xFF);
786
	wLength |= (pUDP->UDP_FDR[0] << 8);
787
788
	DEBUGE("bmRequestType=0x%2x ", bmRequestType);
789
790
	if (bmRequestType & 0x80) {
791
		DEBUGE("DATA_IN=1 ");
792
		pUDP->UDP_CSR[0] |= AT91C_UDP_DIR;
793
		while (!(pUDP->UDP_CSR[0] & AT91C_UDP_DIR)) ;
794 872a81da (no author)
	}
795 43d61cf0 (no author)
	pUDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP;
796
	while ((pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) ;
797
798
	/* Handle supported standard device request Cf Table 9-3 in USB
799
	 * speciication Rev 1.1 */
800
	switch ((bRequest << 8) | bmRequestType) {
801 373c172a Harald Welte
		uint8_t desc_type, desc_index;
802 43d61cf0 (no author)
	case STD_GET_DESCRIPTOR:
803
		DEBUGE("GET_DESCRIPTOR ");
804 5872753e laforge
		desc_type = wValue >> 8;
805
		desc_index = wValue & 0xff;
806
		switch (desc_type) {
807
		case USB_DT_DEVICE:
808 43d61cf0 (no author)
			/* Return Device Descriptor */
809
			udp_ep0_send_data((const char *) 
810
					  &dfu_dev_descriptor,
811 ebf16b4d Holger Hans Peter Freyther
					  sizeof(dfu_dev_descriptor), wLength);
812 5872753e laforge
			break;
813
		case USB_DT_CONFIG:
814 43d61cf0 (no author)
			/* Return Configuration Descriptor */
815
			udp_ep0_send_data((const char *)
816
					  &dfu_cfg_descriptor,
817 ebf16b4d Holger Hans Peter Freyther
					  sizeof(dfu_cfg_descriptor), wLength);
818 5872753e laforge
			break;
819
		case USB_DT_STRING:
820
			/* Return String Descriptor */
821
			if (desc_index > ARRAY_SIZE(usb_strings)) {
822 43d61cf0 (no author)
				udp_ep0_send_stall();
823 5872753e laforge
				break;
824
			}
825 89c40594 laforge
			DEBUGE("bLength=%u, wLength=%u ", 
826 5872753e laforge
				usb_strings[desc_index]->bLength, wLength);
827
			udp_ep0_send_data((const char *) usb_strings[desc_index],
828 ebf16b4d Holger Hans Peter Freyther
					  usb_strings[desc_index]->bLength, wLength);
829 5872753e laforge
			break;
830
		case USB_DT_CS_DEVICE:
831 569d11d8 laforge
			/* Return Function descriptor */
832
			udp_ep0_send_data((const char *) &dfu_cfg_descriptor.func_dfu,
833 ebf16b4d Holger Hans Peter Freyther
					  sizeof(dfu_cfg_descriptor.func_dfu), wLength);
834 5872753e laforge
			break;
835
		default:
836 43d61cf0 (no author)
			udp_ep0_send_stall();
837 5872753e laforge
			break;
838
		}
839 43d61cf0 (no author)
		break;
840
	case STD_SET_ADDRESS:
841
		DEBUGE("SET_ADDRESS ");
842
		udp_ep0_send_zlp();
843
		pUDP->UDP_FADDR = (AT91C_UDP_FEN | wValue);
844
		pUDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;
845
		break;
846
	case STD_SET_CONFIGURATION:
847
		DEBUGE("SET_CONFIG ");
848 7db9f66c Holger Hans Peter Freyther
		if (wValue) {
849 43d61cf0 (no author)
			DEBUGE("VALUE!=0 ");
850 7db9f66c Holger Hans Peter Freyther
		}
851
	
852 43d61cf0 (no author)
		cur_config = wValue;
853
		udp_ep0_send_zlp();
854
		pUDP->UDP_GLBSTATE =
855
		    (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;
856
		pUDP->UDP_CSR[1] =
857
		    (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) :
858
		    0;
859
		pUDP->UDP_CSR[2] =
860
		    (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;
861
		pUDP->UDP_CSR[3] =
862
		    (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;
863
		pUDP->UDP_IER = (AT91C_UDP_EPINT0|AT91C_UDP_EPINT1|
864
				 AT91C_UDP_EPINT2|AT91C_UDP_EPINT3);
865
		break;
866
	case STD_GET_CONFIGURATION:
867
		DEBUGE("GET_CONFIG ");
868 ebf16b4d Holger Hans Peter Freyther
		/* Table 9.4 wLength One */
869
		udp_ep0_send_data((char *)&(cur_config), sizeof(cur_config), 1);
870 43d61cf0 (no author)
		break;
871
	case STD_GET_STATUS_ZERO:
872
		DEBUGE("GET_STATUS_ZERO ");
873
		wStatus = 0;
874 ebf16b4d Holger Hans Peter Freyther
		/* Table 9.4 wLength Two */
875
		udp_ep0_send_data((char *)&wStatus, sizeof(wStatus), 2);
876 43d61cf0 (no author)
		break;
877
	case STD_GET_STATUS_INTERFACE:
878
		DEBUGE("GET_STATUS_INTERFACE ");
879
		wStatus = 0;
880 ebf16b4d Holger Hans Peter Freyther
		/* Table 9.4 wLength Two */
881
		udp_ep0_send_data((char *)&wStatus, sizeof(wStatus), 2);
882 43d61cf0 (no author)
		break;
883
	case STD_GET_STATUS_ENDPOINT:
884
		DEBUGE("GET_STATUS_ENDPOINT(EPidx=%u) ", wIndex&0x0f);
885
		wStatus = 0;
886
		wIndex &= 0x0F;
887
		if ((pUDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex == 0)) {
888
			wStatus =
889
			    (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;
890 ebf16b4d Holger Hans Peter Freyther
			/* Table 9.4 wLength Two */
891
			udp_ep0_send_data((char *)&wStatus, sizeof(wStatus), 2);
892 43d61cf0 (no author)
		} else if ((pUDP->UDP_GLBSTATE & AT91C_UDP_FADDEN)
893
			   && (wIndex == 0)) {
894
			wStatus =
895
			    (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;
896 ebf16b4d Holger Hans Peter Freyther
			/* Table 9.4 wLength Two */
897
			udp_ep0_send_data((char *)&wStatus, sizeof(wStatus), 2);
898 43d61cf0 (no author)
		} else
899
			udp_ep0_send_stall();
900
		break;
901
	case STD_SET_FEATURE_ZERO:
902
		DEBUGE("SET_FEATURE_ZERO ");
903
		udp_ep0_send_stall();
904
		break;
905
	case STD_SET_FEATURE_INTERFACE:
906
		DEBUGE("SET_FEATURE_INTERFACE ");
907
		udp_ep0_send_zlp();
908
		break;
909
	case STD_SET_FEATURE_ENDPOINT:
910
		DEBUGE("SET_FEATURE_ENDPOINT ");
911
		udp_ep0_send_stall();
912
		break;
913
	case STD_CLEAR_FEATURE_ZERO:
914
		DEBUGE("CLEAR_FEATURE_ZERO ");
915
		udp_ep0_send_stall();
916
		break;
917
	case STD_CLEAR_FEATURE_INTERFACE:
918
		DEBUGE("CLEAR_FEATURE_INTERFACE ");
919
		udp_ep0_send_zlp();
920
		break;
921
	case STD_CLEAR_FEATURE_ENDPOINT:
922
		DEBUGE("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f);
923
		udp_ep0_send_stall();
924
		break;
925
	case STD_SET_INTERFACE:
926 58d958e6 Harald Welte
		DEBUGE("SET INTERFACE(if=%d, alt=%d) ", wIndex, wValue);
927
		/* store the interface number somewhere, once
928 2e6ea1d6 laforge
		 * we need to support DFU flashing DFU */
929 58d958e6 Harald Welte
		usb_if_alt_nr = wValue;
930
		usb_if_nr = wIndex;
931 2e6ea1d6 laforge
		udp_ep0_send_zlp();
932 43d61cf0 (no author)
		break;
933
	default:
934 514b0f72 laforge
		DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ",
935
			bRequest, bmRequestType);
936 43d61cf0 (no author)
		if ((bmRequestType & 0x3f) == USB_TYPE_DFU) {
937 514b0f72 laforge
			dfu_ep0_handler(bmRequestType, bRequest,
938
					wValue, wLength);
939 43d61cf0 (no author)
		} else
940
			udp_ep0_send_stall();
941
		break;
942
	}
943 514b0f72 laforge
	DEBUGE("\r\n");
944 43d61cf0 (no author)
}
945
946
/* minimal USB IRQ handler in DFU mode */
947 b0317c72 (no author)
static __dfufunc void dfu_udp_irq(void)
948 43d61cf0 (no author)
{
949
	AT91PS_UDP pUDP = AT91C_BASE_UDP;
950
	AT91_REG isr = pUDP->UDP_ISR;
951 1c2b1d22 laforge
	led1on();
952 43d61cf0 (no author)
953
	if (isr & AT91C_UDP_ENDBUSRES) {
954 1c2b1d22 laforge
		led2on();
955 43d61cf0 (no author)
		pUDP->UDP_IER = AT91C_UDP_EPINT0;
956
		/* reset all endpoints */
957
		pUDP->UDP_RSTEP = (unsigned int)-1;
958
		pUDP->UDP_RSTEP = 0;
959
		/* Enable the function */
960
		pUDP->UDP_FADDR = AT91C_UDP_FEN;
961
		/* Configure endpoint 0 */
962
		pUDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
963
		cur_config = 0;
964 460ece83 laforge
965
		if (dfu_state == DFU_STATE_dfuMANIFEST_WAIT_RST ||
966 d56bb35e Harald Welte
		    dfu_state == DFU_STATE_dfuMANIFEST ||
967
		    past_manifest) {
968 58d958e6 Harald Welte
			AT91F_DBGU_Printk("sam7dfu: switching to APP mode\r\n");
969 1acaecb4 Harald Welte
			switch (usb_if_alt_nr_dnload) {
970 58d958e6 Harald Welte
			case 2:
971 1acaecb4 Harald Welte
				switch_to_ram = 1;
972 58d958e6 Harald Welte
				break;
973
			default:
974
				/* reset back into the main application */
975
				AT91F_RSTSoftReset(AT91C_BASE_RSTC,
976
							  AT91C_RSTC_PROCRST|
977
					   		  AT91C_RSTC_PERRST|
978
							  AT91C_RSTC_EXTRST);
979
				break;
980
			}
981 460ece83 laforge
		}
982 43d61cf0 (no author)
	}
983
984
	if (isr & AT91C_UDP_EPINT0)
985
		dfu_udp_ep0_handler();
986
987
	/* clear all interrupts */
988
	pUDP->UDP_ICR = isr;
989
990
	AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_UDP);
991 1c2b1d22 laforge
992
	led1off();
993 43d61cf0 (no author)
}
994
995 b0317c72 (no author)
/* this is only called once before DFU mode, no __dfufunc required */
996 ebc20883 Holger Hans Peter Freyther
static __noreturn void dfu_switch(void)
997 43d61cf0 (no author)
{
998 1ba82b71 laforge
	DEBUGE("\r\nsam7dfu: switching to DFU mode\r\n");
999 1c2b1d22 laforge
1000 460ece83 laforge
	dfu_state = DFU_STATE_appDETACH;
1001
	AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST|
1002
			   AT91C_RSTC_PERRST|AT91C_RSTC_EXTRST);
1003 43d61cf0 (no author)
1004 460ece83 laforge
	/* We should never reach here, but anyway avoid returning to the
1005
	 * caller since he doesn't expect us to do so */
1006
	while (1) ;
1007 872a81da (no author)
}
1008 b0317c72 (no author)
1009
void __dfufunc dfu_main(void)
1010
{
1011 1c2b1d22 laforge
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1);
1012
	AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2);
1013
	led1off();
1014
	led2off();
1015
1016 569d11d8 laforge
	AT91F_DBGU_Init();
1017 1ba82b71 laforge
	AT91F_DBGU_Printk("\n\r\n\rsam7dfu - AT91SAM7 USB DFU bootloader\n\r"
1018 a1e7c0c5 Harald Welte
		 "(C) 2006-2011 by Harald Welte <hwelte@hmw-consulting.de>\n\r"
1019 1ba82b71 laforge
		 "This software is FREE SOFTWARE licensed under GNU GPL\n\r");
1020
	AT91F_DBGU_Printk("Version " COMPILE_SVNREV 
1021
			  " compiled " COMPILE_DATE 
1022
			  " by " COMPILE_BY "\n\r\n\r");
1023 1c2b1d22 laforge
1024 ad18651c (no author)
	udp_init();
1025
1026 514b0f72 laforge
	dfu_state = DFU_STATE_dfuIDLE;
1027
1028 ad18651c (no author)
	/* This implements 
1029 b0317c72 (no author)
	AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_UDP,
1030
			      OPENPCD_IRQ_PRIO_UDP,
1031
			      AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, dfu_udp_irq);
1032
	*/
1033
	AT91PS_AIC pAic = AT91C_BASE_AIC;
1034
	pAic->AIC_IDCR = 1 << AT91C_ID_UDP;
1035
	pAic->AIC_SVR[AT91C_ID_UDP] = (unsigned int) &dfu_udp_irq;
1036
	pAic->AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 
1037
					OPENPCD_IRQ_PRIO_UDP;
1038
	pAic->AIC_ICCR = 1 << AT91C_ID_UDP;
1039
1040
	AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_UDP);
1041
1042
	/* End-of-Bus-Reset is always enabled */
1043
1044
	/* Clear for set the Pull up resistor */
1045 6c6b1878 laforge
#if defined(PCD)
1046 ad18651c (no author)
	AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP);
1047 6c6b1878 laforge
#endif
1048 d1dd3611 laforge
	AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUPv4);
1049 b0317c72 (no author)
1050 569d11d8 laforge
	flash_init();
1051
1052 1ba82b71 laforge
	AT91F_DBGU_Printk("You may now start the DFU up/download process\r\n");
1053 b0317c72 (no author)
	/* do nothing, since all of DFU is interrupt driven */
1054 2306bcac henryk
	int i = 0;
1055
	while (1) {
1056
	    /* Occasionally reset watchdog */
1057
	    i = (i+1) % 10000;
1058
	    if( i== 0) {
1059
		AT91F_WDTRestart(AT91C_BASE_WDTC);
1060
	    }
1061 1acaecb4 Harald Welte
	    if (switch_to_ram) {
1062
		void (*ram_app_entry)(void);
1063 7ab41352 Holger Hans Peter Freyther
		int j;
1064
		for (j = 0; j < 32; j++)
1065
			AT91F_AIC_DisableIt(AT91C_BASE_AIC, j);
1066 1acaecb4 Harald Welte
		/* jump into RAM */
1067
		AT91F_DBGU_Printk("JUMP TO RAM\r\n");
1068
		ram_app_entry = AT91C_ISRAM + SAM7DFU_RAM_SIZE;
1069
		ram_app_entry();
1070
	    }
1071 2306bcac henryk
	}
1072 b0317c72 (no author)
}
1073
1074 83c18361 (no author)
const struct dfuapi __dfufunctab dfu_api = {
1075 a97e460b laforge
	.udp_init		= &udp_init,
1076 b0317c72 (no author)
	.ep0_send_data		= &udp_ep0_send_data,
1077
	.ep0_send_zlp		= &udp_ep0_send_zlp,
1078
	.ep0_send_stall		= &udp_ep0_send_stall,
1079
	.dfu_ep0_handler	= &dfu_ep0_handler,
1080
	.dfu_switch		= &dfu_switch,
1081
	.dfu_state		= &dfu_state,
1082
	.dfu_dev_descriptor	= &dfu_dev_descriptor,
1083
	.dfu_cfg_descriptor	= &dfu_cfg_descriptor,
1084
};
1085
1086 ad18651c (no author)
/* just for testing */
1087 b0317c72 (no author)
int foo = 12345;
Add picture from clipboard (Maximum size: 48.8 MB)