Add firmware for the ATUSB IEEE 802.15.4 USB Adapter
[linux-libre-firmware.git] / atusb / usb / usb.c
1 /*
2  * fw/usb/usb.c - USB hardware setup and standard device requests
3  *
4  * Written 2008-2011, 2013, 2015 by Werner Almesberger
5  * Copyright 2008-2011, 2013, 2015 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  * - should support EP clearing and stalling
17  */
18
19 #include <stdbool.h>
20 #include <stdint.h>
21
22 #include "usb.h"
23 #include "board.h"
24
25
26 #ifndef NULL
27 #define NULL 0
28 #endif
29
30 #if 1
31 extern void panic(void);
32 #define BUG_ON(cond)    do { if (cond) panic(); } while (0)
33 #else
34 #define BUG_ON(cond)
35 #endif
36
37 bool (*user_setup)(const struct setup_request *setup);
38 void (*user_set_interface)(int nth);
39 bool (*user_get_descriptor)(uint8_t type, uint8_t index,
40     const uint8_t **reply, uint8_t *size);
41 void (*user_reset)(void);
42
43
44 void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
45     uint8_t size, void (*callback)(void *user), void *user)
46 {
47         BUG_ON(ep->state);
48         ep->state = state;
49         ep->buf = buf;
50         ep->end = buf+size;
51         ep->callback = callback;
52         ep->user = user;
53         usb_ep_change(ep);
54 }
55
56
57 static bool get_descriptor(uint8_t type, uint8_t index, uint16_t length)
58 {
59         const uint8_t *reply;
60         uint8_t size;
61
62         switch (type) {
63         case USB_DT_DEVICE:
64                 reply = device_descriptor;
65                 size = reply[0];
66                 break;
67         case USB_DT_CONFIG:
68                 if (index)
69                         return 0;
70                 reply = config_descriptor;
71                 size = reply[2];
72                 break;
73         default:
74                 if (!user_get_descriptor)
75                         return 0;
76                 if (!user_get_descriptor(type, index, &reply, &size))
77                         return 0;
78         }
79         if (length < size)
80                 size = length;
81         usb_send(&eps[0], reply, size, NULL, NULL);
82         return 1;
83 }
84
85
86 bool handle_setup(const struct setup_request *setup)
87 {
88         switch (setup->bmRequestType | setup->bRequest << 8) {
89
90         /*
91          * Device request
92          *
93          * See http://www.beyondlogic.org/usbnutshell/usb6.htm
94          */
95
96         case FROM_DEVICE(GET_STATUS):
97                 if (setup->wLength != 2)
98                         return 0;
99                 usb_send(&eps[0], "\000", 2, NULL, NULL);
100                 break;
101         case TO_DEVICE(CLEAR_FEATURE):
102                 break;
103         case TO_DEVICE(SET_FEATURE):
104                 return 0;
105         case TO_DEVICE(SET_ADDRESS):
106                 set_addr(setup->wValue);
107                 break;
108         case FROM_DEVICE(GET_DESCRIPTOR):
109         case FROM_INTERFACE(GET_DESCRIPTOR):
110                 if (!get_descriptor(setup->wValue >> 8, setup->wValue,
111                     setup->wLength))
112                         return 0;
113                 break;
114         case TO_DEVICE(SET_DESCRIPTOR):
115                 return 0;
116         case FROM_DEVICE(GET_CONFIGURATION):
117                 usb_send(&eps[0], "", 1, NULL, NULL);
118                 break;
119         case TO_DEVICE(SET_CONFIGURATION):
120                 if (setup->wValue != config_descriptor[5])
121                         return 0;
122                 break;
123
124         /*
125          * Interface request
126          */
127
128         case FROM_INTERFACE(GET_STATUS):
129                 return 0;
130         case TO_INTERFACE(CLEAR_FEATURE):
131                 return 0;
132         case TO_INTERFACE(SET_FEATURE):
133                 return 0;
134         case FROM_INTERFACE(GET_INTERFACE):
135                 return 0;
136         case TO_INTERFACE(SET_INTERFACE):
137                 {
138                         const uint8_t *interface_descriptor =
139                             config_descriptor+9;
140                         const uint8_t *p;
141                         int i;
142
143                         i = 0;
144                         for (p = interface_descriptor;
145                             p != config_descriptor+config_descriptor[2];
146                             p += p[0]) {
147                                 if (p[1] != USB_DT_INTERFACE)
148                                         continue;
149                                 if (p[2] == setup->wIndex &&
150                                     p[3] == setup->wValue) {
151                                         if (user_set_interface)
152                                                 user_set_interface(i);
153                                         return 1;
154                                 }
155                                 i++;
156                         }
157                         return 0;
158                 }
159                 break;
160
161         /*
162          * Endpoint request
163          */
164
165         case FROM_ENDPOINT(GET_STATUS):
166                 return 0;
167         case TO_ENDPOINT(CLEAR_FEATURE):
168                 return 0;
169         case TO_ENDPOINT(SET_FEATURE):
170                 return 0;
171         case FROM_ENDPOINT(SYNCH_FRAME):
172                 return 0;
173
174         default:
175                 if (user_setup)
176                         return user_setup(setup);
177                 return 0;
178         }
179
180         return 1;
181 }