1/*
2 *	SiS 7018, Trident 4D Wave DX/NX, Acer Lab M5451 Sound Driver.
3 *	Copyright (c) 2002, 2008-2011 S.Zharski <imker@gmx.li>
4 *	Distributed under the terms of the MIT license.
5 *
6 */
7
8
9#include "Driver.h"
10
11#include <kernel_cpp.h>
12#include <string.h>
13
14#include "Device.h"
15#include "Settings.h"
16
17
18int32 api_version = B_CUR_DRIVER_API_VERSION;
19
20size_t gNumCards = 0;
21Device *gDevices[MAX_DEVICES] = { 0 };
22char *gDeviceNames[MAX_DEVICES + 1] = { 0 };
23pci_module_info *gPCI = NULL;
24
25
26static Device::Info cardInfos[] = {
27	{ SiS7018, "SiS 7018" },
28	{ ALi5451, "ALi M5451" },
29	{ TridentDX, "Trident DX" },
30	{ TridentNX, "Trident NX" }
31};
32
33
34status_t
35init_hardware()
36{
37	dprintf("sis7018:init_hardware:ver:%s\n", kVersion);
38	status_t result = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
39	if (result < B_OK) {
40		return ENOSYS;
41	}
42
43	pci_info info = {0};
44	for (long i = 0; B_OK == (*gPCI->get_nth_pci_info)(i, &info); i++) {
45		for (size_t idx = 0; idx < B_COUNT_OF(cardInfos); idx++) {
46			if (info.vendor_id == cardInfos[idx].VendorId() &&
47				info.device_id == cardInfos[idx].DeviceId())
48			{
49				put_module(B_PCI_MODULE_NAME);
50				return B_OK;
51			}
52		}
53	}
54
55	put_module(B_PCI_MODULE_NAME);
56	return ENODEV;
57}
58
59
60status_t
61init_driver()
62{
63	status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
64	if (status < B_OK) {
65		return ENOSYS;
66	}
67
68	load_settings();
69
70	pci_info info = { 0 };
71	for (long i = 0; B_OK == (*gPCI->get_nth_pci_info)(i, &info); i++) {
72		for (size_t idx = 0; idx < B_COUNT_OF(cardInfos); idx++) {
73			if (info.vendor_id == cardInfos[idx].VendorId() &&
74				info.device_id == cardInfos[idx].DeviceId())
75			{
76				if (gNumCards == MAX_DEVICES) {
77					ERROR("Skipped:%s [%#06x:%#06x]\n", cardInfos[idx].Name(),
78						cardInfos[idx].VendorId(), cardInfos[idx].DeviceId());
79					break;
80				}
81
82				Device* device = new(std::nothrow) Device(cardInfos[idx], info);
83				if (device == 0) {
84					return ENODEV;
85				}
86
87				status_t status = device->InitCheck();
88				if (status < B_OK) {
89					delete device;
90					break;
91				}
92
93				status = device->Setup();
94				if (status < B_OK) {
95					delete device;
96					break;
97				}
98
99				char name[32] = {0};
100				sprintf(name, "audio/hmulti/%s/%ld",
101								cardInfos[idx].Name(), gNumCards);
102				gDeviceNames[gNumCards] = strdup(name);
103				gDevices[gNumCards++] = device;
104
105				TRACE("Found:%s [%#06x:%#06x]\n", cardInfos[idx].Name(),
106						cardInfos[idx].VendorId(), cardInfos[idx].DeviceId());
107			}
108		}
109	}
110
111	if (gNumCards == 0) {
112		put_module(B_PCI_MODULE_NAME);
113		return ENODEV;
114	}
115
116	return B_OK;
117}
118
119
120void
121uninit_driver()
122{
123	for (size_t i = 0; i < MAX_DEVICES; i++) {
124		if (gDevices[i]) {
125			delete gDevices[i];
126			gDevices[i] = NULL;
127		}
128
129		free(gDeviceNames[i]);
130		gDeviceNames[i] = NULL;
131	}
132
133	put_module(B_PCI_MODULE_NAME);
134
135	release_settings();
136}
137
138
139static status_t
140SiS7018_open(const char *name, uint32 flags, void **cookie)
141{
142	status_t status = ENODEV;
143	*cookie = NULL;
144	for (size_t i = 0; i < MAX_DEVICES; i++) {
145		if (gDeviceNames[i] && !strcmp(gDeviceNames[i], name)) {
146			status = gDevices[i]->Open(flags);
147			*cookie = gDevices[i];
148		}
149	}
150
151	return status;
152}
153
154
155static status_t
156SiS7018_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
157{
158	Device *device = (Device *)cookie;
159	return device->Read((uint8 *)buffer, numBytes);
160}
161
162
163static status_t
164SiS7018_write(void *cookie, off_t position,
165							const void *buffer, size_t *numBytes)
166{
167	Device *device = (Device *)cookie;
168	return device->Write((const uint8 *)buffer, numBytes);
169}
170
171
172static status_t
173SiS7018_control(void *cookie, uint32 op, void *buffer, size_t length)
174{
175	Device *device = (Device *)cookie;
176	return device->Control(op, buffer, length);
177}
178
179
180static status_t
181SiS7018_close(void *cookie)
182{
183	Device *device = (Device *)cookie;
184	return device->Close();
185}
186
187
188static status_t
189SiS7018_free(void *cookie)
190{
191	Device *device = (Device *)cookie;
192	return device->Free();
193}
194
195
196const char **
197publish_devices()
198{
199	for (size_t i = 0; i < MAX_DEVICES; i++) {
200		if (gDevices[i] == NULL)
201			continue;
202
203		if (gDeviceNames[i])
204			TRACE("%s\n", gDeviceNames[i]);
205	}
206
207	return (const char **)&gDeviceNames[0];
208}
209
210
211device_hooks *
212find_device(const char *name)
213{
214	static device_hooks deviceHooks = {
215		SiS7018_open,
216		SiS7018_close,
217		SiS7018_free,
218		SiS7018_control,
219		SiS7018_read,
220		SiS7018_write,
221		NULL,				// select
222		NULL				// deselect
223	};
224
225	return &deviceHooks;
226}
227
228