version 0.1 written by Akiba, taken from here:
[chibi.git] / freakusb / hw / at90usbxx2 / ep.c
blob35f381aecc1b8c8d2e91687f6ab7c98f7c6476ff
1 /*******************************************************************
2 Copyright (C) 2008 FreakLabs
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 Please post support questions to the FreakLabs forum.
19 *******************************************************************/
20 /*!
21 \file ep.c
22 \ingroup hw_at90usb
24 /*******************************************************************/
25 #include <avr/io.h>
26 #include <avr/interrupt.h>
27 #include "freakusb.h"
28 #include "at90usb.h"
30 /**************************************************************************/
31 /*!
32 Select the endpoint number so that we can see the endpoint's associated
33 registers.
35 /**************************************************************************/
36 void ep_select(U8 ep_num)
38 UENUM = ep_num;
41 /**************************************************************************/
42 /*!
43 Get the max packet size of the endpoint.
45 /**************************************************************************/
46 U8 ep_size_get()
48 U8 tmp = (UECFG1X &= (7<<EPSIZE0));
49 tmp >>= EPSIZE0;
50 return (U8)(1 << (tmp + 3));
53 /**************************************************************************/
54 /*!
55 Get the direction of the endpoint.
57 /**************************************************************************/
58 U8 ep_dir_get()
60 return (UECFG0X & 0x1);
63 /**************************************************************************/
64 /*!
65 Get the endpoint type: BULK, CONTROL, INTERRUPT, ISOCHRONOUS
67 /**************************************************************************/
68 U8 ep_type_get()
70 return ((UECFG0X & (0x3 << EPTYPE0)) >> EPTYPE0);
73 /**************************************************************************/
74 /*!
75 Clear the endpoint configuration registers
77 /**************************************************************************/
78 void ep_cfg_clear()
80 UECFG0X = 0;
81 UECFG1X = 0;
84 /**************************************************************************/
85 /*!
86 Clear the specified endpoint's enable bit.
88 /**************************************************************************/
89 void ep_disable()
91 UECONX &= ~(1 << EPEN);
94 /**************************************************************************/
95 /*!
96 Configure the endpoint with the specified parameters.
98 /**************************************************************************/
99 void ep_config(U8 ep_num, U8 type, U8 dir, U8 size)
101 // init the direction the fifo
102 usb_buf_init(ep_num, dir);
104 // select the endpoint and reset it
105 ep_select(ep_num);
106 UECONX &= ~(1 << EPEN);
107 UECONX |= (1 << EPEN);
109 // set the type, direction, and size
110 UECFG0X |= (type & 0x3) << EPTYPE0;
111 UECFG0X |= dir;
112 UECFG1X |= (size & 0x7) << EPSIZE0;
114 // we're only using single banks for now. double banks can be used on certain EPs only.
115 UECFG1X |= (SINGLE & 0x3) << EPBK0;
117 // alloc memory for the endpoint
118 UECFG1X |= (1 << ALLOC);
120 // spin here until the config is okay
121 while (!(UESTA0X & (1<<CFGOK)));
123 UERST |= (1<<ep_num);
124 UERST &= ~(1<<ep_num);
126 if (ep_num == EP_CTRL)
128 RX_SETUP_INT_ENB();
129 RX_OUT_INT_ENB();
131 else if (dir == DIR_OUT)
133 RX_OUT_INT_ENB();
137 /**************************************************************************/
139 Write into the endpoint's FIFOs. These will be used to transfer data out
140 of that particular endpoint to the host.
142 /**************************************************************************/
143 void ep_write(U8 ep_num)
145 U8 i, ep_size, len;
146 usb_pcb_t *pcb = usb_pcb_get();
148 ep_select(ep_num);
149 ep_size = ep_size_get();
150 len = pcb->fifo[ep_num].len;
152 // make sure that the tx fifo is ready to receive the out data
153 if (ep_num == EP_CTRL)
155 while (!TX_FIFO_READY);
157 else
159 while (!RWAL_INT);
162 for (i=0; i<len; i++)
164 // check if we've reached the max packet size for the endpoint
165 if (i == ep_size)
167 // we've filled the max packet size so break and send the data
168 break;
171 UEDATX = usb_buf_read(ep_num);
174 if (ep_num == EP_CTRL)
176 while (!TX_FIFO_READY);
179 // clearing these two will send the data out
180 TX_IN_INT_CLR();
181 FIFOCON_INT_CLR();
184 /**************************************************************************/
186 Read data from the endpoint's FIFO. This is where data coming into the
187 device from the host is stored.
189 /**************************************************************************/
190 void ep_read(U8 ep_num)
192 U8 i, len;
193 usb_pcb_t *pcb = usb_pcb_get();
195 len = FIFO_BYTE_CNT;
197 for (i=0; i<len; i++)
199 usb_buf_write(ep_num, UEDATX);
202 if (len > 0)
204 pcb->flags |= (ep_num == 0) ? (1<<SETUP_DATA_AVAIL) : (1<<RX_DATA_AVAIL);
208 /**************************************************************************/
210 Send a zero length packet on the specified endpoint. This is usually used
211 to terminate a transfer.
213 /**************************************************************************/
214 void ep_send_zlp(U8 ep_num)
216 cli();
217 ep_select(ep_num);
218 while (!TX_FIFO_READY);
219 TX_DATA();
220 while (!TX_FIFO_READY);
221 sei();
224 /**************************************************************************/
226 Stall the endpoint due to some problem. This function will also set the
227 stall flag in the protocol control block.
229 /**************************************************************************/
230 void ep_set_stall(U8 ep_num)
232 usb_pcb_t *pcb = usb_pcb_get();
234 pcb->ep_stall |= (1 << ep_num);
235 ep_select(ep_num);
236 UECONX |= (1 << STALLRQ);
239 /**************************************************************************/
241 This function will clear the stall on an endpoint.
243 /**************************************************************************/
244 void ep_clear_stall(U8 ep_num)
246 usb_pcb_t *pcb = usb_pcb_get();
248 pcb->ep_stall &= ~(1 << ep_num);
249 ep_select(ep_num);
250 UECONX |= (1<<STALLRQC);
253 /**************************************************************************/
255 Reset the data toggle on the specified endpoint.
257 /**************************************************************************/
258 void ep_reset_toggle(U8 ep_num)
260 ep_select(ep_num);
261 UECONX |= (1<<RSTDT);
264 /**************************************************************************/
266 Clear all endpoints and initialize ep0 for control transfers.
268 /**************************************************************************/
269 void ep_init()
271 U8 i;
273 // disable and clear all endpoints
274 for (i=0; i<MAX_EPS; i++)
276 ep_select(i);
277 ep_disable(i);
278 ep_cfg_clear(i);
281 // reset all the endpoints
282 UERST = 0x7F;
283 UERST = 0;
285 // configure the control endpoint first since that one is needed for enumeration
286 ep_config(EP_CTRL, CONTROL, DIR_OUT, PKTSZ_32);
288 // set the rx setup interrupt to received the enumeration interrupts
289 ep_select(EP_CTRL);
292 /**************************************************************************/
294 Set the address for the device. This will be called when a SET_ADDR request
295 is sent by the host. We can only set the address after we send a ZLP to the host
296 informing it that we successfully received the request. Otherwise, we will
297 be on a different address when the host ACKs us back on the original address (0).
299 /**************************************************************************/
300 void ep_set_addr(U8 addr)
302 // send out a zlp to ack the set address request
303 ep_send_zlp(EP_CTRL);
305 // only write the top 7 bits of the address. the 8th bit is for enable
306 UDADDR = addr & 0x7F;
308 // enable the address after the host acknowledges the frame was sent
309 UDADDR |= (1 << ADDEN);
313 /**************************************************************************/
315 Return the ep where an intp occurred. If no intp occurred, then return 0xff.
317 /**************************************************************************/
318 U8 ep_intp_get_num()
320 U8 i;
322 for (i=0; i<MAX_EPS; i++)
324 if (UEINT & (1<<i))
326 return i;
329 return 0xFF;
332 /**************************************************************************/
334 Get the endpoint number that the interrupt occurred on. If no interrupt
335 is found, return 0xFF.
337 /**************************************************************************/
338 U8 ep_intp_get_src()
340 U8 i;
342 // get the intp src
343 for (i=0; i<8; i++)
345 if ((UEINTX & (1<<i)) && (UEIENX & (1<<i)))
347 return i;
350 return 0xFF;