diff --git a/src/add-ons/kernel/drivers/audio/Jamfile b/src/add-ons/kernel/drivers/audio/Jamfile index ad21de9075..341200f730 100644 --- a/src/add-ons/kernel/drivers/audio/Jamfile +++ b/src/add-ons/kernel/drivers/audio/Jamfile @@ -5,6 +5,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers audio cmedia ; SubInclude HAIKU_TOP src add-ons kernel drivers audio echo ; SubInclude HAIKU_TOP src add-ons kernel drivers audio emuxki ; SubInclude HAIKU_TOP src add-ons kernel drivers audio hda ; +SubInclude HAIKU_TOP src add-ons kernel drivers audio ice1712 ; SubInclude HAIKU_TOP src add-ons kernel drivers audio module_driver ; SubInclude HAIKU_TOP src add-ons kernel drivers audio null ; SubInclude HAIKU_TOP src add-ons kernel drivers audio sb16 ; diff --git a/src/add-ons/kernel/drivers/audio/ice1712/Jamfile b/src/add-ons/kernel/drivers/audio/ice1712/Jamfile new file mode 100644 index 0000000000..b432abf8da --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/Jamfile @@ -0,0 +1,16 @@ +SubDir HAIKU_TOP src add-ons kernel drivers audio ice1712 ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +UsePrivateHeaders media ; + +KernelAddon ice1712 : + debug.c + ice1712.c + io.c + midi.c + multi.c + util.c +; + + diff --git a/src/add-ons/kernel/drivers/audio/ice1712/debug.c b/src/add-ons/kernel/drivers/audio/ice1712/debug.c new file mode 100644 index 0000000000..fa769fe4cb --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/debug.c @@ -0,0 +1,79 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#include +#include +#include +#include +#include +#include "debug.h" +#include "ice1712.h" + +#if DEBUG > 0 +static const char * logfile="/boot/home/"DRIVER_NAME".log"; +static sem_id loglock; +#endif + +void debug_printf(const char *text,...); +void log_printf(const char *text,...); +void log_create(void); + +void debug_printf(const char *text,...) +{ + char buf[1024]; + va_list ap; + + va_start(ap,text); + vsprintf(buf,text,ap); + va_end(ap); + + dprintf(DRIVER_NAME ": %s",buf); +} + +void log_create(void) +{ +#if DEBUG > 0 + int fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); + const char *text = "Driver for " DRIVER_NAME ", Version " VERSION "\n=================\n"; + loglock = create_sem(1,"logfile sem"); + write(fd,text,strlen(text)); + close(fd); +#endif +} + +void log_printf(const char *text,...) +{ +#if DEBUG > 0 + int fd; + char buf[1024]; + va_list ap; + + va_start(ap,text); + vsprintf(buf,text,ap); + va_end(ap); + + dprintf(DRIVER_NAME ": %s",buf); + + acquire_sem(loglock); + fd = open(logfile, O_WRONLY | O_APPEND); + if (fd > 0) + { + write(fd, buf, strlen(buf)); + close(fd); + } + release_sem(loglock); + + #if DEBUG > 1 + snooze(150000); + #endif +#endif +} + diff --git a/src/add-ons/kernel/drivers/audio/ice1712/debug.h b/src/add-ons/kernel/drivers/audio/ice1712/debug.h new file mode 100644 index 0000000000..41a5efacf2 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/debug.h @@ -0,0 +1,54 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +/* + * PRINT() executes dprintf if DEBUG = 0 (disabled), or expands to LOG() when DEBUG > 0 + * TRACE() executes dprintf if DEBUG > 0 + * LOG() executes dprintf and writes to the logfile if DEBUG > 0 + */ + +/* DEBUG == 0, no debugging, PRINT writes to syslog + * DEBUG == 1, TRACE & LOG, PRINT + * DEBUG == 2, TRACE & LOG, PRINT with snooze() + */ +#undef DEBUG + +#ifndef DEBUG +// #define DEBUG 1 +#endif + +#undef PRINT_ICE +#undef TRACE_ICE +#undef ASSERT_ICE + +#if DEBUG > 0 + #define PRINT_ICE(a) log_printf a +// #define TRACE_ICE(a) debug_printf a + #define TRACE_ICE(a) log_printf a + #define LOG_ICE(a) log_printf a + #define LOG_CREATE_ICE() log_create() + #define ASSERT_ICE(a) if (a) {} else LOG_ICE(("ASSERT failed! file = %s, line = %d\n",__FILE__,__LINE__)) + void log_create(); + void log_printf(const char *text,...); + void debug_printf(const char *text,...); +#else + void debug_printf(const char *text,...); + #define PRINT_ICE(a) debug_printf a + #define TRACE_ICE(a) ((void)(0)) + #define ASSERT_ICE(a) ((void)(0)) + #define LOG_ICE(a) ((void)(0)) + #define LOG_CREATE_ICE() +#endif + +#endif diff --git a/src/add-ons/kernel/drivers/audio/ice1712/ice1712.c b/src/add-ons/kernel/drivers/audio/ice1712/ice1712.c new file mode 100644 index 0000000000..6badfd70f0 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/ice1712.c @@ -0,0 +1,575 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "ice1712.h" +#include "ice1712_reg.h" +#include "io.h" +#include "midi_driver.h" +#include "multi.h" +#include "multi_audio.h" +#include "util.h" + + +//------------------------------------------------------ +//------------------------------------------------------ + +status_t init_hardware(void); +status_t init_driver(void); +void uninit_driver(void); +const char **publish_devices(void); +device_hooks *find_device(const char *); + +//------------------------------------------------------ + +int32 ice_1712_int(void *arg); + +//------------------------------------------------------ + +static char pci_name[] = B_PCI_MODULE_NAME; +pci_module_info *pci; +static char mpu401_name[] = B_MPU_401_MODULE_NAME; +generic_mpu401_module *mpu401; + +int32 num_cards = 0; +ice1712 cards[NUM_CARDS]; +int32 num_names = 0; +char *names[NUM_CARDS*20+1]; + +//------------------------------------------------------ +//------------------------------------------------------ + +int32 api_version = B_CUR_DRIVER_API_VERSION; + +#define MODULE_TEST_PATH "audio/multi/ice1712" + +//------------------------------------------------------ +//------------------------------------------------------ + +//void republish_devices(void); + +//extern image_id load_kernel_addon(const char *path); +//extern status_t unload_kernel_addon(image_id imid); + +//------------------------------------------------------ +//------------------------------------------------------ + +status_t init_hardware(void) +{ + int ix = 0; + pci_info info; + + memset(cards, 0, sizeof(ice1712) * NUM_CARDS); + LOG_CREATE_ICE(); + TRACE_ICE(("===init_hardware()===\n")); + + if (get_module(pci_name, (module_info **)&pci)) + return ENOSYS; + + while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { + if ((info.vendor_id == ICE1712_VENDOR_ID) && + (info.device_id == ICE1712_DEVICE_ID)) { + TRACE_ICE(("Found at least 1 card\n")); + put_module(pci_name); + return B_OK; + } + ix++; + } + put_module(pci_name); + return B_ERROR; +} + + +int32 +ice_1712_int(void *arg) +{ + ice1712 *ice = arg; + uint8 reg8 = 0; + uint16 reg16 = 0; + uint32 status = B_UNHANDLED_INTERRUPT; + +// interrupt from DMA PATH + reg8 = read_mt_uint8(ice, MT_DMA_INT_MASK_STATUS); + if (reg8 != 0) { + ice->buffer++; + ice->played_time = system_time(); + + release_sem_etc(ice->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE); + write_mt_uint8(ice, MT_DMA_INT_MASK_STATUS, reg8); + status = B_HANDLED_INTERRUPT; + } + +// interrupt from Controller Registers + reg8 = read_ccs_uint8(ice, CCS_INTERRUPT_STATUS); + if (reg8 != 0) { + write_ccs_uint8(ice, CCS_INTERRUPT_STATUS, reg8); + status = B_HANDLED_INTERRUPT; + } + +// interrupt from DS PATH + reg16 = read_ds_uint16(ice, DS_DMA_INT_STATUS); + if (reg16 != 0) { + //Ack interrupt + write_ds_uint16(ice, DS_DMA_INT_STATUS, reg16); + status = B_HANDLED_INTERRUPT; + } + + return status; +} + + +static status_t +ice1712_setup(ice1712 *ice) +{ + int result, i; + long result_l = 0; + uint8 eeprom_data[32]; + uint8 reg8 = 0; + + ice->irq = ice->info.u.h0.interrupt_line; + ice->Controller = ice->info.u.h0.base_registers[0]; + ice->DDMA = ice->info.u.h0.base_registers[1]; + ice->DMA_Path = ice->info.u.h0.base_registers[2]; + ice->Multi_Track = ice->info.u.h0.base_registers[3]; + + // Soft Reset + write_ccs_uint8(ice, CCS_CONTROL_STATUS, 0x81); + snooze(200000); + write_ccs_uint8(ice, CCS_CONTROL_STATUS, 0x01); + snooze(200000); + + result = read_eeprom(ice, eeprom_data); + + TRACE_ICE(("EEprom -> ")); + for (i = 0; i < 32; i++) + TRACE_ICE(("%x, ", eeprom_data[i])); + TRACE_ICE(("<- EEprom\n")); + + write_ccs_uint8(ice, CCS_SERR_SHADOW, 0x01); + + //Write all configurations register from EEProm + + //Write enable SVID +// (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x42, 2, 0x86); + //Change SVID + ice->info.device_id = eeprom_data[1] << 8 | eeprom_data[0]; + ice->info.vendor_id = eeprom_data[3] << 8 | eeprom_data[2]; + ice->product = ice->info.vendor_id << 16 | ice->info.device_id; +// (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x2C, 4, ice->product); + + //Write Disable SVID +// (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x42, 2, 0x06); + + TRACE_ICE(("Product ID : 0x%x\n", ice->product)); + + (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x60, 1, eeprom_data[6]); + (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x61, 1, eeprom_data[7]); + (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x62, 1, eeprom_data[8]); + (pci->write_pci_config)(ice->info.bus, ice->info.device, ice->info.function, 0x63, 1, eeprom_data[9]); + + write_cci_uint8(ice, CCI_GPIO_WRITE_MASK, eeprom_data[10]); + write_cci_uint8(ice, CCI_GPIO_DATA, eeprom_data[11]); + write_cci_uint8(ice, CCI_GPIO_DIRECTION_CONTROL, eeprom_data[12]); + write_cci_uint8(ice, CCI_CONS_POWER_DOWN, eeprom_data[13]); + write_cci_uint8(ice, CCI_MULTI_POWER_DOWN, eeprom_data[14]); + + ice->nb_MPU401 = ((eeprom_data[6] & 0x20) >> 5) + 1; + ice->nb_ADC = (((eeprom_data[6] & 0x0C) >> 2) + 1 ) * 2; + ice->nb_DAC = ((eeprom_data[6] & 0x03) + 1) * 2; + ice->spdif_config = eeprom_data[9] & 0x03; + + for (i = 0; i < ice->nb_MPU401; i++) { + sprintf(ice->midi_interf[i].name, "midi/ice1712/%ld/%d", ice - cards + 1, i + 1); + names[num_names++] = ice->midi_interf[i].name; + } + + switch (ice->product) + { + case ICE1712_SUBDEVICE_DELTA66 : + case ICE1712_SUBDEVICE_DELTA44 : + ice->gpio_cs_mask = DELTA66_CLK | DELTA66_DOUT | DELTA66_CODEC_CS_0 | DELTA66_CODEC_CS_1; + ice->analog_codec = (codec_info){DELTA66_CLK, 0, DELTA66_DOUT}; + break; + case ICE1712_SUBDEVICE_DELTA410 : + case ICE1712_SUBDEVICE_AUDIOPHILE_2496 : + case ICE1712_SUBDEVICE_DELTADIO2496 : + ice->gpio_cs_mask = AP2496_CLK | AP2496_DIN | AP2496_DOUT | AP2496_SPDIF_CS | AP2496_CODEC_CS; + ice->analog_codec = (codec_info){AP2496_CLK, AP2496_DIN, AP2496_DOUT}; + break; + case ICE1712_SUBDEVICE_DELTA1010 : + case ICE1712_SUBDEVICE_DELTA1010LT : + ice->gpio_cs_mask = DELTA1010LT_CLK | DELTA1010LT_DIN | DELTA1010LT_DOUT | DELTA1010LT_CS_NONE; + ice->analog_codec = (codec_info){DELTA1010LT_CLK, DELTA1010LT_DIN, DELTA1010LT_DOUT}; + break; + case ICE1712_SUBDEVICE_VX442 : + ice->gpio_cs_mask = VX442_SPDIF_CS | VX442_CODEC_CS_0 | VX442_CODEC_CS_1; + ice->analog_codec = (codec_info){VX442_CLK, VX442_DIN, VX442_DOUT}; + break; + } + + sprintf(ice->name, "%s/%ld", MODULE_TEST_PATH, ice - cards + 1); + names[num_names++] = ice->name; + names[num_names] = NULL; + + if ((eeprom_data[6] & 0x10) == 0) {//Consumer AC'97 Exist + TRACE_ICE(("Consumer AC'97 does exist\n")); + write_ccs_uint8(ice, CCS_CONS_AC97_COMMAND_STATUS, 0x40); + snooze(10000); + write_ccs_uint8(ice, CCS_CONS_AC97_COMMAND_STATUS, 0x00); + snooze(20000); + } else { + TRACE_ICE(("Consumer AC'97 does NOT exist\n")); + } + + ice->buffer_ready_sem = create_sem(0, "Buffer Exchange"); + +// TRACE_ICE(("installing interrupt : %0x\n", ice->irq)); + result_l = install_io_interrupt_handler(ice->irq, ice_1712_int, ice, 0); + if (result_l == B_OK) + TRACE_ICE(("Install Interrupt Handler == B_OK\n")); + else + TRACE_ICE(("Install Interrupt Handler != B_OK\n")); + + ice->mem_id_pb = alloc_mem(&ice->phys_addr_pb, &ice->log_addr_pb, + PLAYBACK_BUFFER_TOTAL_SIZE, + "playback buffer"); + + ice->mem_id_rec = alloc_mem(&ice->phys_addr_rec, &ice->log_addr_rec, + RECORD_BUFFER_TOTAL_SIZE, + "record buffer"); + + memset(ice->log_addr_pb, 0, PLAYBACK_BUFFER_TOTAL_SIZE); + memset(ice->log_addr_rec, 0, RECORD_BUFFER_TOTAL_SIZE); + + ice->sampling_rate = 0x08; + ice->buffer = 0; + ice->output_buffer_size = MAX_BUFFER_FRAMES; + ice->input_buffer_size = MAX_BUFFER_FRAMES; + + ice->total_output_channels = ice->nb_DAC; + if (ice->spdif_config & NO_IN_YES_OUT) + ice->total_output_channels += 2; + + ice->total_input_channels = ice->nb_ADC + 2; + if (ice->spdif_config & YES_IN_NO_OUT) + ice->total_input_channels += 2; + + //Write bits in the GPIO + write_cci_uint8(ice, CCI_GPIO_WRITE_MASK, ~(ice->gpio_cs_mask)); + //Deselect CS + write_cci_uint8(ice, CCI_GPIO_DATA, ice->gpio_cs_mask); + + //Just to route input to output +// write_mt_uint16(ice, MT_ROUTING_CONTROL_PSDOUT, 0x0101); +// write_mt_uint32(ice, MT_CAPTURED_DATA, 0x0000); + + //Unmask Interrupt + write_ccs_uint8(ice, CCS_CONTROL_STATUS, 0x41); + + reg8 = read_ccs_uint8(ice, CCS_INTERRUPT_MASK); + TRACE_ICE(("-----CCS----- = %x\n", reg8)); + write_ccs_uint8(ice, CCS_INTERRUPT_MASK, 0x6F); + +/* reg16 = read_ds_uint16(ice, DS_DMA_INT_MASK); + TRACE_ICE(("-----DS_DMA----- = %x\n", reg16)); + write_ds_uint16(ice, DS_DMA_INT_MASK, 0x0000); +*/ + reg8 = read_mt_uint8(ice, MT_DMA_INT_MASK_STATUS); + TRACE_ICE(("-----MT_DMA----- = %x\n", reg8)); + write_mt_uint8(ice, MT_DMA_INT_MASK_STATUS, 0x00); + + return B_OK; +}; + + +status_t +init_driver(void) +{ + int i = 0; + num_cards = 0; + + TRACE_ICE(("===init_driver()===\n")); + + if (get_module(pci_name, (module_info **)&pci)) + return ENOSYS; + + if (get_module(mpu401_name, (module_info **) &mpu401)) { + put_module(pci_name); + return ENOSYS; + } + + while ((*pci->get_nth_pci_info)(i, &cards[num_cards].info) == B_OK) + {//TODO check other Vendor_ID and DEVICE_ID + if ((cards[num_cards].info.vendor_id == ICE1712_VENDOR_ID) && + (cards[num_cards].info.device_id == ICE1712_DEVICE_ID)) + { + if (num_cards == NUM_CARDS) + { + TRACE_ICE(("Too many ice1712 cards installed!\n")); + break; + } + + if (ice1712_setup(&cards[num_cards]) != B_OK) + //Vendor_ID and Device_ID has been modified + { + TRACE_ICE(("Setup of ice1712 %d failed\n", num_cards + 1)); + } + else + { + num_cards++; + } + } + i++; + } + + TRACE_ICE(("Number of succesfully initialised card : %d\n", num_cards)); + + if (num_cards == 0) { + put_module(pci_name); + put_module(mpu401_name); + return ENODEV; + } + return B_OK; +} + + +static void +ice_1712_shutdown(ice1712 *ice) +{ + long result_l; + + result_l = remove_io_interrupt_handler(ice->irq, ice_1712_int, ice); + if (result_l == B_OK) + TRACE_ICE(("remove Interrupt result == B_OK\n")); + else + TRACE_ICE(("remove Interrupt result != B_OK\n")); + + if (ice->mem_id_pb != B_ERROR) + delete_area(ice->mem_id_pb); + + if (ice->mem_id_rec != B_ERROR) + delete_area(ice->mem_id_rec); + + codec_write(ice, AK45xx_RESET_REGISTER, 0x00); +} + + +void +uninit_driver(void) +{ + int ix, cnt = num_cards; + + TRACE_ICE(("===uninit_driver()===\n")); + + num_cards = 0; + + for (ix = 0; ix < cnt; ix++) { + ice_1712_shutdown(&cards[ix]); + } + memset(&cards, 0, sizeof(cards)); + put_module(mpu401_name); + put_module(pci_name); +} + +//------------------------------------------------------ + +const char ** +publish_devices(void) +{ + int ix = 0; + TRACE_ICE(("===publish_devices()===\n")); + + for (ix=0; names[ix]; ix++) { + TRACE_ICE(("publish %s\n", names[ix])); + } + return (const char **)names; +} + + +static status_t +ice_1712_open(const char *name, uint32 flags, void **cookie) +{//Not Implemented (partialy only) + TRACE_ICE(("===open()===\n")); + *cookie = cards; + return B_OK; +} + + +static status_t +ice_1712_close(void *cookie) +{ + TRACE_ICE(("===close()===\n")); + return B_ERROR; +} + + +static status_t +ice_1712_free(void *cookie) +{ + TRACE_ICE(("===free()===\n")); + return B_ERROR; +} + + +static status_t +ice_1712_control(void *cookie, uint32 op, void *arg, size_t len) +{ + switch (op) + { + case B_MULTI_GET_DESCRIPTION : + TRACE_ICE(("B_MULTI_GET_DESCRIPTION\n")); + return ice1712_get_description((ice1712 *)cookie, (multi_description*)arg); + case B_MULTI_GET_EVENT_INFO : + TRACE_ICE(("B_MULTI_GET_EVENT_INFO\n")); + return B_ERROR; + case B_MULTI_SET_EVENT_INFO : + TRACE_ICE(("B_MULTI_SET_EVENT_INFO\n")); + return B_ERROR; + case B_MULTI_GET_EVENT : + TRACE_ICE(("B_MULTI_GET_EVENT\n")); + return B_ERROR; + case B_MULTI_GET_ENABLED_CHANNELS : + TRACE_ICE(("B_MULTI_GET_ENABLED_CHANNELS\n")); + return ice1712_get_enabled_channels((ice1712*)cookie, (multi_channel_enable*)arg); + case B_MULTI_SET_ENABLED_CHANNELS : + TRACE_ICE(("B_MULTI_SET_ENABLED_CHANNELS\n")); + return ice1712_set_enabled_channels((ice1712*)cookie, (multi_channel_enable*)arg); + case B_MULTI_GET_GLOBAL_FORMAT : + TRACE_ICE(("B_MULTI_GET_GLOBAL_FORMAT\n")); + return ice1712_get_global_format((ice1712*)cookie, (multi_format_info *)arg); + case B_MULTI_SET_GLOBAL_FORMAT : + TRACE_ICE(("B_MULTI_SET_GLOBAL_FORMAT\n")); + return ice1712_set_global_format((ice1712*)cookie, (multi_format_info *)arg); + case B_MULTI_GET_CHANNEL_FORMATS : + TRACE_ICE(("B_MULTI_GET_CHANNEL_FORMATS\n")); + return B_ERROR; + case B_MULTI_SET_CHANNEL_FORMATS : + TRACE_ICE(("B_MULTI_SET_CHANNEL_FORMATS\n")); + return B_ERROR; + case B_MULTI_GET_MIX : + TRACE_ICE(("B_MULTI_GET_MIX\n")); + return ice1712_get_mix((ice1712*)cookie, (multi_mix_value_info *)arg); + case B_MULTI_SET_MIX : + TRACE_ICE(("B_MULTI_SET_MIX\n")); + return ice1712_set_mix((ice1712*)cookie, (multi_mix_value_info *)arg); + case B_MULTI_LIST_MIX_CHANNELS : + TRACE_ICE(("B_MULTI_LIST_MIX_CHANNELS\n")); + return ice1712_list_mix_channels((ice1712*)cookie, (multi_mix_channel_info *)arg); + case B_MULTI_LIST_MIX_CONTROLS : + TRACE_ICE(("B_MULTI_LIST_MIX_CONTROLS\n")); + return ice1712_list_mix_controls((ice1712*)cookie, (multi_mix_control_info *)arg); + case B_MULTI_LIST_MIX_CONNECTIONS : + TRACE_ICE(("B_MULTI_LIST_MIX_CONNECTIONS\n")); + return ice1712_list_mix_connections((ice1712*)cookie, (multi_mix_connection_info *)arg); + case B_MULTI_GET_BUFFERS : + TRACE_ICE(("B_MULTI_GET_BUFFERS\n")); + return ice1712_get_buffers((ice1712*)cookie, (multi_buffer_list*)arg); + case B_MULTI_SET_BUFFERS : + TRACE_ICE(("B_MULTI_SET_BUFFERS\n")); + return B_ERROR; + case B_MULTI_SET_START_TIME : + TRACE_ICE(("B_MULTI_SET_START_TIME\n")); + return B_ERROR; + case B_MULTI_BUFFER_EXCHANGE : +// TRACE_ICE(("B_MULTI_BUFFER_EXCHANGE\n")); + return ice1712_buffer_exchange((ice1712*)cookie, (multi_buffer_info *)arg); + case B_MULTI_BUFFER_FORCE_STOP : + TRACE_ICE(("B_MULTI_BUFFER_FORCE_STOP\n")); + return ice1712_buffer_force_stop((ice1712*)cookie); + case B_MULTI_LIST_EXTENSIONS : + TRACE_ICE(("B_MULTI_LIST_EXTENSIONS\n")); + return B_ERROR; + case B_MULTI_GET_EXTENSION : + TRACE_ICE(("B_MULTI_GET_EXTENSION\n")); + return B_ERROR; + case B_MULTI_SET_EXTENSION : + TRACE_ICE(("B_MULTI_SET_EXTENSION\n")); + return B_ERROR; + case B_MULTI_LIST_MODES : + TRACE_ICE(("B_MULTI_LIST_MODES\n")); + return B_ERROR; + case B_MULTI_GET_MODE : + TRACE_ICE(("B_MULTI_GET_MODE\n")); + return B_ERROR; + case B_MULTI_SET_MODE : + TRACE_ICE(("B_MULTI_SET_MODE\n")); + return B_ERROR; + + default : + TRACE_ICE(("ERROR: unknown multi_control %#x\n", op)); + return B_ERROR; + } +} + + +static status_t +ice_1712_read(void *cookie, off_t position, void *buf, size_t *num_bytes) +{ + TRACE_ICE(("===read()===\n")); + *num_bytes = 0; + return B_IO_ERROR; +} + + +static status_t +ice_1712_write(void *cookie, off_t position, const void *buffer, size_t *num_bytes) +{ + TRACE_ICE(("===write()===\n")); + *num_bytes = 0; + return B_IO_ERROR; +} + + +device_hooks ice_1712_hooks = +{ + ice_1712_open, + ice_1712_close, + ice_1712_free, + ice_1712_control, + ice_1712_read, + ice_1712_write, + NULL, + NULL, + NULL, + NULL +}; + + +device_hooks * +find_device(const char * name) +{ + int ix; + + PRINT_ICE(("ice1712: find_device(%s)\n", name)); + + for (ix=0; ix + +#define DRIVER_NAME "ice1712" +#define VERSION "0.3" + +#define ICE1712_VENDOR_ID 0x1412 +#define ICE1712_DEVICE_ID 0x1712 + + +typedef enum product_t { + ICE1712_SUBDEVICE_DELTA1010 = 0x121430d6, + ICE1712_SUBDEVICE_DELTADIO2496 = 0x121431d6, + ICE1712_SUBDEVICE_DELTA66 = 0x121432d6, + ICE1712_SUBDEVICE_DELTA44 = 0x121433d6, + ICE1712_SUBDEVICE_AUDIOPHILE_2496 = 0x121434d6, + ICE1712_SUBDEVICE_DELTA410 = 0x121438d6, + ICE1712_SUBDEVICE_DELTA1010LT = 0x12143bd6, + ICE1712_SUBDEVICE_VX442 = 0x12143cd6, +} product_t; + +#define NUM_CARDS 4 +#define MAX_ADC 12 // + the output of the Digital mixer +#define MAX_DAC 10 +#define SWAPPING_BUFFERS 2 +#define SAMPLE_SIZE 4 +#define MIN_BUFFER_FRAMES 64 +#define MAX_BUFFER_FRAMES 2048 + +#define PLAYBACK_BUFFER_SIZE (MAX_BUFFER_FRAMES * MAX_DAC * SAMPLE_SIZE) +#define RECORD_BUFFER_SIZE (MAX_BUFFER_FRAMES * MAX_ADC * SAMPLE_SIZE) + +#define PLAYBACK_BUFFER_TOTAL_SIZE (PLAYBACK_BUFFER_SIZE * SWAPPING_BUFFERS) +#define RECORD_BUFFER_TOTAL_SIZE (RECORD_BUFFER_SIZE * SWAPPING_BUFFERS) + +#define SPDIF_LEFT 8 +#define SPDIF_RIGHT 9 +#define MIXER_OUT_LEFT 10 +#define MIXER_OUT_RIGHT 11 + +typedef enum { + NO_IN_NO_OUT = 0, + NO_IN_YES_OUT = 1, + YES_IN_NO_OUT = 2, + YES_IN_YES_OUT = 3, +} _spdif_config_ ; + +typedef struct _midi_dev { + struct _ice1712_ *card; + void *driver; + void *cookie; + int32 count; + char name[64]; +} midi_dev; + +typedef struct codec_info +{ + uint8 clock; + uint8 data_in; + uint8 data_out; + uint8 reserved[5]; +} codec_info; + +typedef struct _ice1712_ +{ + uint32 irq; + pci_info info; + char name[128]; + + midi_dev midi_interf[2]; + + uint32 Controller; //PCI_10 + uint32 DDMA; //PCI_14 + uint32 DMA_Path; //PCI_18 + uint32 Multi_Track; //PCI_1C + + int8 nb_ADC; //Mono Channel + int8 nb_DAC; //Mono Channel + _spdif_config_ spdif_config; + int8 nb_MPU401; + + product_t product; + uint8 gpio_cs_mask; //a Mask for removing all Chip select + + //We hope all manufacturer will not use different codec on the same card + codec_info analog_codec; + codec_info digital_codec; + + uint32 buffer; + bigtime_t played_time; + + //Output + area_id mem_id_pb; + void *phys_addr_pb, *log_addr_pb; + uint32 output_buffer_size; //in frames + uint8 total_output_channels; + + //Input + area_id mem_id_rec; + void *phys_addr_rec, *log_addr_rec; + uint32 input_buffer_size; //in frames + uint8 total_input_channels; + + sem_id buffer_ready_sem; + + uint8 sampling_rate; //in the format of the register + +} ice1712; + +extern int32 num_cards; +extern ice1712 cards[NUM_CARDS]; + +//??????? +#define GPIO_SPDIF_STATUS 0x02 //Status +#define GPIO_SPDIF_CCLK 0x04 //data Clock +#define GPIO_SPDIF_DOUT 0x08 //data output + +//For Delta 66 / Delta 44 +#define DELTA66_DOUT 0x10 // data output +#define DELTA66_CLK 0x20 // clock +#define DELTA66_CODEC_CS_0 0x40 // AK4524 #0 +#define DELTA66_CODEC_CS_1 0x80 // AK4524 #1 + +//For AudioPhile 2496 / Delta 410 +#define AP2496_CLK 0x02 // clock +#define AP2496_DIN 0x04 // data input +#define AP2496_DOUT 0x08 // data output +#define AP2496_SPDIF_CS 0x10 // CS8427 chip select +#define AP2496_CODEC_CS 0x20 // AK4528 chip select + +//For Delta 1010 LT +#define DELTA1010LT_CLK 0x02 // clock +#define DELTA1010LT_DIN 0x04 // data input +#define DELTA1010LT_DOUT 0x08 // data output +#define DELTA1010LT_CODEC_CS_0 0x00 // AK4524 #0 +#define DELTA1010LT_CODEC_CS_1 0x10 // AK4524 #1 +#define DELTA1010LT_CODEC_CS_2 0x20 // AK4524 #2 +#define DELTA1010LT_CODEC_CS_3 0x30 // AK4524 #3 +#define DELTA1010LT_SPDIF_CS 0x40 // CS8427 +#define DELTA1010LT_CS_NONE 0x50 // All CS deselected + +//For VX442 +#define VX442_CLK 0x02 // clock +#define VX442_DIN 0x04 // data input +#define VX442_DOUT 0x08 // data output +#define VX442_SPDIF_CS 0x10 // CS8427 +#define VX442_CODEC_CS_0 0x20 // ?? #0 +#define VX442_CODEC_CS_1 0x40 // ?? #1 + +#define AK45xx_BITS_TO_WRITE 16 +//2 - Chip Address (10b) +//1 - R/W (Always 1 for Writing) +//5 - Register Address +//8 - Data + +//Register definition for the AK45xx codec (xx = 24 or 28) +#define AK45xx_DELAY 100 //Clock Delay +#define AK45xx_CHIP_ADDRESS 0x02 //Chip address of the codec +#define AK45xx_RESET_REGISTER 0x01 +#define AK45xx_CLOCK_FORMAT_REGISTER 0x02 +//Other register are not defined cause they are not used, I'm very lazy... + +#define CS84xx_BITS_TO_WRITE 24 +//7 - Chip Address (0010000b) +//1 - R/W (1 for Reading) +//8 - Register MAP +//8 - Data + +//Register definition for the CS84xx codec (xx = 27) +#define CS84xx_DELAY 100 //Clock Delay +#define CS84xx_CHIP_ADDRESS 0x10 //Chip address of the codec +#define CS84xx_CONTROL_1_PORT_REG 0x01 +#define CS84xx_CONTROL_2_PORT_REG 0x02 +#define CS84xx_DATA_FLOW_CONTROL_REG 0x03 +#define CS84xx_CLOCK_SOURCE_REG 0x04 +#define CS84xx_SERIAL_INPUT_FORMAT_REG 0x05 +#define CS84xx_SERIAL_OUTPUT_FORMAT_REG 0x06 +//Other register are not defined cause they are not used, I'm very lazy... + + +/* A default switch for all suported product + switch (card->product) + { + case ICE1712_SUBDEVICE_DELTA1010 : + break; + case ICE1712_SUBDEVICE_DELTADIO2496 : + break; + case ICE1712_SUBDEVICE_DELTA66 : + break; + case ICE1712_SUBDEVICE_DELTA44 : + break; + case ICE1712_SUBDEVICE_AUDIOPHILE : + break; + case ICE1712_SUBDEVICE_DELTA410 : + break; + case ICE1712_SUBDEVICE_DELTA1010LT : + break; + case ICE1712_SUBDEVICE_VX442 : + break; + } +*/ + +#endif diff --git a/src/add-ons/kernel/drivers/audio/ice1712/ice1712_reg.h b/src/add-ons/kernel/drivers/audio/ice1712/ice1712_reg.h new file mode 100644 index 0000000000..b1a0ef5928 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/ice1712_reg.h @@ -0,0 +1,167 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#ifndef _ICE1712_REG_H_ +#define _ICE1712_REG_H_ + +//------------------------------------------------------ +//------------------------------------------------------ +//PCI Interface and Configuration Registers (Page 3.1) +//Table 3.1 +/* +#define PCI_VENDOR_ID 0x00 //2 bytes +#define PCI_DEVICE_ID 0x02 //2 bytes +#define PCI_COMMAND 0x04 //2 bytes +#define PCI_DEVICE_STATUS 0x06 //2 bytes +#define PCI_REVISION_ID 0x08 //1 byte +#define PCI_CLASS_CODE 0x0A //2 bytes +#define PCI_LATENCY_TIMER 0x0D //1 byte +#define PCI_HEADER_TYPE 0x0E //1 byte +#define PCI_BIST 0x0F //1 byte +#define PCI_CONTROLLER_BASE_AD 0x10 //4 bytes +#define PCI_DDMA_BASE_AD 0x14 //4 bytes +#define PCI_DMA_BASE_AD 0x18 //4 bytes +#define PCI_MULTI_BASE_AD 0x1C //4 bytes +#define PCI_SUB_VENDOR_ID 0x2C //2 bytes +#define PCI_SUB_SYSTEM_ID 0x2E //2 bytes +#define PCI_CAPABILITY_POINTER 0x34 //4 bytes +#define PCI_INT_PIN_LINE 0x3C //2 bytes +#define PCI_LATENCY_GRANT 0x3E //2 bytes +#define PCI_LEGACY_AUDIO_CONTROL 0x40 //2 bytes +#define PCI_LEGACY_CONF_CONTROL 0x42 //2 bytes +#define PCI_HARD_CONF_CONTROL 0x60 //4 bytes +#define PCI_CAPABILITY_ID 0x80 //1 byte +#define PCI_NEXT_ITEM_POINTER 0x81 //1 byte +#define PCI_POWER_CAPABILITY 0x82 //2 bytes +#define PCI_POWER_CONTROL_STATUS 0x84 //2 bytes +#define PCI_PMCSR_EXT_DATA 0x86 //2 bytes +*/ +//------------------------------------------------------ +//------------------------------------------------------ +//CCSxx Controller Register Map (Page 4.3) +//Table 4.2 +#define CCS_CONTROL_STATUS 0x00 //1 byte +#define CCS_INTERRUPT_MASK 0x01 //1 byte +#define CCS_INTERRUPT_STATUS 0x02 //1 byte +#define CCS_CCI_INDEX 0x03 //1 byte +#define CCS_CCI_DATA 0x04 //1 byte +#define CCS_NMI_STATUS_1 0x05 //1 byte +#define CCS_NMI_DATA 0x06 //1 byte +#define CCS_NMI_INDEX 0x07 //1 byte +#define CCS_CONS_AC97_INDEX 0x08 //1 byte +#define CCS_CONS_AC97_COMMAND_STATUS 0x09 //1 byte +#define CCS_CONS_AC97_DATA 0x0A //2 bytes +#define CCS_MIDI_1_DATA 0x0C //1 byte +#define CCS_MIDI_1_COMMAND_STATUS 0x0D //1 byte +#define CCS_NMI_STATUS_2 0x0E //1 byte +#define CCS_GAME_PORT 0x0F //1 byte +#define CCS_I2C_DEV_ADDRESS 0x10 //1 byte +#define CCS_I2C_BYTE_ADDRESS 0x11 //1 byte +#define CCS_I2C_DATA 0x12 //1 byte +#define CCS_I2C_CONTROL_STATUS 0x13 //1 byte +#define CCS_CONS_DMA_BASE_ADDRESS 0x14 //4 bytes +#define CCS_CONS_DMA_COUNT_ADDRESS 0x18 //2 bytes +#define CCS_SERR_SHADOW 0x1B //1 byte +#define CCS_MIDI_2_DATA 0x1C //1 byte +#define CCS_MIDI_2_COMMAND_STATUS 0x1D //1 byte +#define CCS_TIMER 0x1E //2 bytes +//------------------------------------------------------ +//------------------------------------------------------ +//Controller Indexed Register (Page 4.12) +#define CCI_PB_TERM_COUNT_HI 0x00 //1 byte +#define CCI_PB_TERM_COUNT_LO 0x01 //1 byte +#define CCI_PB_CONTROL 0x02 //1 byte +#define CCI_PB_LEFT_VOLUME 0x03 //1 byte +#define CCI_PB_RIGHT_VOLUME 0x04 //1 byte +#define CCI_SOFT_VOLUME 0x05 //1 byte +#define CCI_PB_SAMPLING_RATE_LO 0x06 //1 byte +#define CCI_PB_SAMPLING_RATE_MI 0x07 //1 byte +#define CCI_PB_SAMPLING_RATE_HI 0x08 //1 byte +#define CCI_REC_TERM_COUNT_HI 0x10 //1 byte +#define CCI_REC_TERM_COUNT_LO 0x11 //1 byte +#define CCI_REC_CONTROL 0x12 //1 byte +#define CCI_GPIO_DATA 0x20 //1 byte +#define CCI_GPIO_WRITE_MASK 0x21 //1 byte +#define CCI_GPIO_DIRECTION_CONTROL 0x22 //1 byte +#define CCI_CONS_POWER_DOWN 0x30 //1 byte +#define CCI_MULTI_POWER_DOWN 0x31 //1 byte +//------------------------------------------------------ +//------------------------------------------------------ +//Consumer Section DMA Channel Registers (Page 4.20) +//Table 4.4 +#define DS_DMA_INT_MASK 0x00 //2 bytes +#define DS_DMA_INT_STATUS 0x02 //2 bytes +#define DS_CHANNEL_DATA 0x04 //4 bytes +#define DS_CHANNEL_INDEX 0x08 //1 byte +//------------------------------------------------------ +//------------------------------------------------------ +//Professional Multi-Track Control Registers (Page 4.24) +//Table 4.7 +#define MT_DMA_INT_MASK_STATUS 0x00 //1 byte +#define MT_SAMPLING_RATE_SELECT 0x01 //1 byte +#define MT_I2S_DATA_FORMAT 0x02 //1 byte +#define MT_PROF_AC97_INDEX 0x04 //1 byte +#define MT_PROF_AC97_COMMAND_STATUS 0x05 //1 byte +#define MT_PROF_AC97_DATA 0x06 //2 bytes +#define MT_PROF_PB_DMA_BASE_ADDRESS 0x10 //4 bytes +#define MT_PROF_PB_DMA_COUNT_ADDRESS 0x14 //2 bytes +#define MT_PROF_PB_DMA_TERM_COUNT 0x16 //2 bytes +#define MT_PROF_PB_CONTROL 0x18 //1 byte +#define MT_PROF_REC_DMA_BASE_ADDRESS 0x20 //4 bytes +#define MT_PROF_REC_DMA_COUNT_ADDRESS 0x24 //2 bytes +#define MT_PROF_REC_DMA_TERM_COUNT 0x26 //2 bytes +#define MT_PROF_REC_CONTROL 0x28 //1 byte +#define MT_ROUTING_CONTROL_PSDOUT 0x30 //2 bytes +#define MT_ROUTING_CONTROL_SPDOUT 0x32 //2 bytes +#define MT_CAPTURED_DATA 0x34 //4 bytes +#define MT_LR_VOLUME_CONTROL 0x38 //2 bytes +#define MT_VOLUME_CONTROL_CHANNEL_INDEX 0x3A //1 byte +#define MT_VOLUME_CONTROL_RATE 0x3B //1 byte +#define MT_MIXER_MONITOR_RETURN 0x3C //1 byte +#define MT_PEAK_METER_INDEX 0x3E //1 byte +#define MT_PEAK_METER_DATA 0x3F //1 byte +//------------------------------------------------------ +//------------------------------------------------------ +#define I2C_EEPROM_ADDRESS_READ 0xA0 //1010 0000 +#define I2C_EEPROM_ADDRESS_WRITE 0xA1 //1010 0001 +//------------------------------------------------------ +//------------------------------------------------------ +#define SPDIF_STEREO_IN 0x02 //0000 0010 +#define SPDIF_STEREO_OUT 0x01 //0000 0001 +//------------------------------------------------------ +//------------------------------------------------------ + +//------------------------------------------------------ +//------------------------------------------------------ + +//------------------------------------------------------ +//------------------------------------------------------ + +//------------------------------------------------------ +//------------------------------------------------------ + +//------------------------------------------------------ +//------------------------------------------------------ + +//------------------------------------------------------ +//------------------------------------------------------ + +//------------------------------------------------------ +//------------------------------------------------------ + +//------------------------------------------------------ +//------------------------------------------------------ + +//------------------------------------------------------ +//------------------------------------------------------ + +//------------------------------------------------------ +//------------------------------------------------------ + +#endif diff --git a/src/add-ons/kernel/drivers/audio/ice1712/io.c b/src/add-ons/kernel/drivers/audio/ice1712/io.c new file mode 100644 index 0000000000..ad755598fc --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/io.c @@ -0,0 +1,459 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#include "io.h" +#include "ice1712_reg.h" +#include "debug.h" + +extern pci_module_info *pci; + + +static void ak45xx_write_gpio(ice1712 *ice, uint8 reg_addr, + uint8 data, uint8 chip_select); + +static void cs84xx_write_gpio(ice1712 *ice, uint8 reg_addr, + uint8 data, uint8 chip_select); + +//Address are [PCI_10] + xx + +uint8 +read_ccs_uint8(ice1712 *ice, int8 regno) +{ + return pci->read_io_8(ice->Controller + regno); +}; + + +uint16 +read_ccs_uint16(ice1712 *ice, int8 regno) +{ + return pci->read_io_16(ice->Controller + regno); +}; + + +uint32 +read_ccs_uint32(ice1712 *ice, int8 regno) +{ + return pci->read_io_32(ice->Controller + regno); +}; + + +void +write_ccs_uint8(ice1712 *ice, int8 regno, uint8 value) +{ + pci->write_io_8(ice->Controller + regno, value); +}; + + +void +write_ccs_uint16(ice1712 *ice, int8 regno, uint16 value) +{ + pci->write_io_16(ice->Controller + regno, value); +}; + + +void +write_ccs_uint32(ice1712 *ice, int8 regno, uint32 value) +{ + pci->write_io_32(ice->Controller + regno, value); +}; + + +uint8 +read_cci_uint8(ice1712 *ice, int8 index) +{ + write_ccs_uint8(ice, CCS_CCI_INDEX, index); + return read_ccs_uint8(ice, CCS_CCI_DATA); +}; + + +void +write_cci_uint8(ice1712 *ice, int8 index, uint8 value) +{ + write_ccs_uint8(ice, CCS_CCI_INDEX, index); + write_ccs_uint8(ice, CCS_CCI_DATA, value); +}; + +//-------------------------------------------------- +//-------------------------------------------------- +//Address are [PCI_14] + xx + +uint8 +read_ddma_uint8(ice1712 *ice, int8 regno) +{ + return pci->read_io_8(ice->DDMA + regno); +}; + + +uint16 +read_ddma_uint16(ice1712 *ice, int8 regno) +{ + return pci->read_io_16(ice->DDMA + regno); +}; + + +uint32 +read_ddma_uint32(ice1712 *ice, int8 regno) +{ + return pci->read_io_32(ice->DDMA + regno); +}; + + +void +write_ddma_uint8(ice1712 *ice, int8 regno, uint8 value) +{ + pci->write_io_8(ice->DDMA + regno, value); +}; + + +void +write_ddma_uint16(ice1712 *ice, int8 regno, uint16 value) +{ + pci->write_io_16(ice->DDMA + regno, value); +}; + + +void +write_ddma_uint32(ice1712 *ice, int8 regno, uint32 value) +{ + pci->write_io_32(ice->DDMA + regno, value); +}; + + +//-------------------------------------------------- +//-------------------------------------------------- +//Address are [PCI_18] + x +uint8 +read_ds_uint8(ice1712 *ice, int8 regno) +{ + return pci->read_io_8(ice->DMA_Path + regno); +}; + + +uint16 +read_ds_uint16(ice1712 *ice, int8 regno) +{ + return pci->read_io_16(ice->DMA_Path + regno); +}; + + +uint32 +read_ds_uint32(ice1712 *ice, int8 regno) +{ + return pci->read_io_32(ice->DMA_Path + regno); +}; + + +void +write_ds_uint8(ice1712 *ice, int8 regno, uint8 value) +{ + pci->write_io_8(ice->DMA_Path + regno, value); +}; + + +void +write_ds_uint16(ice1712 *ice, int8 regno, uint16 value) +{ + pci->write_io_16(ice->DMA_Path + regno, value); +}; + + +void +write_ds_uint32(ice1712 *ice, int8 regno, uint32 value) +{ + pci->write_io_32(ice->DMA_Path + regno, value); +}; + + +uint32 +read_ds_channel_data(ice1712 *ice, uint8 channel, ds8_register index) +{ + uint8 ds8_channel_index = channel << 4 | index; + + write_ds_uint8(ice, DS_CHANNEL_INDEX, ds8_channel_index); + return read_ds_uint32(ice, DS_CHANNEL_DATA); +} + + +void +write_ds_channel_data(ice1712 *ice, uint8 channel, ds8_register index, uint32 data) +{ + uint8 ds8_channel_index = channel << 4 | index; + + write_ds_uint8(ice, DS_CHANNEL_INDEX, ds8_channel_index); + write_ds_uint32(ice, DS_CHANNEL_DATA, data); +} + + +//-------------------------------------------------- +//-------------------------------------------------- +//Address are [PCI_1C] + xx + +uint8 +read_mt_uint8(ice1712 *ice, int8 regno) +{ + return pci->read_io_8(ice->Multi_Track + regno); +}; + + +uint16 +read_mt_uint16(ice1712 *ice, int8 regno) +{ + return pci->read_io_16(ice->Multi_Track + regno); +}; + + +uint32 +read_mt_uint32(ice1712 *ice, int8 regno) +{ + return pci->read_io_32(ice->Multi_Track + regno); +}; + +void +write_mt_uint8(ice1712 *ice, int8 regno, uint8 value) +{ + pci->write_io_8(ice->Multi_Track + regno, value); +}; + + +void +write_mt_uint16(ice1712 *ice, int8 regno, uint16 value) +{ + pci->write_io_16(ice->Multi_Track + regno, value); +}; + + +void +write_mt_uint32(ice1712 *ice, int8 regno, uint32 value) +{ + pci->write_io_32(ice->Multi_Track + regno, value); +}; + + +int16 +read_i2c(ice1712 *ice, uint8 dev_addr, uint8 byte_addr) +{//return -1 if error else return an uint8 + + if (read_ccs_uint8(ice, CCS_I2C_CONTROL_STATUS) != 0x80) + return -1; + write_ccs_uint8(ice, CCS_I2C_BYTE_ADDRESS, byte_addr); + write_ccs_uint8(ice, CCS_I2C_DEV_ADDRESS, dev_addr); + snooze(1000); + return read_ccs_uint8(ice, CCS_I2C_DATA); +} + + +int16 +write_i2c(ice1712 *ice, uint8 dev_addr, uint8 byte_addr, uint8 value) +{//return -1 if error else return 0 + if (read_ccs_uint8(ice, CCS_I2C_CONTROL_STATUS) != 0x80) + return -1; + + write_ccs_uint8(ice, CCS_I2C_BYTE_ADDRESS, byte_addr); + write_ccs_uint8(ice, CCS_I2C_DEV_ADDRESS, dev_addr); + write_ccs_uint8(ice, CCS_I2C_DATA, value); + return 0; +} + + +int16 read_eeprom(ice1712 *ice, uint8 eeprom[32]) +{ + int i; + int16 tmp; + + for (i = 0; i < 6; i++) + { + tmp = read_i2c(ice, I2C_EEPROM_ADDRESS_READ, i); + if (tmp >= 0) + eeprom[i] = (uint8)tmp; + else + return -1; + } + if (eeprom[4] > 32) + return -1; + for (i = 6; i < eeprom[4]; i++) + { + tmp = read_i2c(ice, I2C_EEPROM_ADDRESS_READ, i); + if (tmp >= 0) + eeprom[i] = (uint8)tmp; + else + return -1; + } + return eeprom[4]; +} + + +void +codec_write(ice1712 *ice, uint8 reg_addr, uint8 data) +{ + switch (ice->product) + { + case ICE1712_SUBDEVICE_DELTA66 : + case ICE1712_SUBDEVICE_DELTA44 : + ak45xx_write_gpio(ice, reg_addr, data, DELTA66_CODEC_CS_0); + ak45xx_write_gpio(ice, reg_addr, data, DELTA66_CODEC_CS_1); + break; + case ICE1712_SUBDEVICE_DELTA410 : + case ICE1712_SUBDEVICE_AUDIOPHILE_2496 : + case ICE1712_SUBDEVICE_DELTADIO2496 : + ak45xx_write_gpio(ice, reg_addr, data, AP2496_CODEC_CS); + break; + case ICE1712_SUBDEVICE_DELTA1010 : + case ICE1712_SUBDEVICE_DELTA1010LT : + ak45xx_write_gpio(ice, reg_addr, data, DELTA1010LT_CODEC_CS_0); + ak45xx_write_gpio(ice, reg_addr, data, DELTA1010LT_CODEC_CS_1); + ak45xx_write_gpio(ice, reg_addr, data, DELTA1010LT_CODEC_CS_2); + ak45xx_write_gpio(ice, reg_addr, data, DELTA1010LT_CODEC_CS_3); + break; + case ICE1712_SUBDEVICE_VX442 : + ak45xx_write_gpio(ice, reg_addr, data, VX442_CODEC_CS_0); + ak45xx_write_gpio(ice, reg_addr, data, VX442_CODEC_CS_1); + break; + } +} + + +void +spdif_write(ice1712 *ice, uint8 reg_addr, uint8 data) +{ + switch (ice->product) + { + case ICE1712_SUBDEVICE_DELTA1010 : + break; + case ICE1712_SUBDEVICE_DELTADIO2496 : + break; + case ICE1712_SUBDEVICE_DELTA66 : + break; + case ICE1712_SUBDEVICE_DELTA44 : + break; + case ICE1712_SUBDEVICE_AUDIOPHILE_2496 : + cs84xx_write_gpio(ice, reg_addr, data, AP2496_SPDIF_CS); + break; + case ICE1712_SUBDEVICE_DELTA410 : + break; + case ICE1712_SUBDEVICE_DELTA1010LT : + cs84xx_write_gpio(ice, reg_addr, data, DELTA1010LT_SPDIF_CS); + break; + case ICE1712_SUBDEVICE_VX442 : + cs84xx_write_gpio(ice, reg_addr, data, VX442_SPDIF_CS); + break; + } +} + + +void +ak45xx_write_gpio(ice1712 *ice, uint8 reg_addr, uint8 data, uint8 chip_select) +{ + int i; + uint8 tmp; + uint32 serial_data; + + tmp = read_gpio(ice); + + serial_data = ((AK45xx_CHIP_ADDRESS & 0x03) << 6) | 0x20 | (reg_addr & 0x1F); + serial_data = (serial_data << 8) | data; + + tmp |= ice->gpio_cs_mask; + tmp &= ~(chip_select); + + write_gpio(ice, tmp); + snooze(AK45xx_DELAY); + + for (i = 0; i < AK45xx_BITS_TO_WRITE; i++) + { + // drop clock and data bits + tmp &= ~(ice->analog_codec.clock | ice->analog_codec.data_out); + + // set data if needed + if (serial_data & (1 << (AK45xx_BITS_TO_WRITE - 1))) + tmp |= ice->analog_codec.data_out; + + // shift data for sending next bit + serial_data <<= 1; + + write_gpio(ice, tmp); + snooze(AK45xx_DELAY); + + // raise clock + tmp |= ice->analog_codec.clock; + write_gpio(ice, tmp); + snooze(AK45xx_DELAY); + } + + // drop clock and Data + tmp &= ~(ice->analog_codec.clock | ice->analog_codec.data_out); + + tmp |= ice->gpio_cs_mask; + write_gpio(ice, tmp); + snooze(AK45xx_DELAY); +} + + +void +cs84xx_write_gpio(ice1712 *ice, uint8 reg_addr, uint8 data, uint8 chip_select) +{ + int i; + uint8 tmp; + uint32 serial_data; + + tmp = read_gpio(ice); + + serial_data = (CS84xx_CHIP_ADDRESS & 0x7F) << 1; //Last bit is for writing + serial_data = (serial_data << 8) | (reg_addr & 0x7F); //Do not Increment + serial_data = (serial_data << 8) | data; + + tmp |= ice->gpio_cs_mask; + tmp &= ~(chip_select); + + write_gpio(ice, tmp); + snooze(CS84xx_DELAY); + + for (i = 0; i < CS84xx_BITS_TO_WRITE; i++) + { + // drop clock and data bits + tmp &= ~(ice->digital_codec.clock | ice->digital_codec.data_out); + + // set data bit if needed + if (serial_data & (1 << (CS84xx_BITS_TO_WRITE - 1))) + tmp |= ice->digital_codec.data_out; + + // shift data for sending next bit + serial_data <<= 1; + + write_gpio(ice, tmp); + snooze(CS84xx_DELAY); + + // raise clock + tmp |= ice->digital_codec.clock; + write_gpio(ice, tmp); + snooze(CS84xx_DELAY); + } + + // drop clock and Data + tmp &= ~(ice->digital_codec.clock | ice->digital_codec.data_out); + tmp |= ice->gpio_cs_mask; + write_gpio(ice, tmp); + snooze(CS84xx_DELAY); +} + + +uint8 +read_gpio(ice1712 *ice) +{//return -1 if error else return an uint8 + return read_cci_uint8(ice, CCI_GPIO_DATA); +} + + +void +write_gpio(ice1712 *ice, uint8 value) +{//return -1 if error else return 0 + write_cci_uint8(ice, CCI_GPIO_DATA, value); +} + diff --git a/src/add-ons/kernel/drivers/audio/ice1712/io.h b/src/add-ons/kernel/drivers/audio/ice1712/io.h new file mode 100644 index 0000000000..1b0c4551d2 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/io.h @@ -0,0 +1,102 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#ifndef _IO_H_ +#define _IO_H_ + +#include "ice1712.h" + +#include + +//------------------------------------------------------ +//------------------------------------------------------ +//Address are [PCI_10] + xx +uint8 read_ccs_uint8(ice1712 *ice, int8 regno); +uint16 read_ccs_uint16(ice1712 *ice, int8 regno); +uint32 read_ccs_uint32(ice1712 *ice, int8 regno); + +void write_ccs_uint8(ice1712 *ice, int8 regno, uint8 value); +void write_ccs_uint16(ice1712 *ice, int8 regno, uint16 value); +void write_ccs_uint32(ice1712 *ice, int8 regno, uint32 value); +//------------------------------------------------------ +//------------------------------------------------------ +uint8 read_cci_uint8(ice1712 *ice, int8 index); +void write_cci_uint8(ice1712 *ice, int8 index, uint8 value); +//------------------------------------------------------ +//------------------------------------------------------ +//Address are [PCI_14] + xx +uint8 read_ddma_uint8(ice1712 *ice, int8 regno); +uint16 read_ddma_uint16(ice1712 *ice, int8 regno); +uint32 read_ddma_uint32(ice1712 *ice, int8 regno); + +void write_ddma_uint8(ice1712 *ice, int8 regno, uint8 value); +void write_ddma_uint16(ice1712 *ice, int8 regno, uint16 value); +void write_ddma_uint32(ice1712 *ice, int8 regno, uint32 value); +//------------------------------------------------------ +//------------------------------------------------------ +//Address are [PCI_18] + x +uint8 read_ds_uint8(ice1712 *ice, int8 regno); +uint16 read_ds_uint16(ice1712 *ice, int8 regno); +uint32 read_ds_uint32(ice1712 *ice, int8 regno); + +void write_ds_uint8(ice1712 *ice, int8 regno, uint8 value); +void write_ds_uint16(ice1712 *ice, int8 regno, uint16 value); +void write_ds_uint32(ice1712 *ice, int8 regno, uint32 value); + +typedef enum { + DS8_REGISTER_BUFFER_0_BASE_ADDRESS = 0, + DS8_REGISTER_BUFFER_0_BASE_COUNT, + DS8_REGISTER_BUFFER_1_BASE_ADDRESS, + DS8_REGISTER_BUFFER_1_BASE_COUNT, + DS8_REGISTER_CONTROL_AND_STATUS, + DS8_REGISTER_SAMPLING_RATE, + DS8_REGISTER_LEFT_RIGHT_VOLUME, +} ds8_register; + +uint32 read_ds_channel_data(ice1712 *ice, uint8 channel, ds8_register index); +void write_ds_channel_data(ice1712 *ice, uint8 channel, ds8_register index, uint32 data); +//------------------------------------------------------ +//------------------------------------------------------ +//Address are [PCI_1C] + xx +uint8 read_mt_uint8(ice1712 *ice, int8 regno); +uint16 read_mt_uint16(ice1712 *ice, int8 regno); +uint32 read_mt_uint32(ice1712 *ice, int8 regno); + +void write_mt_uint8(ice1712 *ice, int8 regno, uint8 value); +void write_mt_uint16(ice1712 *ice, int8 regno, uint16 value); +void write_mt_uint32(ice1712 *ice, int8 regno, uint32 value); +//------------------------------------------------------ +//------------------------------------------------------ + +int16 read_i2c(ice1712 *ice, uint8 dev_addr, uint8 byte_addr); +//return -1 if error else return an uint8 + +int16 write_i2c(ice1712 *ice, uint8 dev_addr, uint8 byte_addr, uint8 value); +//return -1 if error else return 0 + +//------------------------------------------------------ + +int16 read_eeprom(ice1712 *ice, uint8 eeprom[32]); + +//------------------------------------------------------ + +void codec_write(ice1712 *ice, uint8 reg_addr, uint8 data); + +void spdif_write(ice1712 *ice, uint8 reg_addr, uint8 data); + +//------------------------------------------------------ + +uint8 read_gpio(ice1712 *ice); +//return -1 if error else return an uint8 + +void write_gpio(ice1712 *ice, uint8 value); + +#endif diff --git a/src/add-ons/kernel/drivers/audio/ice1712/midi.c b/src/add-ons/kernel/drivers/audio/ice1712/midi.c new file mode 100644 index 0000000000..15890fc461 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/midi.c @@ -0,0 +1,187 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#include +#include +#include + +#include "ice1712.h" +#include "io.h" +#include "debug.h" +#include "midi_driver.h" +#include "util.h" + +extern generic_mpu401_module * mpu401; + +void midi_interrupt_op(int32 op, void * data) +{ +// midi_dev * port = (midi_dev *)data; + if (op == B_MPU_401_ENABLE_CARD_INT) + { + // sample code + cpu_status cp; +// ddprintf(("sonic_vibes: B_MPU_401_ENABLE_CARD_INT\n")); + cp = disable_interrupts(); +// acquire_spinlock(&port->card->hardware); +// increment_interrupt_handler(port->card); +// set_direct(port->card, 0x01, 0x00, 0x80); +// set_indirect(port->card, 0x2A, 0x04, 0xff); +// release_spinlock(&port->card->hardware); + restore_interrupts(cp); + + //real code + cp = lock(); +// emuxki_reg_write_32(&(port->card->config), EMU_INTE, +// emuxki_reg_read_32(&(port->card->config), EMU_INTE) | +// EMU_INTE_MIDITXENABLE | EMU_INTE_MIDIRXENABLE ); + unlock(cp); + } + else if (op == B_MPU_401_DISABLE_CARD_INT) + { + // sample code + /* turn off MPU interrupts */ + cpu_status cp; +// ddprintf(("sonic_vibes: B_MPU_401_DISABLE_CARD_INT\n")); + cp = disable_interrupts(); +// acquire_spinlock(&port->card->hardware); +// set_direct(port->card, 0x01, 0x80, 0x80);*/ + /* remove interrupt handler if necessary */ +// decrement_interrupt_handler(port->card); +// release_spinlock(&port->card->hardware); + restore_interrupts(cp); + + //real code +// cpu_status status; + cp = lock(); +// emuxki_reg_write_32(&port->card->config, EMU_INTE, +// emuxki_reg_read_32(&port->card->config, EMU_INTE) & +// ~ (EMU_INTE_MIDITXENABLE | EMU_INTE_MIDIRXENABLE ) ); + unlock(cp); + } +} + +static status_t midi_open(const char *name, uint32 flags, void **cookie); +static status_t midi_close(void *cookie); +static status_t midi_free(void *cookie); +static status_t midi_control(void *cookie, uint32 op, void *data, size_t len); +static status_t midi_read(void *cookie, off_t pos, void *data, size_t *len); +static status_t midi_write(void *cookie, off_t pos, const void *data, size_t *len); + + +device_hooks midi_hooks = { + &midi_open, + &midi_close, + &midi_free, + &midi_control, + &midi_read, + &midi_write, + NULL, /* select */ + NULL, /* deselect */ + NULL, /* readv */ + NULL /* writev */ +}; + +static status_t midi_open(const char * name, uint32 flags, void ** cookie) +{ + int i, ix, used_midi = -1; + int ret; + + TRACE_ICE(("midi_open()\n")); + + *cookie = NULL; + for (ix = 0; ix < num_cards; ix++) + { + for (i = 0; i < cards[ix].nb_MPU401; i++) + if (!strcmp(name, cards[ix].midi_interf[i].name)) + { + used_midi = i; + break; + } + } + + if (ix >= num_cards) + { + TRACE_ICE(("bad device\n")); + return ENODEV; + } + + TRACE_ICE(("mpu401: %p open(): %p driver: %p\n", mpu401, mpu401->open_hook, cards[ix].midi_interf[used_midi].driver)); + ret = (*mpu401->open_hook)(cards[ix].midi_interf[used_midi].driver, flags, cookie); + if (ret >= B_OK) + { + cards[ix].midi_interf[used_midi].cookie = *cookie; + atomic_add(&cards[ix].midi_interf[used_midi].count, 1); + } + TRACE_ICE(("mpu401: open returns %x / %p\n", ret, *cookie)); + return ret; + +} + + +static status_t midi_close(void * cookie) +{ + TRACE_ICE(("midi_close()\n")); + return (*mpu401->close_hook)(cookie); +} + + +static status_t midi_free(void * cookie) +{ + int i, ix; + status_t f; + TRACE_ICE(("midi_free()\n")); + f = (*mpu401->free_hook)(cookie); + for (ix = 0; ix < num_cards; ix++) + { + for (i = 0; i < cards[ix].nb_MPU401; i++) + if (cards[ix].midi_interf[i].cookie == cookie) + { + if (atomic_add(&cards[ix].midi_interf[i].count, -1) == 1) + { + cards[ix].midi_interf[i].cookie = NULL; + TRACE_ICE(("cleared %p card %d\n", cookie, ix)); + } + break; + } + } + TRACE_ICE(("midi_free() done\n")); + return f; +} + + +static status_t midi_control(void * cookie, uint32 iop, void * data, size_t len) +{ + return (*mpu401->control_hook)(cookie, iop, data, len); +} + + +static status_t midi_read(void * cookie, off_t pos, void * ptr, size_t * nread) +{ + return (*mpu401->read_hook)(cookie, pos, ptr, nread); +} + + +static status_t midi_write(void * cookie, off_t pos, const void * ptr, size_t * nwritten) +{ + return (*mpu401->write_hook)(cookie, pos, ptr, nwritten); +} + + +bool midi_interrupt(ice1712 *card) +{ + TRACE_ICE(("midi_interrupt\n")); + if (!card->midi_interf[0].driver) + { +// kprintf("aiigh\n"); + return false; + } + return (*mpu401->interrupt_hook)(card->midi_interf[0].driver); +} diff --git a/src/add-ons/kernel/drivers/audio/ice1712/multi.c b/src/add-ons/kernel/drivers/audio/ice1712/multi.c new file mode 100644 index 0000000000..1fef6607d1 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/multi.c @@ -0,0 +1,579 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#include "debug.h" +#include "ice1712_reg.h" +#include "io.h" +#include "multi.h" +#include "util.h" + +#include + +#define AUTORIZED_RATE (B_SR_96000 | B_SR_88200 | B_SR_48000 | B_SR_44100) +#define AUTORIZED_SAMPLE_SIZE (B_FMT_24BIT) + +static void +start_DMA(ice1712 *card) +{ + uint16 size = card->output_buffer_size * MAX_DAC; + + write_mt_uint8(card, MT_PROF_PB_CONTROL, 0); + + write_mt_uint32(card, MT_PROF_PB_DMA_BASE_ADDRESS, (uint32)card->phys_addr_pb); + write_mt_uint16(card, MT_PROF_PB_DMA_COUNT_ADDRESS, (size * SWAPPING_BUFFERS) - 1); + //We want interrupt only from playback + write_mt_uint16(card, MT_PROF_PB_DMA_TERM_COUNT, size - 1/*0*/); + TRACE_ICE(("SIZE DMA PLAYBACK %#x\n", size)); + + size = card->input_buffer_size * MAX_ADC; + + write_mt_uint32(card, MT_PROF_REC_DMA_BASE_ADDRESS, (uint32)card->phys_addr_rec); + write_mt_uint16(card, MT_PROF_REC_DMA_COUNT_ADDRESS, (size * SWAPPING_BUFFERS) - 1); + //We do not want any interrupt from the record + write_mt_uint16(card, MT_PROF_REC_DMA_TERM_COUNT, /*size - 1*/0); + TRACE_ICE(("SIZE DMA RECORD %#x\n", size)); + + //Enable output AND Input from Analog CODEC + switch (card->product) + {//TODO: find correct value for all card + case ICE1712_SUBDEVICE_DELTA66 : + case ICE1712_SUBDEVICE_DELTA44 : + case ICE1712_SUBDEVICE_AUDIOPHILE_2496 : + case ICE1712_SUBDEVICE_DELTADIO2496 : + case ICE1712_SUBDEVICE_DELTA410 : + case ICE1712_SUBDEVICE_DELTA1010LT : + case ICE1712_SUBDEVICE_DELTA1010 : + codec_write(card, AK45xx_CLOCK_FORMAT_REGISTER, 0x69); + codec_write(card, AK45xx_RESET_REGISTER, 0x03); + break; + case ICE1712_SUBDEVICE_VX442 : +// ak45xx_write_gpio(ice, reg_addr, data, VX442_CODEC_CS_0); +// ak45xx_write_gpio(ice, reg_addr, data, VX442_CODEC_CS_1); + break; + } + + //Set Data Format for SPDif codec + switch (card->product) + {//TODO: find correct value for all card + case ICE1712_SUBDEVICE_DELTA1010 : + break; + case ICE1712_SUBDEVICE_DELTADIO2496 : + break; + case ICE1712_SUBDEVICE_DELTA66 : + case ICE1712_SUBDEVICE_DELTA44 : +// ak45xx_write_gpio(ice, reg_addr, data, DELTA66_CODEC_CS_0); +// ak45xx_write_gpio(ice, reg_addr, data, DELTA66_CODEC_CS_1); + break; + case ICE1712_SUBDEVICE_AUDIOPHILE_2496 : + spdif_write(card, CS84xx_SERIAL_INPUT_FORMAT_REG, 0x85); + spdif_write(card, CS84xx_SERIAL_OUTPUT_FORMAT_REG, 0x85); + spdif_write(card, CS84xx_SERIAL_OUTPUT_FORMAT_REG, 0x41); + break; + case ICE1712_SUBDEVICE_DELTA410 : + break; + case ICE1712_SUBDEVICE_DELTA1010LT : +// ak45xx_write_gpio(ice, reg_addr, data, DELTA1010LT_CODEC_CS_0); +// ak45xx_write_gpio(ice, reg_addr, data, DELTA1010LT_CODEC_CS_1); +// ak45xx_write_gpio(ice, reg_addr, data, DELTA1010LT_CODEC_CS_2); +// ak45xx_write_gpio(ice, reg_addr, data, DELTA1010LT_CODEC_CS_3); + break; + case ICE1712_SUBDEVICE_VX442 : +// ak45xx_write_gpio(ice, reg_addr, data, VX442_CODEC_CS_0); +// ak45xx_write_gpio(ice, reg_addr, data, VX442_CODEC_CS_1); + break; + } + + card->buffer = 0; + write_mt_uint8(card, MT_PROF_PB_CONTROL, 5); +} + + +status_t +ice1712_get_description(ice1712 *card, multi_description *data) +{ + int chan = 0, i; + + data->interface_version = B_CURRENT_INTERFACE_VERSION; + data->interface_minimum = B_CURRENT_INTERFACE_VERSION; + + switch (card->product) + { + case ICE1712_SUBDEVICE_DELTA1010 : + strncpy(data->friendly_name, "Delta 1010", 32); + break; + case ICE1712_SUBDEVICE_DELTADIO2496 : + strncpy(data->friendly_name, "Delta DIO 2496", 32); + break; + case ICE1712_SUBDEVICE_DELTA66 : + strncpy(data->friendly_name, "Delta 66", 32); + break; + case ICE1712_SUBDEVICE_DELTA44 : + strncpy(data->friendly_name, "Delta 44", 32); + break; + case ICE1712_SUBDEVICE_AUDIOPHILE_2496 : + strncpy(data->friendly_name, "Audiophile 2496", 32); + break; + case ICE1712_SUBDEVICE_DELTA410 : + strncpy(data->friendly_name, "Delta 410", 32); + break; + case ICE1712_SUBDEVICE_DELTA1010LT : + strncpy(data->friendly_name, "Delta 1010 LT", 32); + break; + case ICE1712_SUBDEVICE_VX442 : + strncpy(data->friendly_name, "VX 442", 32); + break; + + default : + strncpy(data->friendly_name, "Unknow Device", 32); + break; + } + + strncpy(data->vendor_info, "Jerome Leveque", 32); + + data->output_channel_count = card->total_output_channels; + data->input_channel_count = card->total_input_channels; + data->output_bus_channel_count = 0; + data->input_bus_channel_count = 0; + data->aux_bus_channel_count = 0; + + TRACE_ICE(("request_channel_count = %d\n", data->request_channel_count)); + if (data->request_channel_count >= (card->total_output_channels + card->total_input_channels)) { + for (i = 0; i < card->nb_DAC; i++) { + //Analog STEREO output + data->channels[chan].channel_id = chan; + data->channels[chan].kind = B_MULTI_OUTPUT_CHANNEL; + data->channels[chan].designations = B_CHANNEL_STEREO_BUS | \ + (i & 1) ? B_CHANNEL_LEFT : B_CHANNEL_RIGHT; + data->channels[chan].connectors = 0; + chan++; + } + + if (card->spdif_config & NO_IN_YES_OUT) { + //SPDIF STEREO output + data->channels[chan].channel_id = chan; + data->channels[chan].kind = B_MULTI_OUTPUT_CHANNEL; + data->channels[chan].designations = B_CHANNEL_STEREO_BUS | B_CHANNEL_LEFT; + data->channels[chan].connectors = 0; + chan++; + data->channels[chan].channel_id = chan; + data->channels[chan].kind = B_MULTI_OUTPUT_CHANNEL; + data->channels[chan].designations = B_CHANNEL_STEREO_BUS | B_CHANNEL_RIGHT; + data->channels[chan].connectors = 0; + chan++; + } + + for (i = 0; i < card->nb_ADC; i++) { + //Analog STEREO input + data->channels[chan].channel_id = chan; + data->channels[chan].kind = B_MULTI_INPUT_CHANNEL; + data->channels[chan].designations = B_CHANNEL_STEREO_BUS | \ + (i & 1) ? B_CHANNEL_LEFT : B_CHANNEL_RIGHT; + data->channels[chan].connectors = 0; + chan++; + } + + if (card->spdif_config & YES_IN_NO_OUT) { + //SPDIF STEREO input + data->channels[chan].channel_id = chan; + data->channels[chan].kind = B_MULTI_INPUT_CHANNEL; + data->channels[chan].designations = B_CHANNEL_STEREO_BUS | B_CHANNEL_LEFT; + data->channels[chan].connectors = 0; + chan++; + data->channels[chan].channel_id = chan; + data->channels[chan].kind = B_MULTI_INPUT_CHANNEL; + data->channels[chan].designations = B_CHANNEL_STEREO_BUS | B_CHANNEL_RIGHT; + data->channels[chan].connectors = 0; + chan++; + } + + //The digital mixer output + data->channels[chan].channel_id = chan; + data->channels[chan].kind = B_MULTI_INPUT_CHANNEL; + data->channels[chan].designations = B_CHANNEL_STEREO_BUS | B_CHANNEL_LEFT; + data->channels[chan].connectors = 0; + chan++; + data->channels[chan].channel_id = chan; + data->channels[chan].kind = B_MULTI_INPUT_CHANNEL; + data->channels[chan].designations = B_CHANNEL_STEREO_BUS | B_CHANNEL_RIGHT; + data->channels[chan].connectors = 0; + chan++; + } + + TRACE_ICE(("output_channel_count = %d\n", data->output_channel_count)); + TRACE_ICE(("input_channel_count = %d\n", data->input_channel_count)); + TRACE_ICE(("output_bus_channel_count = %d\n", data->output_bus_channel_count)); + TRACE_ICE(("input_bus_channel_count = %d\n", data->input_bus_channel_count)); + + data->output_rates = data->input_rates = AUTORIZED_RATE; + data->min_cvsr_rate = 44100; + data->max_cvsr_rate = 96000; + + data->output_formats = data->input_formats = AUTORIZED_SAMPLE_SIZE; + data->lock_sources = B_MULTI_LOCK_INTERNAL /*| B_MULTI_LOCK_SPDIF*/; + data->timecode_sources = 0; + data->interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD; + data->start_latency = 0; + + strcpy(data->control_panel,""); + + return B_OK; +} + + +status_t +ice1712_get_enabled_channels(ice1712 *card, multi_channel_enable *data) +{ + int i; + uint8 reg; + for (i = 0; i < (card->total_output_channels + card->total_input_channels); i++) + B_SET_CHANNEL(data->enable_bits, i, true); + + reg = read_mt_uint8(card, MT_SAMPLING_RATE_SELECT); + + if (reg == 0x10) + data->lock_source = B_MULTI_LOCK_SPDIF; + else + data->lock_source = B_MULTI_LOCK_INTERNAL; + + return B_OK; +} + + +status_t +ice1712_set_enabled_channels(ice1712 *card, multi_channel_enable *data) +{ + int i; + for (i = 0; i < (card->total_output_channels + card->total_input_channels); i++) + TRACE_ICE(("set_enabled_channels %d : %s\n", i, B_TEST_CHANNEL(data->enable_bits, i) ? "enabled": "disabled")); + + TRACE_ICE(("lock_source %d\n", data->lock_source)); + TRACE_ICE(("lock_data %d\n", data->lock_data)); + + if (data->lock_source == B_MULTI_LOCK_SPDIF) + write_mt_uint8(card, MT_SAMPLING_RATE_SELECT, 0x10); + else + write_mt_uint8(card, MT_SAMPLING_RATE_SELECT, card->sampling_rate); + + return B_OK; +} + + +status_t +ice1712_get_global_format(ice1712 *card, multi_format_info *data) +{ + uint8 sr = read_mt_uint8(card, MT_SAMPLING_RATE_SELECT); + + switch (sr) + { + case 0x0 : + data->input.rate = data->output.rate = B_SR_48000; + data->input.cvsr = data->output.cvsr = 48000.0f; + break; + case 0x7 : + data->input.rate = data->output.rate = B_SR_96000; + data->input.cvsr = data->output.cvsr = 96000.0f; + break; + case 0x8 : + data->input.rate = data->output.rate = B_SR_44100; + data->input.cvsr = data->output.cvsr = 44100.0f; + break; + case 0xB : + data->input.rate = data->output.rate = B_SR_88200; + data->input.cvsr = data->output.cvsr = 88200.0f; + break; + } + + data->timecode_kind = 0; + data->output_latency = data->input_latency = 0; + data->output.format = data->input.format = AUTORIZED_SAMPLE_SIZE; + + TRACE_ICE(("Input Sampling Rate = %d\n", (int)data->input.cvsr)); + TRACE_ICE(("Output Sampling Rate = %d\n", (int)data->output.cvsr)); + + return B_OK; +} + + +status_t +ice1712_set_global_format(ice1712 *card, multi_format_info *data) +{ + uint8 i; + + TRACE_ICE(("Input Sampling Rate = %#x\n", data->input.rate)); + TRACE_ICE(("Output Sampling Rate = %#x\n", data->output.rate)); + + if (data->input.rate == data->output.rate) { + switch (data->input.rate) + { + case B_SR_96000 : + card->sampling_rate = 0x07; + break; + case B_SR_48000 : + card->sampling_rate = 0x00; + break; + case B_SR_88200 : + card->sampling_rate = 0x0B; + break; + case B_SR_44100 : + card->sampling_rate = 0x08; + break; + } + write_mt_uint8(card, MT_SAMPLING_RATE_SELECT, card->sampling_rate); + } + i = read_mt_uint8(card, MT_SAMPLING_RATE_SELECT); + TRACE_ICE(("RATE = %#x\n", i)); + return B_OK; +} + + +status_t +ice1712_get_mix(ice1712 *card, multi_mix_value_info *MMVI) +{//Not Implemented + return B_ERROR; +} + + +status_t +ice1712_set_mix(ice1712 *card, multi_mix_value_info *MMVI) +{//Not Implemented + return B_ERROR; +} + + +status_t +ice1712_list_mix_channels(ice1712 *card, multi_mix_channel_info *data) +{//Not Implemented + return B_ERROR; +} + + +status_t +ice1712_list_mix_controls(ice1712 *card, multi_mix_control_info *MMCI) +{//Not Implemented + return B_ERROR; +} + + +status_t +ice1712_list_mix_connections(ice1712 *card, multi_mix_connection_info *data) +{//Not Implemented + return B_ERROR; +} + + +status_t +ice1712_get_buffers(ice1712 *card, multi_buffer_list *data) +{ + int buff, chan_i = 0, chan_o = 0; + + TRACE_ICE(("flags = %#x\n",data->flags)); + TRACE_ICE(("request_playback_buffers = %#x\n", data->request_playback_buffers)); + TRACE_ICE(("request_playback_channels = %#x\n", data->request_playback_channels)); + TRACE_ICE(("request_playback_buffer_size = %#x\n", data->request_playback_buffer_size)); + TRACE_ICE(("request_record_buffers = %#x\n", data->request_record_buffers)); + TRACE_ICE(("request_record_channels = %#x\n", data->request_record_channels)); + TRACE_ICE(("request_record_buffer_size = %#x\n", data->request_record_buffer_size)); + + // MIN_BUFFER_FRAMES <= requested value are <= MAX_BUFFER_FRAMES + card->output_buffer_size = data->request_playback_buffer_size <= MAX_BUFFER_FRAMES ? \ + data->request_playback_buffer_size >= MIN_BUFFER_FRAMES ? \ + data->request_playback_buffer_size : MIN_BUFFER_FRAMES \ + : MAX_BUFFER_FRAMES; + + // MIN_BUFFER_FRAMES <= requested value are <= MAX_BUFFER_FRAMES + card->input_buffer_size = data->request_record_buffer_size <= MAX_BUFFER_FRAMES ? \ + data->request_record_buffer_size >= MIN_BUFFER_FRAMES ? \ + data->request_record_buffer_size : MIN_BUFFER_FRAMES \ + : MAX_BUFFER_FRAMES; + + for (buff = 0; buff < SWAPPING_BUFFERS; buff++) { + uint32 stride_o = MAX_DAC * SAMPLE_SIZE; + uint32 stride_i = MAX_ADC * SAMPLE_SIZE; + uint32 buf_o = stride_o * card->output_buffer_size; + uint32 buf_i = stride_i * card->input_buffer_size; + + if (data->request_playback_channels == card->total_output_channels) { + for (chan_o = 0; chan_o < card->nb_DAC; chan_o++) { + //Analog STEREO output + data->playback_buffers[buff][chan_o].base = card->log_addr_pb + \ + buf_o * buff + \ + SAMPLE_SIZE * chan_o; + data->playback_buffers[buff][chan_o].stride = stride_o; + TRACE_ICE(("pb_buffer[%d][%d] = %#x\n", \ + buff, chan_o, data->playback_buffers[buff][chan_o].base)); + } + + if (card->spdif_config & NO_IN_YES_OUT) { + //SPDIF STEREO output + data->playback_buffers[buff][chan_o].base = card->log_addr_pb + \ + buf_o * buff + \ + SAMPLE_SIZE * SPDIF_LEFT; + data->playback_buffers[buff][chan_o].stride = stride_o; + TRACE_ICE(("pb_buffer[%d][%d] = %#x\n", \ + buff, chan_o, data->playback_buffers[buff][chan_o].base)); + + chan_o++; + data->playback_buffers[buff][chan_o].base = card->log_addr_pb + \ + buf_o * buff + \ + SAMPLE_SIZE * SPDIF_RIGHT; + data->playback_buffers[buff][chan_o].stride = stride_o; + TRACE_ICE(("pb_buffer[%d][%d] = %#x\n", \ + buff, chan_o, data->playback_buffers[buff][chan_o].base)); + chan_o++; + } + } + + if (data->request_record_channels == card->total_input_channels) { + for (chan_i = 0; chan_i < card->nb_ADC; chan_i++) { + //Analog STEREO input + data->record_buffers[buff][chan_i].base = card->log_addr_rec + \ + buf_i * buff + \ + SAMPLE_SIZE * chan_i; + data->record_buffers[buff][chan_i].stride = stride_i; + TRACE_ICE(("rec_buffer[%d][%d] = %#x\n", \ + buff, chan_i, data->record_buffers[buff][chan_i].base)); + } + + if (card->spdif_config & YES_IN_NO_OUT) { + //SPDIF STEREO input + data->record_buffers[buff][chan_i].base = card->log_addr_rec + \ + buf_i * buff + \ + SAMPLE_SIZE * SPDIF_LEFT; + data->record_buffers[buff][chan_i].stride = stride_i; + TRACE_ICE(("rec_buffer[%d][%d] = %#x\n", \ + buff, chan_i, data->record_buffers[buff][chan_i].base)); + + chan_i++; + data->record_buffers[buff][chan_i].base = card->log_addr_rec + \ + buf_i * buff + \ + SAMPLE_SIZE * SPDIF_RIGHT; + data->record_buffers[buff][chan_i].stride = stride_i; + TRACE_ICE(("rec_buffer[%d][%d] = %#x\n", \ + buff, chan_i, data->record_buffers[buff][chan_i].base)); + chan_i++; + } + + //The digital mixer output + data->record_buffers[buff][chan_i].base = card->log_addr_rec + \ + buf_i * buff + \ + SAMPLE_SIZE * MIXER_OUT_LEFT; + data->record_buffers[buff][chan_i].stride = stride_i; + TRACE_ICE(("rec_buffer[%d][%d] = %#x\n", \ + buff, chan_i, data->record_buffers[buff][chan_i].base)); + + chan_i++; + data->record_buffers[buff][chan_i].base = card->log_addr_rec + \ + buf_i * buff + \ + SAMPLE_SIZE * MIXER_OUT_RIGHT; + data->record_buffers[buff][chan_i].stride = stride_i; + TRACE_ICE(("rec_buffer[%d][%d] = %#x\n", \ + buff, chan_i, data->record_buffers[buff][chan_i].base)); + chan_i++; + } + } + + data->return_playback_buffers = SWAPPING_BUFFERS; + data->return_playback_channels = card->total_output_channels; + data->return_playback_buffer_size = card->output_buffer_size; + + TRACE_ICE(("return_playback_buffers = %#x\n", data->return_playback_buffers)); + TRACE_ICE(("return_playback_channels = %#x\n", data->return_playback_channels)); + TRACE_ICE(("return_playback_buffer_size = %#x\n", data->return_playback_buffer_size)); + + data->return_record_buffers = SWAPPING_BUFFERS; + data->return_record_channels = card->total_input_channels; + data->return_record_buffer_size = card->input_buffer_size; + + TRACE_ICE(("return_record_buffers = %#x\n", data->return_record_buffers)); + TRACE_ICE(("return_record_channels = %#x\n", data->return_record_channels)); + TRACE_ICE(("return_record_buffer_size = %#x\n", data->return_record_buffer_size)); + + start_DMA(card); + + return B_OK; +} + + +status_t +ice1712_buffer_exchange(ice1712 *card, multi_buffer_info *data) +{ + int cpu_status = 0, status; +/* unsigned char peak[MAX_ADC]; + int i; +*/ +// TRACE_ICE(("Avant Exchange p : %d, r : %d\n", data->playback_buffer_cycle, data->record_buffer_cycle)); + + status = acquire_sem_etc(card->buffer_ready_sem, 1, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 50000); + switch (status) + { + case B_NO_ERROR : +// TRACE_ICE(("B_NO_ERROR\n")); + cpu_status = lock(); + + // do playback + data->played_real_time = card->played_time; + data->played_frames_count += card->output_buffer_size; + data->playback_buffer_cycle = (card->buffer - 1) & 0x1; //Buffer TO fill + + // do record + data->recorded_real_time = card->played_time; + data->recorded_frames_count += card->input_buffer_size; + data->record_buffer_cycle = (card->buffer - 1) & 0x1; //Buffer filled + + data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD; + + unlock(cpu_status); + break; + + case B_BAD_SEM_ID : + TRACE_ICE(("B_BAD_SEM_ID\n")); + break; + + case B_INTERRUPTED : + TRACE_ICE(("B_INTERRUPTED\n")); + break; + + case B_BAD_VALUE : + TRACE_ICE(("B_BAD_VALUE\n")); + break; + + case B_WOULD_BLOCK : + TRACE_ICE(("B_WOULD_BLOCK\n")); + break; + + case B_TIMED_OUT : + TRACE_ICE(("B_TIMED_OUT\n")); + start_DMA(card); + cpu_status = lock(); + + data->record_buffer_cycle = 0; + data->playback_buffer_cycle = 1; + data->played_frames_count += card->output_buffer_size; + data->recorded_frames_count += card->input_buffer_size; + data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD; + + unlock(cpu_status); + break; + + default : + TRACE_ICE(("Default\n")); + break; + } + + return B_OK; +} + +status_t ice1712_buffer_force_stop(ice1712 *card) +{ +// write_mt_uint8(card, MT_PROF_PB_CONTROL, 0); + return B_OK; +} + diff --git a/src/add-ons/kernel/drivers/audio/ice1712/multi.h b/src/add-ons/kernel/drivers/audio/ice1712/multi.h new file mode 100644 index 0000000000..b8c6d9bbe8 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/multi.h @@ -0,0 +1,27 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#include "multi_audio.h" +#include "ice1712.h" + +status_t ice1712_get_description(ice1712 *card, multi_description *data); +status_t ice1712_get_enabled_channels(ice1712 *card, multi_channel_enable *data); +status_t ice1712_set_enabled_channels(ice1712 *card, multi_channel_enable *data); +status_t ice1712_get_global_format(ice1712 *card, multi_format_info *data); +status_t ice1712_set_global_format(ice1712 *card, multi_format_info *data); +status_t ice1712_get_mix(ice1712 *card, multi_mix_value_info *MMVI); +status_t ice1712_set_mix(ice1712 *card, multi_mix_value_info *MMVI); +status_t ice1712_list_mix_channels(ice1712 *card, multi_mix_channel_info *data); +status_t ice1712_list_mix_controls(ice1712 *card, multi_mix_control_info *MMCI); +status_t ice1712_list_mix_connections(ice1712 *card, multi_mix_connection_info *data); +status_t ice1712_get_buffers(ice1712 *card, multi_buffer_list *data); +status_t ice1712_buffer_exchange(ice1712 *card, multi_buffer_info *data); +status_t ice1712_buffer_force_stop(ice1712 *card); diff --git a/src/add-ons/kernel/drivers/audio/ice1712/util.c b/src/add-ons/kernel/drivers/audio/ice1712/util.c new file mode 100644 index 0000000000..de0890d2dc --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/util.c @@ -0,0 +1,72 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#include +#include +#include + +//#define DEBUG 2 + +#include "debug.h" +#include "util.h" + +spinlock slock = 0; + +uint32 round_to_pagesize(uint32 size); + +cpu_status lock(void) +{ + cpu_status status = disable_interrupts(); + acquire_spinlock(&slock); + return status; +} + +void unlock(cpu_status status) +{ + release_spinlock(&slock); + restore_interrupts(status); +} + +uint32 round_to_pagesize(uint32 size) +{ + return (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); +} + +area_id alloc_mem(void **phy, void **log, size_t size, const char *name) +{ + physical_entry pe; + void * logadr; + area_id areaid; + status_t rv; + + TRACE_ICE(("allocating %#08 bytes for %s\n",size,name)); + + size = round_to_pagesize(size); + areaid = create_area(name, &logadr, B_ANY_KERNEL_ADDRESS,size,B_FULL_LOCK | B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA); + if (areaid < B_OK) { + TRACE_ICE(("couldn't allocate area %s\n",name)); + return B_ERROR; + } + rv = get_memory_map(logadr,size,&pe,1); + if (rv < B_OK) { + delete_area(areaid); + TRACE_ICE(("couldn't map %s\n",name)); + return B_ERROR; + } + memset(logadr,0,size); + if (log) + *log = logadr; + if (phy) + *phy = pe.address; + TRACE_ICE(("area = %d, size = %#08X, log = %#08X, phy = %#08X\n",areaid,size,logadr,pe.address)); + return areaid; +} + diff --git a/src/add-ons/kernel/drivers/audio/ice1712/util.h b/src/add-ons/kernel/drivers/audio/ice1712/util.h new file mode 100644 index 0000000000..b25997e9e1 --- /dev/null +++ b/src/add-ons/kernel/drivers/audio/ice1712/util.h @@ -0,0 +1,22 @@ +/* + * ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller + * + * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr) + * Copyright (c) 2003, Marcus Overhagen (marcus@overhagen.de) + * Copyright (c) 2007, Jerome Leveque (leveque.jerome@neuf.fr) + * + * All rights reserved + * Distributed under the terms of the MIT license. + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include + +area_id alloc_mem(void **phy, void **log, size_t size, const char *name); + +cpu_status lock(void); +void unlock(cpu_status status); + +#endif