2 * fw/usb/atu2.c - Chip-specific driver for Atmel ATxxxU2 USB chips
4 * Written 2008-2011, 2013-2014 by Werner Almesberger
5 * Copyright 2008-2011, 2013-2014 Werner Almesberger
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.
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)
24 #define F_CPU 8000000UL
25 #include <util/delay.h>
28 #include <avr/interrupt.h>
38 #define BUG_ON(cond) do { if (cond) panic(); } while (0)
44 struct ep_descr eps[NUM_EPS];
47 static uint16_t usb_read_word(void)
52 return low | UEDATX << 8;
56 static void enable_addr(void *user)
58 while (!(UEINTX & (1 << TXINI)));
63 void set_addr(uint8_t addr)
66 usb_send(&eps[0], NULL, 0, enable_addr, NULL);
70 void usb_ep_change(struct ep_descr *ep)
72 if (ep->state == EP_TX) {
79 static bool ep_setup(void)
81 struct setup_request setup;
85 setup.bmRequestType = UEDATX;
86 setup.bRequest = UEDATX;
87 setup.wValue = usb_read_word();
88 setup.wIndex = usb_read_word();
89 setup.wLength = usb_read_word();
91 if (!handle_setup(&setup))
93 if (!(setup.bmRequestType & 0x80) && eps[0].state == EP_IDLE)
94 usb_send(&eps[0], NULL, 0, NULL, NULL);
99 static bool ep_rx(struct ep_descr *ep)
104 if (size > ep->end-ep->buf)
108 if (ep->buf == ep->end) {
111 ep->callback(ep->user);
112 // if (ep == &eps[0])
113 usb_send(ep, NULL, 0, NULL, NULL);
119 static void ep_tx(struct ep_descr *ep)
121 uint8_t size = ep->end-ep->buf;
126 for (left = size; left; left--)
128 if (size == ep->size)
134 static void handle_ep(int n)
136 struct ep_descr *ep = eps+n;
140 if (UEINTX & (1 << RXSTPI)) {
141 /* @@@ EP_RX. EP_TX: cancel */
145 UEINTX = ~(1 << RXSTPI);
147 if (UEINTX & (1 << RXOUTI)) {
148 /* @@ EP_TX: cancel */
149 if (ep->state != EP_RX)
153 /* @@@ gcc 4.5.2 wants this cast */
154 UEINTX = (uint8_t) ~(1 << RXOUTI | 1 << FIFOCON);
156 if (UEINTX & (1 << STALLEDI)) {
158 UEINTX = ~(1 << STALLEDI);
160 if (UEINTX & (1 << TXINI)) {
161 /* @@ EP_RX: cancel (?) */
162 if (ep->state == EP_TX) {
166 mask |= 1 << FIFOCON;
168 if (ep->state == EP_IDLE && ep->callback)
169 ep->callback(ep->user);
171 UEIENX &= ~(1 << TXINE);
177 UEINTX = ~(1 << RXSTPI | 1 << RXOUTI | 1 << STALLEDI);
179 UECONX |= 1 << STALLRQ;
186 UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */
187 UECFG0X = 0; /* control, direction is ignored */
188 UECFG1X = 3 << EPSIZE0; /* 64 bytes */
189 UECFG1X |= 1 << ALLOC;
191 while (!(UESTA0X & (1 << CFGOK)));
194 (1 << RXSTPE) | (1 << RXOUTE) | (1 << STALLEDE) | (1 << TXINE);
196 eps[0].state = EP_IDLE;
202 UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */
203 UECFG0X = (1 << EPTYPE1) | (1 << EPDIR); /* bulk IN */
204 UECFG1X = 3 << EPSIZE0; /* 64 bytes */
205 UECFG1X |= 1 << ALLOC;
207 while (!(UESTA0X & (1 << CFGOK)));
209 UEIENX = (1 << STALLEDE) | (1 << TXINE);
211 eps[1].state = EP_IDLE;
223 if (flags & (1 << EORSTI)) {
227 UDINT = ~(1 << EORSTI);
237 for (i = 0; i != NUM_EPS; i++)
238 if (flags & (1 << i))
245 UDCON |= 1 << DETACH; /* detach the pull-up */