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