Root/tools/lib/atusb-common.c

Source at commit f8f2f890d9cc1c81996fb83f7c131b0e1b78e262 created 8 years 4 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
32int atusb_error(void *handle)
33{
34    struct atusb_dsc *dsc = handle;
35
36    return dsc->error;
37}
38
39
40int 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
54void *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
88void atusb_close(void *handle)
89{
90    /* to do */
91}
92
93
94/* ----- device mode ------------------------------------------------------- */
95
96
97void 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
114void 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
131void 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
151void 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
203int 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
240int 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
276void *atusb_dev_handle(void *handle)
277{
278    struct atusb_dsc *dsc = handle;
279
280    return dsc->dev;
281}
282

Archive Download this file



interactive