IEEE 802.15.4 subsystem
Sign in or create your account | Project List | Help
IEEE 802.15.4 subsystem Git Source Tree
Root/
Source at commit 1dcc83391e51890c76fc8e11aeb24300a99412a2 created 13 years 20 days ago. By Werner Almesberger, atusb/fw/Makefile: put -mmcu into CFLAGS so that DEPEND uses it, too | |
---|---|
1 | /* |
2 | * fw/usb/atu2.c - Chip-specific driver for Atmel ATxxxU2 USB chips |
3 | * |
4 | * Written 2008-2011 by Werner Almesberger |
5 | * Copyright 2008-2011 Werner Almesberger |
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 | |
13 | /* |
14 | * Known issues: |
15 | * - no suspend/resume |
16 | * - we don't call back after failed transmissions, |
17 | * - we don't reset the EP buffer after failed receptions |
18 | * - enumeration often encounters an error -71 (from which it recovers) |
19 | */ |
20 | |
21 | #include <stdint.h> |
22 | |
23 | #define F_CPU 8000000UL |
24 | #include <util/delay.h> |
25 | |
26 | #include <avr/io.h> |
27 | #include "usb.h" |
28 | #include "../board.h" |
29 | |
30 | |
31 | #ifndef NULL |
32 | #define NULL 0 |
33 | #endif |
34 | |
35 | #if 1 |
36 | #define BUG_ON(cond) do { if (cond) panic(); } while (0) |
37 | #else |
38 | #define BUG_ON(cond) |
39 | #endif |
40 | |
41 | |
42 | #define NUM_EPS 1 |
43 | |
44 | |
45 | struct ep_descr eps[NUM_EPS]; |
46 | |
47 | |
48 | static uint16_t usb_read_word(void) |
49 | { |
50 | uint8_t low; |
51 | |
52 | low = UEDATX; |
53 | return low | UEDATX << 8; |
54 | } |
55 | |
56 | |
57 | static void enable_addr(void *user) |
58 | { |
59 | while (!(UEINTX & (1 << TXINI))); |
60 | UDADDR |= 1 << ADDEN; |
61 | } |
62 | |
63 | |
64 | int set_addr(uint8_t addr) |
65 | { |
66 | UDADDR = addr; |
67 | usb_send(&eps[0], NULL, 0, enable_addr, NULL); |
68 | return 1; |
69 | } |
70 | |
71 | |
72 | static int ep_setup(void) |
73 | { |
74 | struct setup_request setup; |
75 | |
76 | BUG_ON(UEBCLX < 8); |
77 | |
78 | setup.bmRequestType = UEDATX; |
79 | setup.bRequest = UEDATX; |
80 | setup.wValue = usb_read_word(); |
81 | setup.wIndex = usb_read_word(); |
82 | setup.wLength = usb_read_word(); |
83 | |
84 | if (!handle_setup(&setup)) |
85 | return 0; |
86 | if (!(setup.bmRequestType & 0x80) && eps[0].state == EP_IDLE) |
87 | usb_send(&eps[0], NULL, 0, NULL, NULL); |
88 | return 1; |
89 | } |
90 | |
91 | |
92 | static int ep_rx(struct ep_descr *ep) |
93 | { |
94 | uint8_t size; |
95 | |
96 | size = UEBCLX; |
97 | if (size > ep->end-ep->buf) |
98 | return 0; |
99 | while (size--) |
100 | *ep->buf++ = UEDATX; |
101 | if (ep->buf == ep->end) { |
102 | ep->state = EP_IDLE; |
103 | if (ep->callback) |
104 | ep->callback(ep->user); |
105 | if (ep == &eps[0]) |
106 | usb_send(ep, NULL, 0, NULL, NULL); |
107 | } |
108 | return 1; |
109 | } |
110 | |
111 | |
112 | static void ep_tx(struct ep_descr *ep) |
113 | { |
114 | uint8_t size = ep->end-ep->buf; |
115 | uint8_t left; |
116 | |
117 | if (size > ep->size) |
118 | size = ep->size; |
119 | for (left = size; left; left--) |
120 | UEDATX = *ep->buf++; |
121 | if (size == ep->size) |
122 | return; |
123 | ep->state = EP_IDLE; |
124 | } |
125 | |
126 | |
127 | static void handle_ep(int n) |
128 | { |
129 | struct ep_descr *ep = eps+n; |
130 | |
131 | UENUM = n; |
132 | if (UEINTX & (1 << RXSTPI)) { |
133 | /* @@@ EP_RX. EP_TX: cancel */ |
134 | if (!ep_setup()) |
135 | goto stall; |
136 | UEINTX &= ~(1 << RXSTPI); |
137 | } |
138 | if (UEINTX & (1 << RXOUTI)) { |
139 | /* @@ EP_TX: cancel */ |
140 | if (ep->state != EP_RX) |
141 | goto stall; |
142 | if (!ep_rx(ep)) |
143 | goto stall; |
144 | // UEINTX &= ~(1 << RXOUTI); |
145 | UEINTX &= ~(1 << RXOUTI | 1 << FIFOCON); |
146 | } |
147 | if (UEINTX & (1 << STALLEDI)) { |
148 | ep->state = EP_IDLE; |
149 | UEINTX &= ~(1 << STALLEDI); |
150 | } |
151 | if (UEINTX & (1 << TXINI)) { |
152 | /* @@ EP_RX: cancel */ |
153 | if (ep->state == EP_TX) { |
154 | ep_tx(ep); |
155 | UEINTX &= ~(1 << TXINI); |
156 | if (ep->state == EP_IDLE && ep->callback) |
157 | ep->callback(ep->user); |
158 | } |
159 | } |
160 | return; |
161 | |
162 | stall: |
163 | UEINTX &= ~(1 << RXSTPI | 1 << RXOUTI | 1 << STALLEDI); |
164 | ep->state = EP_IDLE; |
165 | UECONX |= 1 << STALLRQ; |
166 | } |
167 | |
168 | |
169 | void usb_poll(void) |
170 | { |
171 | uint8_t flags, i; |
172 | |
173 | flags = UEINT; |
174 | for (i = 0; i != NUM_EPS; i++) |
175 | if (1 || flags & (1 << i)) |
176 | handle_ep(i); |
177 | /* @@@ USB bus reset */ |
178 | } |
179 | |
180 | |
181 | static void ep_init(void) |
182 | { |
183 | UENUM = 0; |
184 | UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */ |
185 | UECFG0X = 0; /* control, direction is ignored */ |
186 | UECFG1X = 3 << EPSIZE0; /* 64 bytes */ |
187 | UECFG1X |= 1 << ALLOC; |
188 | |
189 | while (!(UESTA0X & (1 << CFGOK))); |
190 | |
191 | eps[0].state = EP_IDLE; |
192 | eps[0].size = 64; |
193 | } |
194 | |
195 | |
196 | void usb_init(void) |
197 | { |
198 | USBCON |= 1 << FRZCLK; /* freeze the clock */ |
199 | |
200 | /* enable the PLL and wait for it to lock */ |
201 | PLLCSR &= ~(1 << PLLP2 | 1 << PLLP1 | 1 << PLLP0); |
202 | PLLCSR |= 1 << PLLE; |
203 | while (!(PLLCSR & (1 << PLOCK))); |
204 | |
205 | USBCON &= ~(1 << USBE); /* reset the controller */ |
206 | USBCON |= 1 << USBE; |
207 | |
208 | USBCON &= ~(1 << FRZCLK); /* thaw the clock */ |
209 | |
210 | UDCON &= ~(1 << DETACH); /* attach the pull-up */ |
211 | UDCON |= 1 << RSTCPU; /* reset CPU on bus reset */ |
212 | |
213 | ep_init(); |
214 | } |
215 |