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 f8f2f890d9cc1c81996fb83f7c131b0e1b78e262 created 12 years 9 months ago. By Werner Almesberger, tools/lib/atusb-common.c (atusb_interrupt_wait): don't try to pull more irqs | |
---|---|
1 | /* |
2 | * lib/atusb-common.c - ATUSB access functions shared by all ATUSB drivers |
3 | * |
4 | * Written 2010-2011 by Werner Almesberger |
5 | * Copyright 2010-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 | #include <stdint.h> |
15 | #include <stdlib.h> |
16 | #include <stdio.h> |
17 | #include <usb.h> |
18 | #include <errno.h> |
19 | |
20 | #include "atusb/ep0.h" |
21 | #include "atusb/usb-ids.h" |
22 | |
23 | #include "at86rf230.h" |
24 | #include "usbopen.h" |
25 | #include "driver.h" |
26 | #include "atusb-common.h" |
27 | |
28 | |
29 | /* ----- error handling ---------------------------------------------------- */ |
30 | |
31 | |
32 | int atusb_error(void *handle) |
33 | { |
34 | struct atusb_dsc *dsc = handle; |
35 | |
36 | return dsc->error; |
37 | } |
38 | |
39 | |
40 | int atusb_clear_error(void *handle) |
41 | { |
42 | struct atusb_dsc *dsc = handle; |
43 | int ret; |
44 | |
45 | ret = dsc->error; |
46 | dsc->error = 0; |
47 | return ret; |
48 | } |
49 | |
50 | |
51 | /* ----- open/close -------------------------------------------------------- */ |
52 | |
53 | |
54 | void *atusb_open(const char *arg) |
55 | { |
56 | usb_dev_handle *dev; |
57 | struct atusb_dsc *dsc; |
58 | int res; |
59 | |
60 | usb_unrestrict(); |
61 | if (arg) |
62 | restrict_usb_path(arg); |
63 | dev = open_usb(USB_VENDOR, USB_PRODUCT); |
64 | if (!dev) { |
65 | fprintf(stderr, ":-(\n"); |
66 | return NULL; |
67 | } |
68 | |
69 | res = usb_claim_interface(dev, 0); |
70 | if (res) { |
71 | fprintf(stderr, "usb_claim_interface: %d\n", res); |
72 | return NULL; |
73 | } |
74 | |
75 | dsc = malloc(sizeof(*dsc)); |
76 | if (!dsc) { |
77 | perror("malloc"); |
78 | exit(1); |
79 | } |
80 | |
81 | dsc->dev = dev; |
82 | dsc->error = 0; |
83 | |
84 | return dsc; |
85 | } |
86 | |
87 | |
88 | void atusb_close(void *handle) |
89 | { |
90 | /* to do */ |
91 | } |
92 | |
93 | |
94 | /* ----- device mode ------------------------------------------------------- */ |
95 | |
96 | |
97 | void atusb_reset(void *handle) |
98 | { |
99 | struct atusb_dsc *dsc = handle; |
100 | int res; |
101 | |
102 | if (dsc->error) |
103 | return; |
104 | |
105 | res = |
106 | usb_control_msg(dsc->dev, TO_DEV, ATUSB_RESET, 0, 0, NULL, 0, 1000); |
107 | if (res < 0) { |
108 | fprintf(stderr, "ATUSB_RESET: %d\n", res); |
109 | dsc->error = 1; |
110 | } |
111 | } |
112 | |
113 | |
114 | void atusb_reset_rf(void *handle) |
115 | { |
116 | struct atusb_dsc *dsc = handle; |
117 | int res; |
118 | |
119 | if (dsc->error) |
120 | return; |
121 | |
122 | res = usb_control_msg(dsc->dev, TO_DEV, ATUSB_RF_RESET, 0, 0, NULL, |
123 | 0, 1000); |
124 | if (res < 0) { |
125 | fprintf(stderr, "ATUSB_RF_RESET: %d\n", res); |
126 | dsc->error = 1; |
127 | } |
128 | } |
129 | |
130 | |
131 | void atusb_test_mode(void *handle) |
132 | { |
133 | struct atusb_dsc *dsc = handle; |
134 | int res; |
135 | |
136 | if (dsc->error) |
137 | return; |
138 | |
139 | res = |
140 | usb_control_msg(dsc->dev, TO_DEV, ATUSB_TEST, 0, 0, NULL, 0, 1000); |
141 | if (res < 0) { |
142 | fprintf(stderr, "ATUSB_TEST: %d\n", res); |
143 | dsc->error = 1; |
144 | } |
145 | } |
146 | |
147 | |
148 | /* ----- SLP_TR ------------------------------------------------------------ */ |
149 | |
150 | |
151 | void atusb_slp_tr(void *handle, int on, int pulse) |
152 | { |
153 | struct atusb_dsc *dsc = handle; |
154 | int res; |
155 | |
156 | if (dsc->error) |
157 | return; |
158 | |
159 | if (!on || !pulse) { |
160 | fprintf(stderr, |
161 | "SLP_TR mode on=%d pulse=%d not supported\n", on, pulse); |
162 | return; |
163 | } |
164 | |
165 | res = usb_control_msg(dsc->dev, TO_DEV, ATUSB_SLP_TR, 0, 0, NULL, 0, |
166 | 1000); |
167 | if (res < 0) { |
168 | fprintf(stderr, "ATUSB_SLP_TR: %d\n", res); |
169 | dsc->error = 1; |
170 | } |
171 | } |
172 | |
173 | |
174 | /* ----- RF interrupt ------------------------------------------------------ */ |
175 | |
176 | |
177 | /* |
178 | * The logic here is a bit tricky. Assuming that we can get a lot of |
179 | * interrupts, system state can change as follows: |
180 | * |
181 | * Event IRQ_STATUS EP1 on atusb EP1 on host irq |
182 | * INT (var) |
183 | * -------------------- ------- --- ------------ ----------- ----- |
184 | * interrupt A A H EP_IDLE - - |
185 | * INT0 handler - - EP_TX (A) - - |
186 | * interrupt B B H EP_TX (A) - - |
187 | * INT0 handler B H EP_TX (A) - - |
188 | * IN from host B H EP_IDLE A - |
189 | * interrupt C B+C H EP_IDLE A - |
190 | * call to atusb_interrupt_wait |
191 | * read IRQ_STATUS - - EP_IDLE A B+C |
192 | * interrupt D D H EP_IDLE A B+C |
193 | * INT0 handler - - EP_TX (D) A B+C |
194 | * IN from host - - EP_IDLE A, D B+C |
195 | * usb_bulk_read - - EP_IDLE - A+B+C+D |
196 | * usb_bulk_read -> no more data, done |
197 | * |
198 | * We therefore have to consider interrupts queued up at the host and pending |
199 | * in REG_IRQ_STATUS in addition to anything that may arrive while we wait. |
200 | */ |
201 | |
202 | |
203 | int atusb_interrupt_wait(void *handle, int timeout_ms) |
204 | { |
205 | struct atusb_dsc *dsc = handle; |
206 | uint8_t irq, buf[100]; |
207 | int res, i; |
208 | |
209 | if (dsc->error) |
210 | return 0; |
211 | |
212 | irq = atusb_driver.reg_read(handle, REG_IRQ_STATUS); |
213 | if (irq) |
214 | timeout_ms = 1; |
215 | |
216 | res = usb_bulk_read(dsc->dev, 1, |
217 | (char *) &buf, sizeof(buf), timeout_ms); |
218 | if (res != -ETIMEDOUT) { |
219 | if (res < 0) { |
220 | fprintf(stderr, "usb_bulk_read: %d\n", res); |
221 | dsc->error = 1; |
222 | return 0; /* handle this via atrf_error */ |
223 | } |
224 | for (i = 0; i != res; i++) |
225 | irq |= buf[i]; |
226 | } |
227 | return irq; |
228 | } |
229 | |
230 | |
231 | /* ----- CLKM handling ----------------------------------------------------- */ |
232 | |
233 | |
234 | /* |
235 | * ATmega32U2-based boards don't allow disabling CLKM, so we keep it at 8 MHz. |
236 | * We could accommodate a choice between 8 MHz and 16 MHz, but that's for |
237 | * later. |
238 | */ |
239 | |
240 | int atusb_set_clkm(void *handle, int mhz) |
241 | { |
242 | struct atusb_dsc *dsc = handle; |
243 | uint8_t ids[3]; |
244 | int res; |
245 | |
246 | if (dsc->error) |
247 | return 0; |
248 | res = usb_control_msg(dsc->dev, FROM_DEV, ATUSB_ID, 0, 0, |
249 | (void *) ids, 3, 1000); |
250 | if (res < 0) { |
251 | fprintf(stderr, "ATUSB_ID: %s\n", usb_strerror()); |
252 | dsc->error = 1; |
253 | return 0; |
254 | } |
255 | switch (ids[2]) { |
256 | case HW_TYPE_100813: |
257 | case HW_TYPE_101216: |
258 | break; |
259 | case HW_TYPE_110131: |
260 | if (mhz == 0 || mhz == 8) |
261 | return 1; |
262 | fprintf(stderr, "this board only supports CLKM = 8 MHz\n"); |
263 | return 0; |
264 | default: |
265 | fprintf(stderr, |
266 | "atusb_set_clkm: unknown hardware type 0x%02x\n", ids[2]); |
267 | return 0; |
268 | } |
269 | return atrf_set_clkm_generic(atusb_driver.reg_write, dsc, mhz); |
270 | } |
271 | |
272 | |
273 | /* ----- Driver-specific hacks --------------------------------------------- */ |
274 | |
275 | |
276 | void *atusb_dev_handle(void *handle) |
277 | { |
278 | struct atusb_dsc *dsc = handle; |
279 | |
280 | return dsc->dev; |
281 | } |
282 |