source: mainline/uspace/drv/pciintel/pci.c@ 969585f

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

Merge mainline changes

  • Property mode set to 100644
File size: 17.4 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/**
31 * @defgroup pciintel pci bus driver for intel method 1.
32 * @brief HelenOS root pci bus driver for intel method 1.
33 * @{
34 */
35
36/** @file
37 */
38
39#include <assert.h>
40#include <stdio.h>
41#include <errno.h>
42#include <bool.h>
43#include <fibril_synch.h>
44#include <str.h>
45#include <ctype.h>
46#include <macros.h>
47#include <str_error.h>
48
49#include <ddf/driver.h>
50#include <ddf/log.h>
51#include <devman.h>
52#include <ipc/devman.h>
53#include <ipc/dev_iface.h>
54#include <ipc/irc.h>
55#include <ipc/ns.h>
56#include <ipc/services.h>
57#include <sysinfo.h>
58#include <ops/hw_res.h>
59#include <device/hw_res.h>
60#include <ddi.h>
61#include <libarch/ddi.h>
62#include <pci_dev_iface.h>
63
64#include "pci.h"
65
66#define NAME "pciintel"
67
68#define CONF_ADDR(bus, dev, fn, reg) \
69 ((1 << 31) | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
70
71/** Obtain PCI function soft-state from DDF function node */
72#define PCI_FUN(fnode) ((pci_fun_t *) (fnode)->driver_data)
73
74/** Obtain PCI bus soft-state from DDF device node */
75#define PCI_BUS(dnode) ((pci_bus_t *) (dnode)->driver_data)
76
77/** Obtain PCI bus soft-state from function soft-state */
78#define PCI_BUS_FROM_FUN(fun) ((fun)->busptr)
79
80static hw_resource_list_t *pciintel_get_resources(ddf_fun_t *fnode)
81{
82 pci_fun_t *fun = PCI_FUN(fnode);
83
84 if (fun == NULL)
85 return NULL;
86 return &fun->hw_resources;
87}
88
89static bool pciintel_enable_interrupt(ddf_fun_t *fnode)
90{
91 /* This is an old ugly way, copied from ne2000 driver */
92 assert(fnode);
93 pci_fun_t *dev_data = (pci_fun_t *) fnode->driver_data;
94
95 sysarg_t apic;
96 sysarg_t i8259;
97
98 int irc_phone = ENOTSUP;
99
100 if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
101 || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))) {
102 irc_phone = service_connect_blocking(SERVICE_IRC, 0, 0);
103 }
104
105 if (irc_phone < 0) {
106 return false;
107 }
108
109 size_t i;
110 for (i = 0; i < dev_data->hw_resources.count; i++) {
111 if (dev_data->hw_resources.resources[i].type == INTERRUPT) {
112 int irq = dev_data->hw_resources.resources[i].res.interrupt.irq;
113 int rc = async_req_1_0(irc_phone, IRC_ENABLE_INTERRUPT, irq);
114 if (rc != EOK) {
115 async_hangup(irc_phone);
116 return false;
117 }
118 }
119 }
120
121 async_hangup(irc_phone);
122 return true;
123}
124
125static int pci_config_space_write_32(
126 ddf_fun_t *fun, uint32_t address, uint32_t data)
127{
128 if (address > 252)
129 return EINVAL;
130 pci_conf_write_32(PCI_FUN(fun), address, data);
131 return EOK;
132}
133
134static int pci_config_space_write_16(
135 ddf_fun_t *fun, uint32_t address, uint16_t data)
136{
137 if (address > 254)
138 return EINVAL;
139 pci_conf_write_16(PCI_FUN(fun), address, data);
140 return EOK;
141}
142
143static int pci_config_space_write_8(
144 ddf_fun_t *fun, uint32_t address, uint8_t data)
145{
146 if (address > 255)
147 return EINVAL;
148 pci_conf_write_8(PCI_FUN(fun), address, data);
149 return EOK;
150}
151
152static int pci_config_space_read_32(
153 ddf_fun_t *fun, uint32_t address, uint32_t *data)
154{
155 if (address > 252)
156 return EINVAL;
157 *data = pci_conf_read_32(PCI_FUN(fun), address);
158 return EOK;
159}
160
161static int pci_config_space_read_16(
162 ddf_fun_t *fun, uint32_t address, uint16_t *data)
163{
164 if (address > 254)
165 return EINVAL;
166 *data = pci_conf_read_16(PCI_FUN(fun), address);
167 return EOK;
168}
169
170static int pci_config_space_read_8(
171 ddf_fun_t *fun, uint32_t address, uint8_t *data)
172{
173 if (address > 255)
174 return EINVAL;
175 *data = pci_conf_read_8(PCI_FUN(fun), address);
176 return EOK;
177}
178
179static hw_res_ops_t pciintel_hw_res_ops = {
180 &pciintel_get_resources,
181 &pciintel_enable_interrupt
182};
183
184static pci_dev_iface_t pci_dev_ops = {
185 .config_space_read_8 = &pci_config_space_read_8,
186 .config_space_read_16 = &pci_config_space_read_16,
187 .config_space_read_32 = &pci_config_space_read_32,
188 .config_space_write_8 = &pci_config_space_write_8,
189 .config_space_write_16 = &pci_config_space_write_16,
190 .config_space_write_32 = &pci_config_space_write_32
191};
192
193static ddf_dev_ops_t pci_fun_ops = {
194 .interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops,
195 .interfaces[PCI_DEV_IFACE] = &pci_dev_ops
196};
197
198static int pci_add_device(ddf_dev_t *);
199
200/** PCI bus driver standard operations */
201static driver_ops_t pci_ops = {
202 .add_device = &pci_add_device
203};
204
205/** PCI bus driver structure */
206static driver_t pci_driver = {
207 .name = NAME,
208 .driver_ops = &pci_ops
209};
210
211static pci_bus_t *pci_bus_new(void)
212{
213 pci_bus_t *bus;
214
215 bus = (pci_bus_t *) calloc(1, sizeof(pci_bus_t));
216 if (bus == NULL)
217 return NULL;
218
219 fibril_mutex_initialize(&bus->conf_mutex);
220 return bus;
221}
222
223static void pci_bus_delete(pci_bus_t *bus)
224{
225 assert(bus != NULL);
226 free(bus);
227}
228
229static void pci_conf_read(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
230{
231 pci_bus_t *bus = PCI_BUS_FROM_FUN(fun);
232
233 fibril_mutex_lock(&bus->conf_mutex);
234
235 uint32_t conf_addr;
236 conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
237 void *addr = bus->conf_data_port + (reg & 3);
238
239 pio_write_32(bus->conf_addr_port, conf_addr);
240
241 switch (len) {
242 case 1:
243 buf[0] = pio_read_8(addr);
244 break;
245 case 2:
246 ((uint16_t *) buf)[0] = pio_read_16(addr);
247 break;
248 case 4:
249 ((uint32_t *) buf)[0] = pio_read_32(addr);
250 break;
251 }
252
253 fibril_mutex_unlock(&bus->conf_mutex);
254}
255
256static void pci_conf_write(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
257{
258 pci_bus_t *bus = PCI_BUS_FROM_FUN(fun);
259
260 fibril_mutex_lock(&bus->conf_mutex);
261
262 uint32_t conf_addr;
263 conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
264 void *addr = bus->conf_data_port + (reg & 3);
265
266 pio_write_32(bus->conf_addr_port, conf_addr);
267
268 switch (len) {
269 case 1:
270 pio_write_8(addr, buf[0]);
271 break;
272 case 2:
273 pio_write_16(addr, ((uint16_t *) buf)[0]);
274 break;
275 case 4:
276 pio_write_32(addr, ((uint32_t *) buf)[0]);
277 break;
278 }
279
280 fibril_mutex_unlock(&bus->conf_mutex);
281}
282
283uint8_t pci_conf_read_8(pci_fun_t *fun, int reg)
284{
285 uint8_t res;
286 pci_conf_read(fun, reg, &res, 1);
287 return res;
288}
289
290uint16_t pci_conf_read_16(pci_fun_t *fun, int reg)
291{
292 uint16_t res;
293 pci_conf_read(fun, reg, (uint8_t *) &res, 2);
294 return res;
295}
296
297uint32_t pci_conf_read_32(pci_fun_t *fun, int reg)
298{
299 uint32_t res;
300 pci_conf_read(fun, reg, (uint8_t *) &res, 4);
301 return res;
302}
303
304void pci_conf_write_8(pci_fun_t *fun, int reg, uint8_t val)
305{
306 pci_conf_write(fun, reg, (uint8_t *) &val, 1);
307}
308
309void pci_conf_write_16(pci_fun_t *fun, int reg, uint16_t val)
310{
311 pci_conf_write(fun, reg, (uint8_t *) &val, 2);
312}
313
314void pci_conf_write_32(pci_fun_t *fun, int reg, uint32_t val)
315{
316 pci_conf_write(fun, reg, (uint8_t *) &val, 4);
317}
318
319void pci_fun_create_match_ids(pci_fun_t *fun)
320{
321 char *match_id_str;
322 int rc;
323
324 asprintf(&match_id_str, "pci/ven=%04x&dev=%04x",
325 fun->vendor_id, fun->device_id);
326
327 if (match_id_str == NULL) {
328 ddf_msg(LVL_ERROR, "Out of memory creating match ID.");
329 return;
330 }
331
332 rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 90);
333 if (rc != EOK) {
334 ddf_msg(LVL_ERROR, "Failed adding match ID: %s",
335 str_error(rc));
336 }
337
338 /* TODO add more ids (with subsys ids, using class id etc.) */
339}
340
341void pci_add_range(pci_fun_t *fun, uint64_t range_addr, size_t range_size,
342 bool io)
343{
344 hw_resource_list_t *hw_res_list = &fun->hw_resources;
345 hw_resource_t *hw_resources = hw_res_list->resources;
346 size_t count = hw_res_list->count;
347
348 assert(hw_resources != NULL);
349 assert(count < PCI_MAX_HW_RES);
350
351 if (io) {
352 hw_resources[count].type = IO_RANGE;
353 hw_resources[count].res.io_range.address = range_addr;
354 hw_resources[count].res.io_range.size = range_size;
355 hw_resources[count].res.io_range.endianness = LITTLE_ENDIAN;
356 } else {
357 hw_resources[count].type = MEM_RANGE;
358 hw_resources[count].res.mem_range.address = range_addr;
359 hw_resources[count].res.mem_range.size = range_size;
360 hw_resources[count].res.mem_range.endianness = LITTLE_ENDIAN;
361 }
362
363 hw_res_list->count++;
364}
365
366/** Read the base address register (BAR) of the device and if it contains valid
367 * address add it to the devices hw resource list.
368 *
369 * @param fun PCI function
370 * @param addr The address of the BAR in the PCI configuration address space of
371 * the device
372 * @return The addr the address of the BAR which should be read next
373 */
374int pci_read_bar(pci_fun_t *fun, int addr)
375{
376 /* Value of the BAR */
377 uint32_t val, mask;
378 /* IO space address */
379 bool io;
380 /* 64-bit wide address */
381 bool addrw64;
382
383 /* Size of the io or memory range specified by the BAR */
384 size_t range_size;
385 /* Beginning of the io or memory range specified by the BAR */
386 uint64_t range_addr;
387
388 /* Get the value of the BAR. */
389 val = pci_conf_read_32(fun, addr);
390
391#define IO_MASK (~0x3)
392#define MEM_MASK (~0xf)
393
394 io = (bool) (val & 1);
395 if (io) {
396 addrw64 = false;
397 mask = IO_MASK;
398 } else {
399 mask = MEM_MASK;
400 switch ((val >> 1) & 3) {
401 case 0:
402 addrw64 = false;
403 break;
404 case 2:
405 addrw64 = true;
406 break;
407 default:
408 /* reserved, go to the next BAR */
409 return addr + 4;
410 }
411 }
412
413 /* Get the address mask. */
414 pci_conf_write_32(fun, addr, 0xffffffff);
415 mask &= pci_conf_read_32(fun, addr);
416
417 /* Restore the original value. */
418 pci_conf_write_32(fun, addr, val);
419 val = pci_conf_read_32(fun, addr);
420
421 range_size = pci_bar_mask_to_size(mask);
422
423 if (addrw64) {
424 range_addr = ((uint64_t)pci_conf_read_32(fun, addr + 4) << 32) |
425 (val & 0xfffffff0);
426 } else {
427 range_addr = (val & 0xfffffff0);
428 }
429
430 if (range_addr != 0) {
431 ddf_msg(LVL_DEBUG, "Function %s : address = %" PRIx64
432 ", size = %x", fun->fnode->name, range_addr,
433 (unsigned int) range_size);
434 }
435
436 pci_add_range(fun, range_addr, range_size, io);
437
438 if (addrw64)
439 return addr + 8;
440
441 return addr + 4;
442}
443
444void pci_add_interrupt(pci_fun_t *fun, int irq)
445{
446 hw_resource_list_t *hw_res_list = &fun->hw_resources;
447 hw_resource_t *hw_resources = hw_res_list->resources;
448 size_t count = hw_res_list->count;
449
450 assert(NULL != hw_resources);
451 assert(count < PCI_MAX_HW_RES);
452
453 hw_resources[count].type = INTERRUPT;
454 hw_resources[count].res.interrupt.irq = irq;
455
456 hw_res_list->count++;
457
458 ddf_msg(LVL_NOTE, "Function %s uses irq %x.", fun->fnode->name, irq);
459}
460
461void pci_read_interrupt(pci_fun_t *fun)
462{
463 uint8_t irq = pci_conf_read_8(fun, PCI_BRIDGE_INT_LINE);
464 if (irq != 0xff)
465 pci_add_interrupt(fun, irq);
466}
467
468/** Enumerate (recursively) and register the devices connected to a pci bus.
469 *
470 * @param bus Host-to-PCI bridge
471 * @param bus_num Bus number
472 */
473void pci_bus_scan(pci_bus_t *bus, int bus_num)
474{
475 ddf_fun_t *fnode;
476 pci_fun_t *fun;
477
478 int child_bus = 0;
479 int dnum, fnum;
480 bool multi;
481 uint8_t header_type;
482
483 fun = pci_fun_new(bus);
484
485 for (dnum = 0; dnum < 32; dnum++) {
486 multi = true;
487 for (fnum = 0; multi && fnum < 8; fnum++) {
488 pci_fun_init(fun, bus_num, dnum, fnum);
489 fun->vendor_id = pci_conf_read_16(fun,
490 PCI_VENDOR_ID);
491 fun->device_id = pci_conf_read_16(fun,
492 PCI_DEVICE_ID);
493 if (fun->vendor_id == 0xffff) {
494 /*
495 * The device is not present, go on scanning the
496 * bus.
497 */
498 if (fnum == 0)
499 break;
500 else
501 continue;
502 }
503
504 header_type = pci_conf_read_8(fun, PCI_HEADER_TYPE);
505 if (fnum == 0) {
506 /* Is the device multifunction? */
507 multi = header_type >> 7;
508 }
509 /* Clear the multifunction bit. */
510 header_type = header_type & 0x7F;
511
512 char *fun_name = pci_fun_create_name(fun);
513 if (fun_name == NULL) {
514 ddf_msg(LVL_ERROR, "Out of memory.");
515 return;
516 }
517
518 fnode = ddf_fun_create(bus->dnode, fun_inner, fun_name);
519 if (fnode == NULL) {
520 ddf_msg(LVL_ERROR, "Failed creating function.");
521 return;
522 }
523
524 free(fun_name);
525 fun->fnode = fnode;
526
527 pci_alloc_resource_list(fun);
528 pci_read_bars(fun);
529 pci_read_interrupt(fun);
530
531 fnode->ops = &pci_fun_ops;
532 fnode->driver_data = fun;
533
534 ddf_msg(LVL_DEBUG, "Adding new function %s.",
535 fnode->name);
536
537 pci_fun_create_match_ids(fun);
538
539 if (ddf_fun_bind(fnode) != EOK) {
540 pci_clean_resource_list(fun);
541 clean_match_ids(&fnode->match_ids);
542 free((char *) fnode->name);
543 fnode->name = NULL;
544 continue;
545 }
546
547 if (header_type == PCI_HEADER_TYPE_BRIDGE ||
548 header_type == PCI_HEADER_TYPE_CARDBUS) {
549 child_bus = pci_conf_read_8(fun,
550 PCI_BRIDGE_SEC_BUS_NUM);
551 ddf_msg(LVL_DEBUG, "Device is pci-to-pci "
552 "bridge, secondary bus number = %d.",
553 bus_num);
554 if (child_bus > bus_num)
555 pci_bus_scan(bus, child_bus);
556 }
557
558 fun = pci_fun_new(bus);
559 }
560 }
561
562 if (fun->vendor_id == 0xffff) {
563 /* Free the auxiliary function structure. */
564 pci_fun_delete(fun);
565 }
566}
567
568static int pci_add_device(ddf_dev_t *dnode)
569{
570 pci_bus_t *bus = NULL;
571 ddf_fun_t *ctl = NULL;
572 bool got_res = false;
573 int rc;
574
575 ddf_msg(LVL_DEBUG, "pci_add_device");
576 dnode->parent_phone = -1;
577
578 bus = pci_bus_new();
579 if (bus == NULL) {
580 ddf_msg(LVL_ERROR, "pci_add_device allocation failed.");
581 rc = ENOMEM;
582 goto fail;
583 }
584 bus->dnode = dnode;
585 dnode->driver_data = bus;
586
587 dnode->parent_phone = devman_parent_device_connect(dnode->handle,
588 IPC_FLAG_BLOCKING);
589 if (dnode->parent_phone < 0) {
590 ddf_msg(LVL_ERROR, "pci_add_device failed to connect to the "
591 "parent's driver.");
592 rc = dnode->parent_phone;
593 goto fail;
594 }
595
596 hw_resource_list_t hw_resources;
597
598 rc = hw_res_get_resource_list(dnode->parent_phone, &hw_resources);
599 if (rc != EOK) {
600 ddf_msg(LVL_ERROR, "pci_add_device failed to get hw resources "
601 "for the device.");
602 goto fail;
603 }
604 got_res = true;
605
606 ddf_msg(LVL_DEBUG, "conf_addr = %" PRIx64 ".",
607 hw_resources.resources[0].res.io_range.address);
608
609 assert(hw_resources.count > 0);
610 assert(hw_resources.resources[0].type == IO_RANGE);
611 assert(hw_resources.resources[0].res.io_range.size == 8);
612
613 bus->conf_io_addr =
614 (uint32_t) hw_resources.resources[0].res.io_range.address;
615
616 if (pio_enable((void *)(uintptr_t)bus->conf_io_addr, 8,
617 &bus->conf_addr_port)) {
618 ddf_msg(LVL_ERROR, "Failed to enable configuration ports.");
619 rc = EADDRNOTAVAIL;
620 goto fail;
621 }
622 bus->conf_data_port = (char *) bus->conf_addr_port + 4;
623
624 /* Make the bus device more visible. It has no use yet. */
625 ddf_msg(LVL_DEBUG, "Adding a 'ctl' function");
626
627 ctl = ddf_fun_create(bus->dnode, fun_exposed, "ctl");
628 if (ctl == NULL) {
629 ddf_msg(LVL_ERROR, "Failed creating control function.");
630 rc = ENOMEM;
631 goto fail;
632 }
633
634 rc = ddf_fun_bind(ctl);
635 if (rc != EOK) {
636 ddf_msg(LVL_ERROR, "Failed binding control function.");
637 goto fail;
638 }
639
640 /* Enumerate functions. */
641 ddf_msg(LVL_DEBUG, "Scanning the bus");
642 pci_bus_scan(bus, 0);
643
644 hw_res_clean_resource_list(&hw_resources);
645
646 return EOK;
647
648fail:
649 if (bus != NULL)
650 pci_bus_delete(bus);
651 if (dnode->parent_phone >= 0)
652 async_hangup(dnode->parent_phone);
653 if (got_res)
654 hw_res_clean_resource_list(&hw_resources);
655 if (ctl != NULL)
656 ddf_fun_destroy(ctl);
657
658 return rc;
659}
660
661static void pciintel_init(void)
662{
663 ddf_log_init(NAME, LVL_ERROR);
664 pci_fun_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops;
665 pci_fun_ops.interfaces[PCI_DEV_IFACE] = &pci_dev_ops;
666}
667
668pci_fun_t *pci_fun_new(pci_bus_t *bus)
669{
670 pci_fun_t *fun;
671
672 fun = (pci_fun_t *) calloc(1, sizeof(pci_fun_t));
673 if (fun == NULL)
674 return NULL;
675
676 fun->busptr = bus;
677 return fun;
678}
679
680void pci_fun_init(pci_fun_t *fun, int bus, int dev, int fn)
681{
682 fun->bus = bus;
683 fun->dev = dev;
684 fun->fn = fn;
685}
686
687void pci_fun_delete(pci_fun_t *fun)
688{
689 assert(fun != NULL);
690 hw_res_clean_resource_list(&fun->hw_resources);
691 free(fun);
692}
693
694char *pci_fun_create_name(pci_fun_t *fun)
695{
696 char *name = NULL;
697
698 asprintf(&name, "%02x:%02x.%01x", fun->bus, fun->dev,
699 fun->fn);
700 return name;
701}
702
703bool pci_alloc_resource_list(pci_fun_t *fun)
704{
705 fun->hw_resources.resources =
706 (hw_resource_t *) malloc(PCI_MAX_HW_RES * sizeof(hw_resource_t));
707 return fun->hw_resources.resources != NULL;
708}
709
710void pci_clean_resource_list(pci_fun_t *fun)
711{
712 if (fun->hw_resources.resources != NULL) {
713 free(fun->hw_resources.resources);
714 fun->hw_resources.resources = NULL;
715 }
716}
717
718/** Read the base address registers (BARs) of the function and add the addresses
719 * to its HW resource list.
720 *
721 * @param fun PCI function
722 */
723void pci_read_bars(pci_fun_t *fun)
724{
725 /*
726 * Position of the BAR in the PCI configuration address space of the
727 * device.
728 */
729 int addr = PCI_BASE_ADDR_0;
730
731 while (addr <= PCI_BASE_ADDR_5)
732 addr = pci_read_bar(fun, addr);
733}
734
735size_t pci_bar_mask_to_size(uint32_t mask)
736{
737 size_t size = mask & ~(mask - 1);
738 return size;
739}
740
741int main(int argc, char *argv[])
742{
743 printf(NAME ": HelenOS PCI bus driver (Intel method 1).\n");
744 pciintel_init();
745 return ddf_driver_main(&pci_driver);
746}
747
748/**
749 * @}
750 */
Note: See TracBrowser for help on using the repository browser.