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