Hallo,
ich wühle mich gerade durch das Keyboard-Bespiel aus dem ASF und rätsle
über die Notwendigkeit des Verriegels des Interruptsystems. Hintergrund:
ich kann aus anderen Gründe keine allzu lange Zeit im Disabled-Zustand
zulassen.
Atmel hat da Zugriffsroutinen auf den Keyboardreport definiert, hier mal
als Beispiel der Modifiereintrag:
1 | bool udi_hid_kbd_modifier_up(uint8_t modifier_id)
|
2 | {
|
3 | irqflags_t flags = cpu_irq_save();
|
4 |
|
5 | // Fill report
|
6 | udi_hid_kbd_report[0] &= ~(unsigned)modifier_id;
|
7 | udi_hid_kbd_b_report_valid = true;
|
8 |
|
9 | // Send report
|
10 | udi_hid_kbd_send_report();
|
11 |
|
12 | cpu_irq_restore(flags);
|
13 | return true;
|
14 | }
|
Hier machen sie also cli(), dann das Bit eintragen, dann kommt
udi_hid_kbd_send_report():
1 | static bool udi_hid_kbd_send_report(void) // runs in disabled int
|
2 | {
|
3 | if (udi_hid_kbd_b_report_trans_ongoing)
|
4 | return false;
|
5 | memcpy(udi_hid_kbd_report_trans, udi_hid_kbd_report,
|
6 | UDI_HID_KBD_REPORT_SIZE);
|
7 | udi_hid_kbd_b_report_valid = false;
|
8 | udi_hid_kbd_b_report_trans_ongoing =
|
9 | udd_ep_run( UDI_HID_KBD_EP_IN,
|
10 | false,
|
11 | udi_hid_kbd_report_trans,
|
12 | UDI_HID_KBD_REPORT_SIZE,
|
13 | udi_hid_kbd_report_sent);
|
14 | return udi_hid_kbd_b_report_trans_ongoing;
|
15 | }
|
Hier geht es, wenn möglich, nach udd_ep_run() = Endpoint run. Endpoint
run ist dann eine länger Geschichte:
1 | bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t * buf,
|
2 | iram_size_t buf_size, udd_callback_trans_t callback)
|
3 | {
|
4 | udd_ep_job_t *ptr_job;
|
5 | irqflags_t flags;
|
6 | UDD_EP_t *ep_ctrl;
|
7 |
|
8 | Assert(udd_ep_is_valid(ep));
|
9 |
|
10 | // Get control & job about this endpoint
|
11 | ptr_job = udd_ep_get_job(ep);
|
12 | ep_ctrl = udd_ep_get_ctrl(ep);
|
13 |
|
14 | if (!udd_endpoint_is_enable(ep_ctrl)) {
|
15 | return false; // Endpoint not allocated
|
16 | }
|
17 | if (udd_endpoint_get_type(ep_ctrl)!=USB_EP_TYPE_ISOCHRONOUS_gc
|
18 | && udd_endpoint_is_stall(ep_ctrl)) {
|
19 | return false; // Endpoint is halted
|
20 | }
|
21 | flags = cpu_irq_save(); // endpoint run
|
22 | if (ptr_job->busy == true) {
|
23 | cpu_irq_restore(flags);
|
24 | return false; // Job already on going
|
25 | }
|
26 | ptr_job->busy = true;
|
27 | cpu_irq_restore(flags);
|
28 |
|
29 |
|
30 | // Update Job information
|
31 | ptr_job->buf = buf;
|
32 | ptr_job->buf_size = buf_size;
|
33 | ptr_job->nb_trans = 0;
|
34 | ptr_job->call_trans = callback;
|
35 | // Need to enable shortpacket to send a ZLP (buf_size==0)
|
36 | ptr_job->b_shortpacket = b_shortpacket || (buf_size==0);
|
37 | ptr_job->b_use_out_cache_buffer = false;
|
38 |
|
39 | // Initialize value to simulate a empty transfer
|
40 | if (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)) {
|
41 | udd_endpoint_in_reset_nb_sent(ep_ctrl);
|
42 | }
|
43 | else
|
44 | {
|
45 | if ((USB_EP_TYPE_ISOCHRONOUS_gc == udd_endpoint_get_type(ep_ctrl))
|
46 | && (0 != (buf_size % udd_ep_get_size(ep_ctrl)))) {
|
47 | // The user must use a buffer size modulo endpoint size
|
48 | ptr_job->busy = false;
|
49 | return false;
|
50 | }
|
51 | udd_endpoint_out_reset_nb_received(ep_ctrl);
|
52 | udd_endpoint_out_set_nbbyte(ep_ctrl, 0);
|
53 | }
|
54 | // Request next transfer
|
55 | udd_ep_trans_complet(ep);
|
56 | return true;
|
57 | }
|
Hier ist die eigentlich kritische Geschichte, nämlich kontrollieren ob
ptr_job->busy == true ist, nochmals mit cli()-restore geklammert.
Brauche ich dann die äußere Verriegelung bei udi_hid_kbd_modifier_up?
Oder soll die nur reentry verhindern?
Gruß Wolfgang