source: mainline/uspace/drv/ohci/hc.c@ 109d55c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 109d55c was 2df648c2, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

COnst and whitespace fixes, reduce debug output level on interrupt

  • Property mode set to 100644
File size: 19.8 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(%d) to get OHCI root hub address.\n",
68 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_info("HC found in reset.\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_info("OHCI HC up and running(%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.