7d8f446475
Currently supports Intel HDA, AC97, and ES1370 audio cards. See README for further details.
177 lines
3.6 KiB
C++
177 lines
3.6 KiB
C++
/*
|
|
* \brief Driver probing and registration
|
|
* \author Sebasitian Sumpf
|
|
* \date 2012-11-20
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2012 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU General Public License version 2.
|
|
*/
|
|
|
|
#include <base/printf.h>
|
|
#include <pci_session/connection.h>
|
|
#include <pci_device/client.h>
|
|
|
|
extern "C" {
|
|
#include <oss_config.h>
|
|
#include <dde_kit/pci.h>
|
|
}
|
|
|
|
#include <quirks.h>
|
|
|
|
|
|
/**
|
|
* Driver management class
|
|
*/
|
|
class Driver
|
|
{
|
|
private:
|
|
|
|
enum { MAX_DRIVER = 10 };
|
|
|
|
oss_driver *_drivers[MAX_DRIVER + 1]; /* reigsted drivers */
|
|
|
|
Driver()
|
|
{
|
|
Genode::memset(_drivers, 0, sizeof(oss_driver *) * (MAX_DRIVER + 1));
|
|
dde_kit_pci_init();
|
|
}
|
|
|
|
/**
|
|
* Match vendor product IDs
|
|
*/
|
|
bool _match(oss_driver *driver, Pci::Device_capability &cap)
|
|
{
|
|
Pci::Device_client client(cap);
|
|
|
|
unsigned short vendor_id = client.vendor_id();
|
|
unsigned short device_id = client.device_id();
|
|
device_id_t *id_table = driver->id_table;
|
|
|
|
for (int i = 0; id_table[i].vendor; i++) {
|
|
if (id_table[i].vendor == vendor_id &&
|
|
id_table[i].product == device_id) {
|
|
PINF("Found card: vendor 0x%x: product: 0x%x driver: %s",
|
|
vendor_id, device_id, driver->name);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Probe device with registered drivers
|
|
*/
|
|
oss_driver *_probe_driver(Pci::Device_capability &cap)
|
|
{
|
|
for (int i = 0; _drivers[i]; i++)
|
|
if (_match(_drivers[i], cap))
|
|
return _drivers[i];
|
|
|
|
return 0;
|
|
}
|
|
|
|
public:
|
|
|
|
static Driver *d()
|
|
{
|
|
static Driver _d;
|
|
return &_d;
|
|
}
|
|
|
|
/**
|
|
* Register drivers
|
|
*/
|
|
void add(oss_driver *driver)
|
|
{
|
|
for (int i = 0; i < MAX_DRIVER; i++)
|
|
if (!_drivers[i]) {
|
|
_drivers[i] = driver;
|
|
return;
|
|
}
|
|
|
|
PWRN("Driver limit of %d reached", MAX_DRIVER);
|
|
}
|
|
|
|
/**
|
|
* Probe PCI devices with registered drivers
|
|
*/
|
|
void probe()
|
|
{
|
|
using namespace Genode;
|
|
Pci::Connection pci;
|
|
Pci::Device_capability cap = pci.first_device();
|
|
Pci::Device_capability old;
|
|
oss_driver *driver = 0;
|
|
|
|
while (cap.valid()) {
|
|
|
|
Pci::Device_client client(cap);
|
|
|
|
/* check for audio device class */
|
|
enum {
|
|
CLASS_MASK = 0xff0000,
|
|
CLASS_MULTIMEDIA = 0x40000, /* class multimedia */
|
|
};
|
|
|
|
/*
|
|
* Just test for multimedia class, since some devices (e.g., intel
|
|
* hda) do set the subclass to something different then audio (0x1).
|
|
*/
|
|
bool audio = (client.class_code() & CLASS_MASK) == CLASS_MULTIMEDIA;
|
|
if (audio && (driver = _probe_driver(cap))) {
|
|
|
|
uint8_t bus, dev, func;
|
|
client.bus_address(&bus, &dev, &func);
|
|
|
|
/* setup oss device */
|
|
oss_device_t *ossdev = new (env()->heap()) oss_device_t;
|
|
Genode::memset(ossdev, 0, sizeof(oss_device_t));
|
|
|
|
ossdev->bus = bus;
|
|
ossdev->dev = dev;
|
|
ossdev->fun = func;
|
|
|
|
/* set I/O resources */
|
|
for (int i = 0; i < Pci::Device::NUM_RESOURCES; i++) {
|
|
Pci::Device::Resource res = client.resource(i);
|
|
ossdev->res[i].base = res.base();
|
|
ossdev->res[i].size = res.size();
|
|
ossdev->res[i].io = res.type() == Pci::Device::Resource::IO ? 1 : 0;
|
|
}
|
|
|
|
ossdev->drv = driver;
|
|
|
|
/* set quirks */
|
|
setup_quirks(driver);
|
|
driver->attach(ossdev);
|
|
}
|
|
old = cap;
|
|
cap = pci.next_device(cap);
|
|
pci.release_device(old);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/*****************
|
|
** C interface **
|
|
*****************/
|
|
|
|
extern "C" void register_driver(struct oss_driver *driver)
|
|
{
|
|
dde_kit_log(VERBOSE_OSS, "Register driver: %s", driver->name);
|
|
Driver::d()->add(driver);
|
|
}
|
|
|
|
|
|
extern "C" void probe_drivers(void)
|
|
{
|
|
Driver::d()->probe();
|
|
}
|
|
|