pci.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 Lenka Trochtova
00003  * Copyright (c) 2011 Jiri Svoboda
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * - Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  * - Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in the
00014  *   documentation and/or other materials provided with the distribution.
00015  * - The name of the author may not be used to endorse or promote products
00016  *   derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00019  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00039 #include <assert.h>
00040 #include <stdio.h>
00041 #include <errno.h>
00042 #include <bool.h>
00043 #include <fibril_synch.h>
00044 #include <str.h>
00045 #include <ctype.h>
00046 #include <macros.h>
00047 #include <str_error.h>
00048 
00049 #include <ddf/driver.h>
00050 #include <ddf/log.h>
00051 #include <devman.h>
00052 #include <ipc/devman.h>
00053 #include <ipc/dev_iface.h>
00054 #include <ipc/irc.h>
00055 #include <ipc/ns.h>
00056 #include <ipc/services.h>
00057 #include <sysinfo.h>
00058 #include <ops/hw_res.h>
00059 #include <device/hw_res.h>
00060 #include <ddi.h>
00061 #include <libarch/ddi.h>
00062 #include <pci_dev_iface.h>
00063 
00064 #include "pci.h"
00065 
00066 #define NAME "pciintel"
00067 
00068 #define CONF_ADDR(bus, dev, fn, reg) \
00069         ((1 << 31) | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
00070 
00072 #define PCI_FUN(fnode) ((pci_fun_t *) (fnode)->driver_data)
00073 
00075 #define PCI_BUS(dnode) ((pci_bus_t *) (dnode)->driver_data)
00076 
00078 #define PCI_BUS_FROM_FUN(fun) ((fun)->busptr)
00079 
00080 static hw_resource_list_t *pciintel_get_resources(ddf_fun_t *fnode)
00081 {
00082         pci_fun_t *fun = PCI_FUN(fnode);
00083         
00084         if (fun == NULL)
00085                 return NULL;
00086         return &fun->hw_resources;
00087 }
00088 
00089 static bool pciintel_enable_interrupt(ddf_fun_t *fnode)
00090 {
00091         /* This is an old ugly way, copied from ne2000 driver */
00092         assert(fnode);
00093         pci_fun_t *dev_data = (pci_fun_t *) fnode->driver_data;
00094 
00095         sysarg_t apic;
00096         sysarg_t i8259;
00097 
00098         int irc_phone = ENOTSUP;
00099 
00100         if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
00101             || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))) {
00102                 irc_phone = service_connect_blocking(SERVICE_IRC, 0, 0);
00103         }
00104 
00105         if (irc_phone < 0) {
00106                 return false;
00107         }
00108 
00109         size_t i = 0;
00110         hw_resource_list_t *res = &dev_data->hw_resources;
00111         for (; i < res->count; i++) {
00112                 if (res->resources[i].type == INTERRUPT) {
00113                         const int irq = res->resources[i].res.interrupt.irq;
00114                         const int rc =
00115                             async_req_1_0(irc_phone, IRC_ENABLE_INTERRUPT, irq);
00116                         if (rc != EOK) {
00117                                 async_hangup(irc_phone);
00118                                 return false;
00119                         }
00120                 }
00121         }
00122 
00123         async_hangup(irc_phone);
00124         return true;
00125 }
00126 
00127 static int pci_config_space_write_32(
00128     ddf_fun_t *fun, uint32_t address, uint32_t data)
00129 {
00130         if (address > 252)
00131                 return EINVAL;
00132         pci_conf_write_32(PCI_FUN(fun), address, data);
00133         return EOK;
00134 }
00135 
00136 static int pci_config_space_write_16(
00137     ddf_fun_t *fun, uint32_t address, uint16_t data)
00138 {
00139         if (address > 254)
00140                 return EINVAL;
00141         pci_conf_write_16(PCI_FUN(fun), address, data);
00142         return EOK;
00143 }
00144 
00145 static int pci_config_space_write_8(
00146     ddf_fun_t *fun, uint32_t address, uint8_t data)
00147 {
00148         if (address > 255)
00149                 return EINVAL;
00150         pci_conf_write_8(PCI_FUN(fun), address, data);
00151         return EOK;
00152 }
00153 
00154 static int pci_config_space_read_32(
00155     ddf_fun_t *fun, uint32_t address, uint32_t *data)
00156 {
00157         if (address > 252)
00158                 return EINVAL;
00159         *data = pci_conf_read_32(PCI_FUN(fun), address);
00160         return EOK;
00161 }
00162 
00163 static int pci_config_space_read_16(
00164     ddf_fun_t *fun, uint32_t address, uint16_t *data)
00165 {
00166         if (address > 254)
00167                 return EINVAL;
00168         *data = pci_conf_read_16(PCI_FUN(fun), address);
00169         return EOK;
00170 }
00171 
00172 static int pci_config_space_read_8(
00173     ddf_fun_t *fun, uint32_t address, uint8_t *data)
00174 {
00175         if (address > 255)
00176                 return EINVAL;
00177         *data = pci_conf_read_8(PCI_FUN(fun), address);
00178         return EOK;
00179 }
00180 
00181 static hw_res_ops_t pciintel_hw_res_ops = {
00182         &pciintel_get_resources,
00183         &pciintel_enable_interrupt
00184 };
00185 
00186 static pci_dev_iface_t pci_dev_ops = {
00187         .config_space_read_8 = &pci_config_space_read_8,
00188         .config_space_read_16 = &pci_config_space_read_16,
00189         .config_space_read_32 = &pci_config_space_read_32,
00190         .config_space_write_8 = &pci_config_space_write_8,
00191         .config_space_write_16 = &pci_config_space_write_16,
00192         .config_space_write_32 = &pci_config_space_write_32
00193 };
00194 
00195 static ddf_dev_ops_t pci_fun_ops = {
00196         .interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops,
00197         .interfaces[PCI_DEV_IFACE] = &pci_dev_ops
00198 };
00199 
00200 static int pci_add_device(ddf_dev_t *);
00201 
00203 static driver_ops_t pci_ops = {
00204         .add_device = &pci_add_device
00205 };
00206 
00208 static driver_t pci_driver = {
00209         .name = NAME,
00210         .driver_ops = &pci_ops
00211 };
00212 
00213 static pci_bus_t *pci_bus_new(void)
00214 {
00215         pci_bus_t *bus;
00216         
00217         bus = (pci_bus_t *) calloc(1, sizeof(pci_bus_t));
00218         if (bus == NULL)
00219                 return NULL;
00220         
00221         fibril_mutex_initialize(&bus->conf_mutex);
00222         return bus;
00223 }
00224 
00225 static void pci_bus_delete(pci_bus_t *bus)
00226 {
00227         assert(bus != NULL);
00228         free(bus);
00229 }
00230 
00231 static void pci_conf_read(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
00232 {
00233         pci_bus_t *bus = PCI_BUS_FROM_FUN(fun);
00234         
00235         fibril_mutex_lock(&bus->conf_mutex);
00236         
00237         uint32_t conf_addr;
00238         conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
00239         void *addr = bus->conf_data_port + (reg & 3);
00240         
00241         pio_write_32(bus->conf_addr_port, conf_addr);
00242         
00243         switch (len) {
00244         case 1:
00245                 buf[0] = pio_read_8(addr);
00246                 break;
00247         case 2:
00248                 ((uint16_t *) buf)[0] = pio_read_16(addr);
00249                 break;
00250         case 4:
00251                 ((uint32_t *) buf)[0] = pio_read_32(addr);
00252                 break;
00253         }
00254         
00255         fibril_mutex_unlock(&bus->conf_mutex);
00256 }
00257 
00258 static void pci_conf_write(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
00259 {
00260         pci_bus_t *bus = PCI_BUS_FROM_FUN(fun);
00261         
00262         fibril_mutex_lock(&bus->conf_mutex);
00263         
00264         uint32_t conf_addr;
00265         conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
00266         void *addr = bus->conf_data_port + (reg & 3);
00267         
00268         pio_write_32(bus->conf_addr_port, conf_addr);
00269         
00270         switch (len) {
00271         case 1:
00272                 pio_write_8(addr, buf[0]);
00273                 break;
00274         case 2:
00275                 pio_write_16(addr, ((uint16_t *) buf)[0]);
00276                 break;
00277         case 4:
00278                 pio_write_32(addr, ((uint32_t *) buf)[0]);
00279                 break;
00280         }
00281         
00282         fibril_mutex_unlock(&bus->conf_mutex);
00283 }
00284 
00285 uint8_t pci_conf_read_8(pci_fun_t *fun, int reg)
00286 {
00287         uint8_t res;
00288         pci_conf_read(fun, reg, &res, 1);
00289         return res;
00290 }
00291 
00292 uint16_t pci_conf_read_16(pci_fun_t *fun, int reg)
00293 {
00294         uint16_t res;
00295         pci_conf_read(fun, reg, (uint8_t *) &res, 2);
00296         return res;
00297 }
00298 
00299 uint32_t pci_conf_read_32(pci_fun_t *fun, int reg)
00300 {
00301         uint32_t res;
00302         pci_conf_read(fun, reg, (uint8_t *) &res, 4);
00303         return res;
00304 }
00305 
00306 void pci_conf_write_8(pci_fun_t *fun, int reg, uint8_t val)
00307 {
00308         pci_conf_write(fun, reg, (uint8_t *) &val, 1);
00309 }
00310 
00311 void pci_conf_write_16(pci_fun_t *fun, int reg, uint16_t val)
00312 {
00313         pci_conf_write(fun, reg, (uint8_t *) &val, 2);
00314 }
00315 
00316 void pci_conf_write_32(pci_fun_t *fun, int reg, uint32_t val)
00317 {
00318         pci_conf_write(fun, reg, (uint8_t *) &val, 4);
00319 }
00320 
00321 void pci_fun_create_match_ids(pci_fun_t *fun)
00322 {
00323         char *match_id_str;
00324         int rc;
00325         
00326         asprintf(&match_id_str, "pci/ven=%04x&dev=%04x",
00327             fun->vendor_id, fun->device_id);
00328 
00329         if (match_id_str == NULL) {
00330                 ddf_msg(LVL_ERROR, "Out of memory creating match ID.");
00331                 return;
00332         }
00333 
00334         rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 90);
00335         if (rc != EOK) {
00336                 ddf_msg(LVL_ERROR, "Failed adding match ID: %s",
00337                     str_error(rc));
00338         }
00339         
00340         /* TODO add more ids (with subsys ids, using class id etc.) */
00341 }
00342 
00343 void pci_add_range(pci_fun_t *fun, uint64_t range_addr, size_t range_size,
00344     bool io)
00345 {
00346         hw_resource_list_t *hw_res_list = &fun->hw_resources;
00347         hw_resource_t *hw_resources =  hw_res_list->resources;
00348         size_t count = hw_res_list->count;
00349         
00350         assert(hw_resources != NULL);
00351         assert(count < PCI_MAX_HW_RES);
00352         
00353         if (io) {
00354                 hw_resources[count].type = IO_RANGE;
00355                 hw_resources[count].res.io_range.address = range_addr;
00356                 hw_resources[count].res.io_range.size = range_size;
00357                 hw_resources[count].res.io_range.endianness = LITTLE_ENDIAN;
00358         } else {
00359                 hw_resources[count].type = MEM_RANGE;
00360                 hw_resources[count].res.mem_range.address = range_addr;
00361                 hw_resources[count].res.mem_range.size = range_size;
00362                 hw_resources[count].res.mem_range.endianness = LITTLE_ENDIAN;
00363         }
00364         
00365         hw_res_list->count++;
00366 }
00367 
00376 int pci_read_bar(pci_fun_t *fun, int addr)
00377 {
00378         /* Value of the BAR */
00379         uint32_t val, mask;
00380         /* IO space address */
00381         bool io;
00382         /* 64-bit wide address */
00383         bool addrw64;
00384         
00385         /* Size of the io or memory range specified by the BAR */
00386         size_t range_size;
00387         /* Beginning of the io or memory range specified by the BAR */
00388         uint64_t range_addr;
00389         
00390         /* Get the value of the BAR. */
00391         val = pci_conf_read_32(fun, addr);
00392 
00393 #define IO_MASK  (~0x3)
00394 #define MEM_MASK (~0xf)
00395         
00396         io = (bool) (val & 1);
00397         if (io) {
00398                 addrw64 = false;
00399                 mask = IO_MASK;
00400         } else {
00401                 mask = MEM_MASK;
00402                 switch ((val >> 1) & 3) {
00403                 case 0:
00404                         addrw64 = false;
00405                         break;
00406                 case 2:
00407                         addrw64 = true;
00408                         break;
00409                 default:
00410                         /* reserved, go to the next BAR */
00411                         return addr + 4;
00412                 }
00413         }
00414         
00415         /* Get the address mask. */
00416         pci_conf_write_32(fun, addr, 0xffffffff);
00417         mask &= pci_conf_read_32(fun, addr);
00418         
00419         /* Restore the original value. */
00420         pci_conf_write_32(fun, addr, val);
00421         val = pci_conf_read_32(fun, addr);
00422         
00423         range_size = pci_bar_mask_to_size(mask);
00424         
00425         if (addrw64) {
00426                 range_addr = ((uint64_t)pci_conf_read_32(fun, addr + 4) << 32) |
00427                     (val & 0xfffffff0);
00428         } else {
00429                 range_addr = (val & 0xfffffff0);
00430         }
00431         
00432         if (range_addr != 0) {
00433                 ddf_msg(LVL_DEBUG, "Function %s : address = %" PRIx64
00434                     ", size = %x", fun->fnode->name, range_addr,
00435                     (unsigned int) range_size);
00436         }
00437         
00438         pci_add_range(fun, range_addr, range_size, io);
00439         
00440         if (addrw64)
00441                 return addr + 8;
00442         
00443         return addr + 4;
00444 }
00445 
00446 void pci_add_interrupt(pci_fun_t *fun, int irq)
00447 {
00448         hw_resource_list_t *hw_res_list = &fun->hw_resources;
00449         hw_resource_t *hw_resources = hw_res_list->resources;
00450         size_t count = hw_res_list->count;
00451         
00452         assert(NULL != hw_resources);
00453         assert(count < PCI_MAX_HW_RES);
00454         
00455         hw_resources[count].type = INTERRUPT;
00456         hw_resources[count].res.interrupt.irq = irq;
00457         
00458         hw_res_list->count++;
00459         
00460         ddf_msg(LVL_NOTE, "Function %s uses irq %x.", fun->fnode->name, irq);
00461 }
00462 
00463 void pci_read_interrupt(pci_fun_t *fun)
00464 {
00465         uint8_t irq = pci_conf_read_8(fun, PCI_BRIDGE_INT_LINE);
00466         if (irq != 0xff)
00467                 pci_add_interrupt(fun, irq);
00468 }
00469 
00475 void pci_bus_scan(pci_bus_t *bus, int bus_num) 
00476 {
00477         ddf_fun_t *fnode;
00478         pci_fun_t *fun;
00479         
00480         int child_bus = 0;
00481         int dnum, fnum;
00482         bool multi;
00483         uint8_t header_type;
00484         
00485         fun = pci_fun_new(bus);
00486         
00487         for (dnum = 0; dnum < 32; dnum++) {
00488                 multi = true;
00489                 for (fnum = 0; multi && fnum < 8; fnum++) {
00490                         pci_fun_init(fun, bus_num, dnum, fnum);
00491                         fun->vendor_id = pci_conf_read_16(fun,
00492                             PCI_VENDOR_ID);
00493                         fun->device_id = pci_conf_read_16(fun,
00494                             PCI_DEVICE_ID);
00495                         if (fun->vendor_id == 0xffff) {
00496                                 /*
00497                                  * The device is not present, go on scanning the
00498                                  * bus.
00499                                  */
00500                                 if (fnum == 0)
00501                                         break;
00502                                 else
00503                                         continue;
00504                         }
00505                         
00506                         header_type = pci_conf_read_8(fun, PCI_HEADER_TYPE);
00507                         if (fnum == 0) {
00508                                 /* Is the device multifunction? */
00509                                 multi = header_type >> 7;
00510                         }
00511                         /* Clear the multifunction bit. */
00512                         header_type = header_type & 0x7F;
00513                         
00514                         char *fun_name = pci_fun_create_name(fun);
00515                         if (fun_name == NULL) {
00516                                 ddf_msg(LVL_ERROR, "Out of memory.");
00517                                 return;
00518                         }
00519                         
00520                         fnode = ddf_fun_create(bus->dnode, fun_inner, fun_name);
00521                         if (fnode == NULL) {
00522                                 ddf_msg(LVL_ERROR, "Failed creating function.");
00523                                 return;
00524                         }
00525                         
00526                         free(fun_name);
00527                         fun->fnode = fnode;
00528                         
00529                         pci_alloc_resource_list(fun);
00530                         pci_read_bars(fun);
00531                         pci_read_interrupt(fun);
00532                         
00533                         fnode->ops = &pci_fun_ops;
00534                         fnode->driver_data = fun;
00535                         
00536                         ddf_msg(LVL_DEBUG, "Adding new function %s.",
00537                             fnode->name);
00538                         
00539                         pci_fun_create_match_ids(fun);
00540                         
00541                         if (ddf_fun_bind(fnode) != EOK) {
00542                                 pci_clean_resource_list(fun);
00543                                 clean_match_ids(&fnode->match_ids);
00544                                 free((char *) fnode->name);
00545                                 fnode->name = NULL;
00546                                 continue;
00547                         }
00548                         
00549                         if (header_type == PCI_HEADER_TYPE_BRIDGE ||
00550                             header_type == PCI_HEADER_TYPE_CARDBUS) {
00551                                 child_bus = pci_conf_read_8(fun,
00552                                     PCI_BRIDGE_SEC_BUS_NUM);
00553                                 ddf_msg(LVL_DEBUG, "Device is pci-to-pci "
00554                                     "bridge, secondary bus number = %d.",
00555                                     bus_num);
00556                                 if (child_bus > bus_num)
00557                                         pci_bus_scan(bus, child_bus);
00558                         }
00559                         
00560                         fun = pci_fun_new(bus);
00561                 }
00562         }
00563         
00564         if (fun->vendor_id == 0xffff) {
00565                 /* Free the auxiliary function structure. */
00566                 pci_fun_delete(fun);
00567         }
00568 }
00569 
00570 static int pci_add_device(ddf_dev_t *dnode)
00571 {
00572         pci_bus_t *bus = NULL;
00573         ddf_fun_t *ctl = NULL;
00574         bool got_res = false;
00575         int rc;
00576         
00577         ddf_msg(LVL_DEBUG, "pci_add_device");
00578         dnode->parent_phone = -1;
00579         
00580         bus = pci_bus_new();
00581         if (bus == NULL) {
00582                 ddf_msg(LVL_ERROR, "pci_add_device allocation failed.");
00583                 rc = ENOMEM;
00584                 goto fail;
00585         }
00586         bus->dnode = dnode;
00587         dnode->driver_data = bus;
00588         
00589         dnode->parent_phone = devman_parent_device_connect(dnode->handle,
00590             IPC_FLAG_BLOCKING);
00591         if (dnode->parent_phone < 0) {
00592                 ddf_msg(LVL_ERROR, "pci_add_device failed to connect to the "
00593                     "parent's driver.");
00594                 rc = dnode->parent_phone;
00595                 goto fail;
00596         }
00597         
00598         hw_resource_list_t hw_resources;
00599         
00600         rc = hw_res_get_resource_list(dnode->parent_phone, &hw_resources);
00601         if (rc != EOK) {
00602                 ddf_msg(LVL_ERROR, "pci_add_device failed to get hw resources "
00603                     "for the device.");
00604                 goto fail;
00605         }
00606         got_res = true;
00607         
00608         ddf_msg(LVL_DEBUG, "conf_addr = %" PRIx64 ".",
00609             hw_resources.resources[0].res.io_range.address);
00610         
00611         assert(hw_resources.count > 0);
00612         assert(hw_resources.resources[0].type == IO_RANGE);
00613         assert(hw_resources.resources[0].res.io_range.size == 8);
00614         
00615         bus->conf_io_addr =
00616             (uint32_t) hw_resources.resources[0].res.io_range.address;
00617         
00618         if (pio_enable((void *)(uintptr_t)bus->conf_io_addr, 8,
00619             &bus->conf_addr_port)) {
00620                 ddf_msg(LVL_ERROR, "Failed to enable configuration ports.");
00621                 rc = EADDRNOTAVAIL;
00622                 goto fail;
00623         }
00624         bus->conf_data_port = (char *) bus->conf_addr_port + 4;
00625         
00626         /* Make the bus device more visible. It has no use yet. */
00627         ddf_msg(LVL_DEBUG, "Adding a 'ctl' function");
00628         
00629         ctl = ddf_fun_create(bus->dnode, fun_exposed, "ctl");
00630         if (ctl == NULL) {
00631                 ddf_msg(LVL_ERROR, "Failed creating control function.");
00632                 rc = ENOMEM;
00633                 goto fail;
00634         }
00635         
00636         rc = ddf_fun_bind(ctl);
00637         if (rc != EOK) {
00638                 ddf_msg(LVL_ERROR, "Failed binding control function.");
00639                 goto fail;
00640         }
00641         
00642         /* Enumerate functions. */
00643         ddf_msg(LVL_DEBUG, "Scanning the bus");
00644         pci_bus_scan(bus, 0);
00645         
00646         hw_res_clean_resource_list(&hw_resources);
00647         
00648         return EOK;
00649         
00650 fail:
00651         if (bus != NULL)
00652                 pci_bus_delete(bus);
00653         if (dnode->parent_phone >= 0)
00654                 async_hangup(dnode->parent_phone);
00655         if (got_res)
00656                 hw_res_clean_resource_list(&hw_resources);
00657         if (ctl != NULL)
00658                 ddf_fun_destroy(ctl);
00659 
00660         return rc;
00661 }
00662 
00663 static void pciintel_init(void)
00664 {
00665         ddf_log_init(NAME, LVL_ERROR);
00666         pci_fun_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops;
00667         pci_fun_ops.interfaces[PCI_DEV_IFACE] = &pci_dev_ops;
00668 }
00669 
00670 pci_fun_t *pci_fun_new(pci_bus_t *bus)
00671 {
00672         pci_fun_t *fun;
00673         
00674         fun = (pci_fun_t *) calloc(1, sizeof(pci_fun_t));
00675         if (fun == NULL)
00676                 return NULL;
00677 
00678         fun->busptr = bus;
00679         return fun;
00680 }
00681 
00682 void pci_fun_init(pci_fun_t *fun, int bus, int dev, int fn)
00683 {
00684         fun->bus = bus;
00685         fun->dev = dev;
00686         fun->fn = fn;
00687 }
00688 
00689 void pci_fun_delete(pci_fun_t *fun)
00690 {
00691         assert(fun != NULL);
00692         hw_res_clean_resource_list(&fun->hw_resources);
00693         free(fun);
00694 }
00695 
00696 char *pci_fun_create_name(pci_fun_t *fun)
00697 {
00698         char *name = NULL;
00699         
00700         asprintf(&name, "%02x:%02x.%01x", fun->bus, fun->dev,
00701             fun->fn);
00702         return name;
00703 }
00704 
00705 bool pci_alloc_resource_list(pci_fun_t *fun)
00706 {
00707         fun->hw_resources.resources =
00708             (hw_resource_t *) malloc(PCI_MAX_HW_RES * sizeof(hw_resource_t));
00709         return fun->hw_resources.resources != NULL;
00710 }
00711 
00712 void pci_clean_resource_list(pci_fun_t *fun)
00713 {
00714         if (fun->hw_resources.resources != NULL) {
00715                 free(fun->hw_resources.resources);
00716                 fun->hw_resources.resources = NULL;
00717         }
00718 }
00719 
00725 void pci_read_bars(pci_fun_t *fun)
00726 {
00727         /*
00728          * Position of the BAR in the PCI configuration address space of the
00729          * device.
00730          */
00731         int addr = PCI_BASE_ADDR_0;
00732         
00733         while (addr <= PCI_BASE_ADDR_5)
00734                 addr = pci_read_bar(fun, addr);
00735 }
00736 
00737 size_t pci_bar_mask_to_size(uint32_t mask)
00738 {
00739         size_t size = mask & ~(mask - 1);
00740         return size;
00741 }
00742 
00743 int main(int argc, char *argv[])
00744 {
00745         printf(NAME ": HelenOS PCI bus driver (Intel method 1).\n");
00746         pciintel_init();
00747         return ddf_driver_main(&pci_driver);
00748 }
00749 

Generated on Thu Jun 2 07:45:43 2011 for HelenOS/USB by  doxygen 1.4.7