source: mainline/uspace/drv/ohci/hc.c@ 1d1bb0f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1d1bb0f was c4fb5ecd, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Less logging in USB host controller drivers

Many of the debug messages were degraded to debug2 level or
completely removed. Also added formatting string for unified
dump of USB transfer batches.

Warnings in EHCI stub use debug level now.

  • Property mode set to 100644
File size: 19.9 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/** @addtogroup drvusbohcihc
29 * @{
30 */
31/** @file
32 * @brief OHCI Host controller driver routines
33 */
34#include <errno.h>
35#include <str_error.h>
36#include <adt/list.h>
37#include <libarch/ddi.h>
38
39#include <usb/debug.h>
40#include <usb/usb.h>
41#include <usb/ddfiface.h>
42
43#include "hc.h"
44#include "hcd_endpoint.h"
45
46#define OHCI_USED_INTERRUPTS \
47 (I_SO | I_WDH | I_UE | I_RHSC)
48static int interrupt_emulator(hc_t *instance);
49static void hc_gain_control(hc_t *instance);
50static int hc_init_transfer_lists(hc_t *instance);
51static int hc_init_memory(hc_t *instance);
52/*----------------------------------------------------------------------------*/
53/** Announce OHCI root hub to the DDF
54 *
55 * @param[in] instance OHCI driver intance
56 * @param[in] hub_fun DDF fuction representing OHCI root hub
57 * @return Error code
58 */
59int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
60{
61 assert(instance);
62 assert(hub_fun);
63
64 const usb_address_t hub_address =
65 device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
66 if (hub_address <= 0) {
67 usb_log_error("Failed to get OHCI root hub address: %s\n",
68 str_error(hub_address));
69 return hub_address;
70 }
71 instance->rh.address = hub_address;
72 usb_device_keeper_bind(
73 &instance->manager, hub_address, hub_fun->handle);
74
75#define CHECK_RET_RELEASE(ret, message...) \
76if (ret != EOK) { \
77 usb_log_error(message); \
78 hc_remove_endpoint(instance, hub_address, 0, USB_DIRECTION_BOTH); \
79 usb_device_keeper_release(&instance->manager, hub_address); \
80 return ret; \
81} else (void)0
82
83 int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
84 USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
85 CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret);
86
87 char *match_str = NULL;
88 /* DDF needs heap allocated string */
89 ret = asprintf(&match_str, "usb&class=hub");
90 ret = ret > 0 ? 0 : ret;
91 CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret);
92
93 ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
94 CHECK_RET_RELEASE(ret, "Failed(%d) add root hub match-id.\n", ret);
95
96 ret = ddf_fun_bind(hub_fun);
97 CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret);
98
99 return EOK;
100#undef CHECK_RET_RELEASE
101}
102/*----------------------------------------------------------------------------*/
103/** Initialize OHCI hc driver structure
104 *
105 * @param[in] instance Memory place for the structure.
106 * @param[in] regs Address of the memory mapped I/O registers.
107 * @param[in] reg_size Size of the memory mapped area.
108 * @param[in] interrupts True if w interrupts should be used
109 * @return Error code
110 */
111int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts)
112{
113 assert(instance);
114 int ret = EOK;
115#define CHECK_RET_RETURN(ret, message...) \
116if (ret != EOK) { \
117 usb_log_error(message); \
118 return ret; \
119} else (void)0
120
121 ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers);
122 CHECK_RET_RETURN(ret,
123 "Failed(%d) to gain access to device registers: %s.\n",
124 ret, str_error(ret));
125
126 list_initialize(&instance->pending_batches);
127 usb_device_keeper_init(&instance->manager);
128 ret = usb_endpoint_manager_init(&instance->ep_manager,
129 BANDWIDTH_AVAILABLE_USB11);
130 CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
131 str_error(ret));
132
133 ret = hc_init_memory(instance);
134 CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures: %s.\n",
135 str_error(ret));
136#undef CHECK_RET_RETURN
137
138 fibril_mutex_initialize(&instance->guard);
139 hc_gain_control(instance);
140
141 rh_init(&instance->rh, instance->registers);
142
143 if (!interrupts) {
144 instance->interrupt_emulator =
145 fibril_create((int(*)(void*))interrupt_emulator, instance);
146 fibril_add_ready(instance->interrupt_emulator);
147 }
148
149 return EOK;
150}
151/*----------------------------------------------------------------------------*/
152/** Create end register endpoint structures
153 *
154 * @param[in] instance OHCI driver structure.
155 * @param[in] address USB address of the device.
156 * @param[in] endpoint USB endpoint number.
157 * @param[in] speed Communication speeed of the device.
158 * @param[in] type Endpoint's transfer type.
159 * @param[in] direction Endpoint's direction.
160 * @param[in] mps Maximum packet size the endpoint accepts.
161 * @param[in] size Maximum allowed buffer size.
162 * @param[in] interval Time between transfers(interrupt transfers only).
163 * @return Error code
164 */
165int hc_add_endpoint(
166 hc_t *instance, usb_address_t address, usb_endpoint_t endpoint,
167 usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
168 size_t mps, size_t size, unsigned interval)
169{
170 endpoint_t *ep = malloc(sizeof(endpoint_t));
171 if (ep == NULL)
172 return ENOMEM;
173 int ret =
174 endpoint_init(ep, address, endpoint, direction, type, speed, mps);
175 if (ret != EOK) {
176 free(ep);
177 return ret;
178 }
179
180 hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
181 if (hcd_ep == NULL) {
182 endpoint_destroy(ep);
183 return ENOMEM;
184 }
185
186 ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
187 if (ret != EOK) {
188 hcd_endpoint_clear(ep);
189 endpoint_destroy(ep);
190 return ret;
191 }
192
193 /* Enqueue hcd_ep */
194 switch (ep->transfer_type) {
195 case USB_TRANSFER_CONTROL:
196 instance->registers->control &= ~C_CLE;
197 endpoint_list_add_ep(
198 &instance->lists[ep->transfer_type], hcd_ep);
199 instance->registers->control_current = 0;
200 instance->registers->control |= C_CLE;
201 break;
202 case USB_TRANSFER_BULK:
203 instance->registers->control &= ~C_BLE;
204 endpoint_list_add_ep(
205 &instance->lists[ep->transfer_type], hcd_ep);
206 instance->registers->control |= C_BLE;
207 break;
208 case USB_TRANSFER_ISOCHRONOUS:
209 case USB_TRANSFER_INTERRUPT:
210 instance->registers->control &= (~C_PLE & ~C_IE);
211 endpoint_list_add_ep(
212 &instance->lists[ep->transfer_type], hcd_ep);
213 instance->registers->control |= C_PLE | C_IE;
214 break;
215 default:
216 break;
217 }
218
219 return EOK;
220}
221/*----------------------------------------------------------------------------*/
222/** Dequeue and delete endpoint structures
223 *
224 * @param[in] instance OHCI hc driver structure.
225 * @param[in] address USB address of the device.
226 * @param[in] endpoint USB endpoint number.
227 * @param[in] direction Direction of the endpoint.
228 * @return Error code
229 */
230int hc_remove_endpoint(hc_t *instance, usb_address_t address,
231 usb_endpoint_t endpoint, usb_direction_t direction)
232{
233 assert(instance);
234 fibril_mutex_lock(&instance->guard);
235 endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
236 address, endpoint, direction, NULL);
237 if (ep == NULL) {
238 usb_log_error("Endpoint unregister failed: No such EP.\n");
239 fibril_mutex_unlock(&instance->guard);
240 return ENOENT;
241 }
242
243 hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
244 if (hcd_ep) {
245 /* Dequeue hcd_ep */
246 switch (ep->transfer_type) {
247 case USB_TRANSFER_CONTROL:
248 instance->registers->control &= ~C_CLE;
249 endpoint_list_remove_ep(
250 &instance->lists[ep->transfer_type], hcd_ep);
251 instance->registers->control_current = 0;
252 instance->registers->control |= C_CLE;
253 break;
254 case USB_TRANSFER_BULK:
255 instance->registers->control &= ~C_BLE;
256 endpoint_list_remove_ep(
257 &instance->lists[ep->transfer_type], hcd_ep);
258 instance->registers->control |= C_BLE;
259 break;
260 case USB_TRANSFER_ISOCHRONOUS:
261 case USB_TRANSFER_INTERRUPT:
262 instance->registers->control &= (~C_PLE & ~C_IE);
263 endpoint_list_remove_ep(
264 &instance->lists[ep->transfer_type], hcd_ep);
265 instance->registers->control |= C_PLE | C_IE;
266 break;
267 default:
268 break;
269 }
270 hcd_endpoint_clear(ep);
271 } else {
272 usb_log_warning("Endpoint without hcd equivalent structure.\n");
273 }
274 int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager,
275 address, endpoint, direction);
276 fibril_mutex_unlock(&instance->guard);
277 return ret;
278}
279/*----------------------------------------------------------------------------*/
280/** Get access to endpoint structures
281 *
282 * @param[in] instance OHCI hc driver structure.
283 * @param[in] address USB address of the device.
284 * @param[in] endpoint USB endpoint number.
285 * @param[in] direction Direction of the endpoint.
286 * @param[out] bw Reserved bandwidth.
287 * @return Error code
288 */
289endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
290 usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw)
291{
292 assert(instance);
293 fibril_mutex_lock(&instance->guard);
294 endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
295 address, endpoint, direction, bw);
296 fibril_mutex_unlock(&instance->guard);
297 return ep;
298}
299/*----------------------------------------------------------------------------*/
300/** Add USB transfer to the schedule.
301 *
302 * @param[in] instance OHCI hc driver structure.
303 * @param[in] batch Batch representing the transfer.
304 * @return Error code.
305 */
306int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
307{
308 assert(instance);
309 assert(batch);
310 assert(batch->ep);
311
312 /* Check for root hub communication */
313 if (batch->ep->address == instance->rh.address) {
314 return rh_request(&instance->rh, batch);
315 }
316
317 fibril_mutex_lock(&instance->guard);
318 list_append(&batch->link, &instance->pending_batches);
319 batch_commit(batch);
320
321 /* Control and bulk schedules need a kick to start working */
322 switch (batch->ep->transfer_type)
323 {
324 case USB_TRANSFER_CONTROL:
325 instance->registers->command_status |= CS_CLF;
326 break;
327 case USB_TRANSFER_BULK:
328 instance->registers->command_status |= CS_BLF;
329 break;
330 default:
331 break;
332 }
333 fibril_mutex_unlock(&instance->guard);
334 return EOK;
335}
336/*----------------------------------------------------------------------------*/
337/** Interrupt handling routine
338 *
339 * @param[in] instance OHCI hc driver structure.
340 * @param[in] status Value of the status register at the time of interrupt.
341 */
342void hc_interrupt(hc_t *instance, uint32_t status)
343{
344 assert(instance);
345 if ((status & ~I_SF) == 0) /* ignore sof status */
346 return;
347 usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status);
348 if (status & I_RHSC)
349 rh_interrupt(&instance->rh);
350
351 if (status & I_WDH) {
352 fibril_mutex_lock(&instance->guard);
353 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca,
354 instance->registers->hcca,
355 (void *) addr_to_phys(instance->hcca));
356 usb_log_debug2("Periodic current: %#" PRIx32 ".\n",
357 instance->registers->periodic_current);
358
359 link_t *current = instance->pending_batches.next;
360 while (current != &instance->pending_batches) {
361 link_t *next = current->next;
362 usb_transfer_batch_t *batch =
363 usb_transfer_batch_from_link(current);
364
365 if (batch_is_complete(batch)) {
366 list_remove(current);
367 usb_transfer_batch_finish(batch);
368 }
369 current = next;
370 }
371 fibril_mutex_unlock(&instance->guard);
372 }
373
374 if (status & I_UE) {
375 hc_start_hw(instance);
376 }
377
378}
379/*----------------------------------------------------------------------------*/
380/** Check status register regularly
381 *
382 * @param[in] instance OHCI hc driver structure.
383 * @return Error code
384 */
385int interrupt_emulator(hc_t *instance)
386{
387 assert(instance);
388 usb_log_info("Started interrupt emulator.\n");
389 while (1) {
390 const uint32_t status = instance->registers->interrupt_status;
391 instance->registers->interrupt_status = status;
392 hc_interrupt(instance, status);
393 async_usleep(10000);
394 }
395 return EOK;
396}
397/*----------------------------------------------------------------------------*/
398/** Turn off any (BIOS)driver that might be in control of the device.
399 *
400 * @param[in] instance OHCI hc driver structure.
401 */
402void hc_gain_control(hc_t *instance)
403{
404 assert(instance);
405 usb_log_debug("Requesting OHCI control.\n");
406 /* Turn off legacy emulation */
407 volatile uint32_t *ohci_emulation_reg =
408 (uint32_t*)((char*)instance->registers + 0x100);
409 usb_log_debug("OHCI legacy register %p: %x.\n",
410 ohci_emulation_reg, *ohci_emulation_reg);
411 /* Do not change A20 state */
412 *ohci_emulation_reg &= 0x100;
413 usb_log_debug("OHCI legacy register %p: %x.\n",
414 ohci_emulation_reg, *ohci_emulation_reg);
415
416 /* Interrupt routing enabled => smm driver is active */
417 if (instance->registers->control & C_IR) {
418 usb_log_debug("SMM driver: request ownership change.\n");
419 instance->registers->command_status |= CS_OCR;
420 while (instance->registers->control & C_IR) {
421 async_usleep(1000);
422 }
423 usb_log_info("SMM driver: Ownership taken.\n");
424 instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
425 async_usleep(50000);
426 return;
427 }
428
429 const unsigned hc_status =
430 (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
431 /* Interrupt routing disabled && status != USB_RESET => BIOS active */
432 if (hc_status != C_HCFS_RESET) {
433 usb_log_debug("BIOS driver found.\n");
434 if (hc_status == C_HCFS_OPERATIONAL) {
435 usb_log_info("BIOS driver: HC operational.\n");
436 return;
437 }
438 /* HC is suspended assert resume for 20ms */
439 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
440 async_usleep(20000);
441 usb_log_info("BIOS driver: HC resumed.\n");
442 return;
443 }
444
445 /* HC is in reset (hw startup) => no other driver
446 * maintain reset for at least the time specified in USB spec (50 ms)*/
447 usb_log_debug("Host controller found in reset state.\n");
448 async_usleep(50000);
449}
450/*----------------------------------------------------------------------------*/
451/** OHCI hw initialization routine.
452 *
453 * @param[in] instance OHCI hc driver structure.
454 */
455void hc_start_hw(hc_t *instance)
456{
457 /* OHCI guide page 42 */
458 assert(instance);
459 usb_log_debug2("Started hc initialization routine.\n");
460
461 /* Save contents of fm_interval register */
462 const uint32_t fm_interval = instance->registers->fm_interval;
463 usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
464
465 /* Reset hc */
466 usb_log_debug2("HC reset.\n");
467 size_t time = 0;
468 instance->registers->command_status = CS_HCR;
469 while (instance->registers->command_status & CS_HCR) {
470 async_usleep(10);
471 time += 10;
472 }
473 usb_log_debug2("HC reset complete in %zu us.\n", time);
474
475 /* Restore fm_interval */
476 instance->registers->fm_interval = fm_interval;
477 assert((instance->registers->command_status & CS_HCR) == 0);
478
479 /* hc is now in suspend state */
480 usb_log_debug2("HC should be in suspend state(%x).\n",
481 instance->registers->control);
482
483 /* Use HCCA */
484 instance->registers->hcca = addr_to_phys(instance->hcca);
485
486 /* Use queues */
487 instance->registers->bulk_head =
488 instance->lists[USB_TRANSFER_BULK].list_head_pa;
489 usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n",
490 instance->lists[USB_TRANSFER_BULK].list_head,
491 instance->lists[USB_TRANSFER_BULK].list_head_pa);
492
493 instance->registers->control_head =
494 instance->lists[USB_TRANSFER_CONTROL].list_head_pa;
495 usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n",
496 instance->lists[USB_TRANSFER_CONTROL].list_head,
497 instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
498
499 /* Enable queues */
500 instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);
501 usb_log_debug2("All queues enabled(%x).\n",
502 instance->registers->control);
503
504 /* Enable interrupts */
505 instance->registers->interrupt_enable = OHCI_USED_INTERRUPTS;
506 usb_log_debug2("Enabled interrupts: %x.\n",
507 instance->registers->interrupt_enable);
508 instance->registers->interrupt_enable = I_MI;
509
510 /* Set periodic start to 90% */
511 uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK);
512 instance->registers->periodic_start = (frame_length / 10) * 9;
513 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
514 instance->registers->periodic_start,
515 instance->registers->periodic_start, frame_length);
516
517 instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
518 usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
519 instance->registers->control);
520}
521/*----------------------------------------------------------------------------*/
522/** Initialize schedule queues
523 *
524 * @param[in] instance OHCI hc driver structure
525 * @return Error code
526 */
527int hc_init_transfer_lists(hc_t *instance)
528{
529 assert(instance);
530#define SETUP_ENDPOINT_LIST(type) \
531do { \
532 const char *name = usb_str_transfer_type(type); \
533 int ret = endpoint_list_init(&instance->lists[type], name); \
534 if (ret != EOK) { \
535 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
536 ret, name); \
537 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
538 endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
539 endpoint_list_fini(&instance->lists[USB_TRANSFER_CONTROL]); \
540 endpoint_list_fini(&instance->lists[USB_TRANSFER_BULK]); \
541 return ret; \
542 } \
543} while (0)
544
545 SETUP_ENDPOINT_LIST(USB_TRANSFER_ISOCHRONOUS);
546 SETUP_ENDPOINT_LIST(USB_TRANSFER_INTERRUPT);
547 SETUP_ENDPOINT_LIST(USB_TRANSFER_CONTROL);
548 SETUP_ENDPOINT_LIST(USB_TRANSFER_BULK);
549#undef SETUP_ENDPOINT_LIST
550 endpoint_list_set_next(&instance->lists[USB_TRANSFER_INTERRUPT],
551 &instance->lists[USB_TRANSFER_ISOCHRONOUS]);
552
553 return EOK;
554}
555/*----------------------------------------------------------------------------*/
556/** Initialize memory structures used by the OHCI hcd.
557 *
558 * @param[in] instance OHCI hc driver structure.
559 * @return Error code.
560 */
561int hc_init_memory(hc_t *instance)
562{
563 assert(instance);
564
565 bzero(&instance->rh, sizeof(instance->rh));
566 /* Init queues */
567 const int ret = hc_init_transfer_lists(instance);
568 if (ret != EOK) {
569 return ret;
570 }
571
572 /*Init HCCA */
573 instance->hcca = malloc32(sizeof(hcca_t));
574 if (instance->hcca == NULL)
575 return ENOMEM;
576 bzero(instance->hcca, sizeof(hcca_t));
577 usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
578
579 unsigned i = 0;
580 for (; i < 32; ++i) {
581 instance->hcca->int_ep[i] =
582 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
583 }
584 usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
585 instance->lists[USB_TRANSFER_INTERRUPT].list_head,
586 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
587
588 /* Init interrupt code */
589 instance->interrupt_code.cmds = instance->interrupt_commands;
590 instance->interrupt_code.cmdcount = OHCI_NEEDED_IRQ_COMMANDS;
591 {
592 /* Read status register */
593 instance->interrupt_commands[0].cmd = CMD_MEM_READ_32;
594 instance->interrupt_commands[0].dstarg = 1;
595 instance->interrupt_commands[0].addr =
596 (void*)&instance->registers->interrupt_status;
597
598 /* Test whether we are the interrupt cause */
599 instance->interrupt_commands[1].cmd = CMD_BTEST;
600 instance->interrupt_commands[1].value =
601 OHCI_USED_INTERRUPTS;
602 instance->interrupt_commands[1].srcarg = 1;
603 instance->interrupt_commands[1].dstarg = 2;
604
605 /* Predicate cleaning and accepting */
606 instance->interrupt_commands[2].cmd = CMD_PREDICATE;
607 instance->interrupt_commands[2].value = 2;
608 instance->interrupt_commands[2].srcarg = 2;
609
610 /* Write-clean status register */
611 instance->interrupt_commands[3].cmd = CMD_MEM_WRITE_A_32;
612 instance->interrupt_commands[3].srcarg = 1;
613 instance->interrupt_commands[3].addr =
614 (void*)&instance->registers->interrupt_status;
615
616 /* Accept interrupt */
617 instance->interrupt_commands[4].cmd = CMD_ACCEPT;
618 }
619
620 return EOK;
621}
622/**
623 * @}
624 */
Note: See TracBrowser for help on using the repository browser.