xref: /haiku/src/add-ons/kernel/drivers/audio/ac97/sis7018/Driver.cpp (revision 82bbd737a1144aa65550d238c7050b4c8e31c93f)
107910542SSiarzhuk Zharski /*
207910542SSiarzhuk Zharski  *	SiS 7018, Trident 4D Wave DX/NX, Acer Lab M5451 Sound Driver.
307910542SSiarzhuk Zharski  *	Copyright (c) 2002, 2008-2011 S.Zharski <imker@gmx.li>
407910542SSiarzhuk Zharski  *	Distributed under the terms of the MIT license.
507910542SSiarzhuk Zharski  *
607910542SSiarzhuk Zharski  */
707910542SSiarzhuk Zharski 
807910542SSiarzhuk Zharski 
907910542SSiarzhuk Zharski #include "Driver.h"
1007910542SSiarzhuk Zharski 
1107910542SSiarzhuk Zharski #include <kernel_cpp.h>
1207910542SSiarzhuk Zharski #include <string.h>
1307910542SSiarzhuk Zharski 
1407910542SSiarzhuk Zharski #include "Device.h"
1507910542SSiarzhuk Zharski #include "Settings.h"
1607910542SSiarzhuk Zharski 
1707910542SSiarzhuk Zharski 
1807910542SSiarzhuk Zharski int32 api_version = B_CUR_DRIVER_API_VERSION;
1907910542SSiarzhuk Zharski 
2007910542SSiarzhuk Zharski size_t gNumCards = 0;
2107910542SSiarzhuk Zharski Device *gDevices[MAX_DEVICES] = { 0 };
2207910542SSiarzhuk Zharski char *gDeviceNames[MAX_DEVICES + 1] = { 0 };
2307910542SSiarzhuk Zharski pci_module_info *gPCI = NULL;
2407910542SSiarzhuk Zharski 
2507910542SSiarzhuk Zharski 
2607910542SSiarzhuk Zharski static Device::Info cardInfos[] = {
2707910542SSiarzhuk Zharski 	{ SiS7018, "SiS 7018" },
2807910542SSiarzhuk Zharski 	{ ALi5451, "ALi M5451" },
2907910542SSiarzhuk Zharski 	{ TridentDX, "Trident DX" },
3007910542SSiarzhuk Zharski 	{ TridentNX, "Trident NX" }
3107910542SSiarzhuk Zharski };
3207910542SSiarzhuk Zharski 
3307910542SSiarzhuk Zharski 
3407910542SSiarzhuk Zharski status_t
init_hardware()3507910542SSiarzhuk Zharski init_hardware()
3607910542SSiarzhuk Zharski {
3707910542SSiarzhuk Zharski 	dprintf("sis7018:init_hardware:ver:%s\n", kVersion);
3807910542SSiarzhuk Zharski 	status_t result = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
3907910542SSiarzhuk Zharski 	if (result < B_OK) {
4007910542SSiarzhuk Zharski 		return ENOSYS;
4107910542SSiarzhuk Zharski 	}
4207910542SSiarzhuk Zharski 
4307910542SSiarzhuk Zharski 	pci_info info = {0};
4407910542SSiarzhuk Zharski 	for (long i = 0; B_OK == (*gPCI->get_nth_pci_info)(i, &info); i++) {
4557bc6503SAlexander von Gluck IV 		for (size_t idx = 0; idx < B_COUNT_OF(cardInfos); idx++) {
4607910542SSiarzhuk Zharski 			if (info.vendor_id == cardInfos[idx].VendorId() &&
4707910542SSiarzhuk Zharski 				info.device_id == cardInfos[idx].DeviceId())
4807910542SSiarzhuk Zharski 			{
4907910542SSiarzhuk Zharski 				put_module(B_PCI_MODULE_NAME);
5007910542SSiarzhuk Zharski 				return B_OK;
5107910542SSiarzhuk Zharski 			}
5207910542SSiarzhuk Zharski 		}
5307910542SSiarzhuk Zharski 	}
5407910542SSiarzhuk Zharski 
5507910542SSiarzhuk Zharski 	put_module(B_PCI_MODULE_NAME);
5607910542SSiarzhuk Zharski 	return ENODEV;
5707910542SSiarzhuk Zharski }
5807910542SSiarzhuk Zharski 
5907910542SSiarzhuk Zharski 
6007910542SSiarzhuk Zharski status_t
init_driver()6107910542SSiarzhuk Zharski init_driver()
6207910542SSiarzhuk Zharski {
6307910542SSiarzhuk Zharski 	status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
6407910542SSiarzhuk Zharski 	if (status < B_OK) {
6507910542SSiarzhuk Zharski 		return ENOSYS;
6607910542SSiarzhuk Zharski 	}
6707910542SSiarzhuk Zharski 
6807910542SSiarzhuk Zharski 	load_settings();
6907910542SSiarzhuk Zharski 
7007910542SSiarzhuk Zharski 	pci_info info = { 0 };
7107910542SSiarzhuk Zharski 	for (long i = 0; B_OK == (*gPCI->get_nth_pci_info)(i, &info); i++) {
7257bc6503SAlexander von Gluck IV 		for (size_t idx = 0; idx < B_COUNT_OF(cardInfos); idx++) {
7307910542SSiarzhuk Zharski 			if (info.vendor_id == cardInfos[idx].VendorId() &&
7407910542SSiarzhuk Zharski 				info.device_id == cardInfos[idx].DeviceId())
7507910542SSiarzhuk Zharski 			{
7607910542SSiarzhuk Zharski 				if (gNumCards == MAX_DEVICES) {
7707910542SSiarzhuk Zharski 					ERROR("Skipped:%s [%#06x:%#06x]\n", cardInfos[idx].Name(),
7807910542SSiarzhuk Zharski 						cardInfos[idx].VendorId(), cardInfos[idx].DeviceId());
7907910542SSiarzhuk Zharski 					break;
8007910542SSiarzhuk Zharski 				}
8107910542SSiarzhuk Zharski 
82*82bbd737SMurai Takashi 				Device* device = new(std::nothrow) Device(cardInfos[idx], info);
8307910542SSiarzhuk Zharski 				if (device == 0) {
8407910542SSiarzhuk Zharski 					return ENODEV;
8507910542SSiarzhuk Zharski 				}
8607910542SSiarzhuk Zharski 
8707910542SSiarzhuk Zharski 				status_t status = device->InitCheck();
8807910542SSiarzhuk Zharski 				if (status < B_OK) {
8907910542SSiarzhuk Zharski 					delete device;
9007910542SSiarzhuk Zharski 					break;
9107910542SSiarzhuk Zharski 				}
9207910542SSiarzhuk Zharski 
9307910542SSiarzhuk Zharski 				status = device->Setup();
9407910542SSiarzhuk Zharski 				if (status < B_OK) {
9507910542SSiarzhuk Zharski 					delete device;
9607910542SSiarzhuk Zharski 					break;
9707910542SSiarzhuk Zharski 				}
9807910542SSiarzhuk Zharski 
9907910542SSiarzhuk Zharski 				char name[32] = {0};
10007910542SSiarzhuk Zharski 				sprintf(name, "audio/hmulti/%s/%ld",
10107910542SSiarzhuk Zharski 								cardInfos[idx].Name(), gNumCards);
10207910542SSiarzhuk Zharski 				gDeviceNames[gNumCards] = strdup(name);
10307910542SSiarzhuk Zharski 				gDevices[gNumCards++] = device;
10407910542SSiarzhuk Zharski 
10507910542SSiarzhuk Zharski 				TRACE("Found:%s [%#06x:%#06x]\n", cardInfos[idx].Name(),
10607910542SSiarzhuk Zharski 						cardInfos[idx].VendorId(), cardInfos[idx].DeviceId());
10707910542SSiarzhuk Zharski 			}
10807910542SSiarzhuk Zharski 		}
10907910542SSiarzhuk Zharski 	}
11007910542SSiarzhuk Zharski 
11107910542SSiarzhuk Zharski 	if (gNumCards == 0) {
11207910542SSiarzhuk Zharski 		put_module(B_PCI_MODULE_NAME);
11307910542SSiarzhuk Zharski 		return ENODEV;
11407910542SSiarzhuk Zharski 	}
11507910542SSiarzhuk Zharski 
11607910542SSiarzhuk Zharski 	return B_OK;
11707910542SSiarzhuk Zharski }
11807910542SSiarzhuk Zharski 
11907910542SSiarzhuk Zharski 
12007910542SSiarzhuk Zharski void
uninit_driver()12107910542SSiarzhuk Zharski uninit_driver()
12207910542SSiarzhuk Zharski {
12307910542SSiarzhuk Zharski 	for (size_t i = 0; i < MAX_DEVICES; i++) {
12407910542SSiarzhuk Zharski 		if (gDevices[i]) {
12507910542SSiarzhuk Zharski 			delete gDevices[i];
12607910542SSiarzhuk Zharski 			gDevices[i] = NULL;
12707910542SSiarzhuk Zharski 		}
12807910542SSiarzhuk Zharski 
12907910542SSiarzhuk Zharski 		free(gDeviceNames[i]);
13007910542SSiarzhuk Zharski 		gDeviceNames[i] = NULL;
13107910542SSiarzhuk Zharski 	}
13207910542SSiarzhuk Zharski 
13307910542SSiarzhuk Zharski 	put_module(B_PCI_MODULE_NAME);
13407910542SSiarzhuk Zharski 
13507910542SSiarzhuk Zharski 	release_settings();
13607910542SSiarzhuk Zharski }
13707910542SSiarzhuk Zharski 
13807910542SSiarzhuk Zharski 
13907910542SSiarzhuk Zharski static status_t
SiS7018_open(const char * name,uint32 flags,void ** cookie)14007910542SSiarzhuk Zharski SiS7018_open(const char *name, uint32 flags, void **cookie)
14107910542SSiarzhuk Zharski {
14207910542SSiarzhuk Zharski 	status_t status = ENODEV;
14307910542SSiarzhuk Zharski 	*cookie = NULL;
14407910542SSiarzhuk Zharski 	for (size_t i = 0; i < MAX_DEVICES; i++) {
14507910542SSiarzhuk Zharski 		if (gDeviceNames[i] && !strcmp(gDeviceNames[i], name)) {
14607910542SSiarzhuk Zharski 			status = gDevices[i]->Open(flags);
14707910542SSiarzhuk Zharski 			*cookie = gDevices[i];
14807910542SSiarzhuk Zharski 		}
14907910542SSiarzhuk Zharski 	}
15007910542SSiarzhuk Zharski 
15107910542SSiarzhuk Zharski 	return status;
15207910542SSiarzhuk Zharski }
15307910542SSiarzhuk Zharski 
15407910542SSiarzhuk Zharski 
15507910542SSiarzhuk Zharski static status_t
SiS7018_read(void * cookie,off_t position,void * buffer,size_t * numBytes)15607910542SSiarzhuk Zharski SiS7018_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
15707910542SSiarzhuk Zharski {
15807910542SSiarzhuk Zharski 	Device *device = (Device *)cookie;
15907910542SSiarzhuk Zharski 	return device->Read((uint8 *)buffer, numBytes);
16007910542SSiarzhuk Zharski }
16107910542SSiarzhuk Zharski 
16207910542SSiarzhuk Zharski 
16307910542SSiarzhuk Zharski static status_t
SiS7018_write(void * cookie,off_t position,const void * buffer,size_t * numBytes)16407910542SSiarzhuk Zharski SiS7018_write(void *cookie, off_t position,
16507910542SSiarzhuk Zharski 							const void *buffer, size_t *numBytes)
16607910542SSiarzhuk Zharski {
16707910542SSiarzhuk Zharski 	Device *device = (Device *)cookie;
16807910542SSiarzhuk Zharski 	return device->Write((const uint8 *)buffer, numBytes);
16907910542SSiarzhuk Zharski }
17007910542SSiarzhuk Zharski 
17107910542SSiarzhuk Zharski 
17207910542SSiarzhuk Zharski static status_t
SiS7018_control(void * cookie,uint32 op,void * buffer,size_t length)17307910542SSiarzhuk Zharski SiS7018_control(void *cookie, uint32 op, void *buffer, size_t length)
17407910542SSiarzhuk Zharski {
17507910542SSiarzhuk Zharski 	Device *device = (Device *)cookie;
17607910542SSiarzhuk Zharski 	return device->Control(op, buffer, length);
17707910542SSiarzhuk Zharski }
17807910542SSiarzhuk Zharski 
17907910542SSiarzhuk Zharski 
18007910542SSiarzhuk Zharski static status_t
SiS7018_close(void * cookie)18107910542SSiarzhuk Zharski SiS7018_close(void *cookie)
18207910542SSiarzhuk Zharski {
18307910542SSiarzhuk Zharski 	Device *device = (Device *)cookie;
18407910542SSiarzhuk Zharski 	return device->Close();
18507910542SSiarzhuk Zharski }
18607910542SSiarzhuk Zharski 
18707910542SSiarzhuk Zharski 
18807910542SSiarzhuk Zharski static status_t
SiS7018_free(void * cookie)18907910542SSiarzhuk Zharski SiS7018_free(void *cookie)
19007910542SSiarzhuk Zharski {
19107910542SSiarzhuk Zharski 	Device *device = (Device *)cookie;
19207910542SSiarzhuk Zharski 	return device->Free();
19307910542SSiarzhuk Zharski }
19407910542SSiarzhuk Zharski 
19507910542SSiarzhuk Zharski 
19607910542SSiarzhuk Zharski const char **
publish_devices()19707910542SSiarzhuk Zharski publish_devices()
19807910542SSiarzhuk Zharski {
19907910542SSiarzhuk Zharski 	for (size_t i = 0; i < MAX_DEVICES; i++) {
20007910542SSiarzhuk Zharski 		if (gDevices[i] == NULL)
20107910542SSiarzhuk Zharski 			continue;
20207910542SSiarzhuk Zharski 
20307910542SSiarzhuk Zharski 		if (gDeviceNames[i])
20407910542SSiarzhuk Zharski 			TRACE("%s\n", gDeviceNames[i]);
20507910542SSiarzhuk Zharski 	}
20607910542SSiarzhuk Zharski 
20707910542SSiarzhuk Zharski 	return (const char **)&gDeviceNames[0];
20807910542SSiarzhuk Zharski }
20907910542SSiarzhuk Zharski 
21007910542SSiarzhuk Zharski 
21107910542SSiarzhuk Zharski device_hooks *
find_device(const char * name)21207910542SSiarzhuk Zharski find_device(const char *name)
21307910542SSiarzhuk Zharski {
21407910542SSiarzhuk Zharski 	static device_hooks deviceHooks = {
21507910542SSiarzhuk Zharski 		SiS7018_open,
21607910542SSiarzhuk Zharski 		SiS7018_close,
21707910542SSiarzhuk Zharski 		SiS7018_free,
21807910542SSiarzhuk Zharski 		SiS7018_control,
21907910542SSiarzhuk Zharski 		SiS7018_read,
22007910542SSiarzhuk Zharski 		SiS7018_write,
22107910542SSiarzhuk Zharski 		NULL,				// select
22207910542SSiarzhuk Zharski 		NULL				// deselect
22307910542SSiarzhuk Zharski 	};
22407910542SSiarzhuk Zharski 
22507910542SSiarzhuk Zharski 	return &deviceHooks;
22607910542SSiarzhuk Zharski }
22707910542SSiarzhuk Zharski 
228