/* * Copyright 2007-2008, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Ithamar Adema, ithamar AT unet DOT nl */ #include "driver.h" int32 api_version = B_CUR_DRIVER_API_VERSION; hda_controller gCards[MAX_CARDS]; uint32 gNumCards; pci_module_info* gPci; static struct { uint16 vendor; uint16 device; } kSupportedDevices[] = { { 0x8086, 0xa170}, // 100 Series HD Audio { 0x8086, 0x9d71}, // 200 Series HD Audio { 0x8086, 0xa348}, // 300 Series cAVS { 0x8086, 0x9dc8}, // 300 Series HD Audio { 0x8086, 0x06c8}, // 400 Series cAVS { 0x8086, 0x02c8}, // 400 Series HD Audio { 0x8086, 0xa0c8}, // 500 Series HD Audio { 0x8086, 0x51c8}, // 600 Series HD Audio { 0x8086, 0x4dc8}, // JasperLake HD Audio { 0x8086, 0x43c8}, // Tiger Lake-H HD Audio { 0x8086, 0xa171}, // CM238 HD Audio { 0x8086, 0x3198}, // GeminiLake HD Audio }; static bool supports_device(pci_info &info) { for (size_t i = 0; i < B_COUNT_OF(kSupportedDevices); i++) { if (info.vendor_id == kSupportedDevices[i].vendor && info.device_id == kSupportedDevices[i].device) { return true; } } return false; } extern "C" status_t init_hardware(void) { pci_info info; long i; if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPci) != B_OK) return ENODEV; for (i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) { if ((info.class_base == PCI_multimedia && info.class_sub == PCI_hd_audio) || supports_device(info)) { put_module(B_PCI_MODULE_NAME); return B_OK; } } put_module(B_PCI_MODULE_NAME); return ENODEV; } extern "C" status_t init_driver(void) { char path[B_PATH_NAME_LENGTH]; pci_info info; long i; if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPci) != B_OK) return ENODEV; gNumCards = 0; for (i = 0; gPci->get_nth_pci_info(i, &info) == B_OK && gNumCards < MAX_CARDS; i++) { if ((info.class_base == PCI_multimedia && info.class_sub == PCI_hd_audio) || supports_device(info)) { #ifdef __HAIKU__ if ((*gPci->reserve_device)(info.bus, info.device, info.function, "hda", &gCards[gNumCards]) < B_OK) { dprintf("HDA: Failed to reserve PCI:%d:%d:%d\n", info.bus, info.device, info.function); continue; } #endif memset(&gCards[gNumCards], 0, sizeof(hda_controller)); gCards[gNumCards].pci_info = info; gCards[gNumCards].opened = 0; sprintf(path, DEVFS_PATH_FORMAT, gNumCards); gCards[gNumCards++].devfs_path = strdup(path); dprintf("HDA: Detected controller @ PCI:%d:%d:%d, IRQ:%d, " "type %04x/%04x (%04x/%04x)\n", info.bus, info.device, info.function, info.u.h0.interrupt_line, info.vendor_id, info.device_id, info.u.h0.subsystem_vendor_id, info.u.h0.subsystem_id); } } if (gNumCards == 0) { put_module(B_PCI_MODULE_NAME); return ENODEV; } return B_OK; } extern "C" void uninit_driver(void) { for (uint32 i = 0; i < gNumCards; i++) { #ifdef __HAIKU__ (*gPci->unreserve_device)(gCards[i].pci_info.bus, gCards[i].pci_info.device, gCards[i].pci_info.function, "hda", &gCards[i]); #endif free((void*)gCards[i].devfs_path); gCards[i].devfs_path = NULL; } put_module(B_PCI_MODULE_NAME); } extern "C" const char** publish_devices(void) { static const char* devs[MAX_CARDS + 1]; uint32 i; for (i = 0; i < gNumCards; i++) devs[i] = gCards[i].devfs_path; devs[i] = NULL; return devs; } extern "C" device_hooks* find_device(const char* name) { return &gDriverHooks; }