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