1/*
2 * Copyright 2007-2008, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Ithamar Adema, ithamar AT unet DOT nl
7 */
8
9
10#include "driver.h"
11
12
13int32 api_version = B_CUR_DRIVER_API_VERSION;
14
15hda_controller gCards[MAX_CARDS];
16uint32 gNumCards;
17pci_module_info* gPci;
18
19
20static struct {
21	uint16	vendor;
22	uint16	device;
23} kSupportedDevices[] = {
24	{ 0x8086, 0xa170},	// 100 Series HD Audio
25	{ 0x8086, 0x9d71},	// 200 Series HD Audio
26	{ 0x8086, 0xa348},	// 300 Series cAVS
27	{ 0x8086, 0x9dc8},	// 300 Series HD Audio
28	{ 0x8086, 0x06c8},	// 400 Series cAVS
29	{ 0x8086, 0x02c8},	// 400 Series HD Audio
30	{ 0x8086, 0xa0c8},	// 500 Series HD Audio
31	{ 0x8086, 0x51c8},	// 600 Series HD Audio
32	{ 0x8086, 0x4dc8},	// JasperLake HD Audio
33	{ 0x8086, 0x43c8},	// Tiger Lake-H HD Audio
34	{ 0x8086, 0xa171},	// CM238 HD Audio
35	{ 0x8086, 0x3198},	// GeminiLake HD Audio
36};
37
38
39static bool
40supports_device(pci_info &info)
41{
42	for (size_t i = 0; i < B_COUNT_OF(kSupportedDevices); i++) {
43		if (info.vendor_id == kSupportedDevices[i].vendor
44			&& info.device_id == kSupportedDevices[i].device) {
45			return true;
46		}
47	}
48	return false;
49}
50
51
52extern "C" status_t
53init_hardware(void)
54{
55	pci_info info;
56	long i;
57
58	if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPci) != B_OK)
59		return ENODEV;
60
61	for (i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) {
62		if ((info.class_base == PCI_multimedia
63				&& info.class_sub == PCI_hd_audio)
64			|| supports_device(info)) {
65			put_module(B_PCI_MODULE_NAME);
66			return B_OK;
67		}
68	}
69
70	put_module(B_PCI_MODULE_NAME);
71	return ENODEV;
72}
73
74
75extern "C" status_t
76init_driver(void)
77{
78	char path[B_PATH_NAME_LENGTH];
79	pci_info info;
80	long i;
81
82	if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPci) != B_OK)
83		return ENODEV;
84
85	gNumCards = 0;
86
87	for (i = 0; gPci->get_nth_pci_info(i, &info) == B_OK
88			&& gNumCards < MAX_CARDS; i++) {
89		if ((info.class_base == PCI_multimedia
90				&& info.class_sub == PCI_hd_audio)
91			|| supports_device(info)) {
92#ifdef __HAIKU__
93			if ((*gPci->reserve_device)(info.bus, info.device, info.function,
94				"hda", &gCards[gNumCards]) < B_OK) {
95				dprintf("HDA: Failed to reserve PCI:%d:%d:%d\n",
96					info.bus, info.device, info.function);
97				continue;
98			}
99#endif
100			memset(&gCards[gNumCards], 0, sizeof(hda_controller));
101			gCards[gNumCards].pci_info = info;
102			gCards[gNumCards].opened = 0;
103			sprintf(path, DEVFS_PATH_FORMAT, gNumCards);
104			gCards[gNumCards++].devfs_path = strdup(path);
105
106			dprintf("HDA: Detected controller @ PCI:%d:%d:%d, IRQ:%d, "
107				"type %04x/%04x (%04x/%04x)\n",
108				info.bus, info.device, info.function,
109				info.u.h0.interrupt_line, info.vendor_id, info.device_id,
110				info.u.h0.subsystem_vendor_id, info.u.h0.subsystem_id);
111		}
112	}
113
114	if (gNumCards == 0) {
115		put_module(B_PCI_MODULE_NAME);
116		return ENODEV;
117	}
118
119	return B_OK;
120}
121
122
123extern "C" void
124uninit_driver(void)
125{
126	for (uint32 i = 0; i < gNumCards; i++) {
127#ifdef __HAIKU__
128		(*gPci->unreserve_device)(gCards[i].pci_info.bus,
129			gCards[i].pci_info.device, gCards[i].pci_info.function, "hda",
130			&gCards[i]);
131#endif
132		free((void*)gCards[i].devfs_path);
133		gCards[i].devfs_path = NULL;
134	}
135
136	put_module(B_PCI_MODULE_NAME);
137}
138
139
140extern "C" const char**
141publish_devices(void)
142{
143	static const char* devs[MAX_CARDS + 1];
144	uint32 i;
145
146	for (i = 0; i < gNumCards; i++)
147		devs[i] = gCards[i].devfs_path;
148
149	devs[i] = NULL;
150
151	return devs;
152}
153
154
155extern "C" device_hooks*
156find_device(const char* name)
157{
158	return &gDriverHooks;
159}
160