added ice1712 driver on behalf of Jérôme Leveque. Thanks!

Current status : playback only.
Support for M-Audio Delta 1010, Delta 1010 LT, Delta DIO 2496, Delta 66, Delta 44, Audiophile 2496 and Delta 410 VX 442.
Tested on M-Audio Audiophile2496.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22458 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2007-10-06 13:45:16 +00:00
parent 5c7dbe881d
commit 4689d4f1ab
14 changed files with 2556 additions and 0 deletions
+1
View File
@@ -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 ;
@@ -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
;
@@ -0,0 +1,79 @@
/*
* ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller
*
* Copyright (c) 2002, Jerome Duval ([email protected])
* Copyright (c) 2003, Marcus Overhagen ([email protected])
* Copyright (c) 2007, Jerome Leveque ([email protected])
*
* All rights reserved
* Distributed under the terms of the MIT license.
*/
#include <KernelExport.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <OS.h>
#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
}
@@ -0,0 +1,54 @@
/*
* ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller
*
* Copyright (c) 2002, Jerome Duval ([email protected])
* Copyright (c) 2003, Marcus Overhagen ([email protected])
* Copyright (c) 2007, Jerome Leveque ([email protected])
*
* 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
@@ -0,0 +1,575 @@
/*
* ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller
*
* Copyright (c) 2002, Jerome Duval ([email protected])
* Copyright (c) 2003, Marcus Overhagen ([email protected])
* Copyright (c) 2007, Jerome Leveque ([email protected])
*
* All rights reserved
* Distributed under the terms of the MIT license.
*/
#include <KernelExport.h>
#include <Drivers.h>
#include <Errors.h>
#include <OS.h>
#include <malloc.h>
#include <fcntl.h>
#include <image.h>
#include <string.h>
#include <PCI.h>
#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<num_cards; ix++) {
/*#if MIDI
if (!strcmp(cards[ix].midi.name, name)) {
return &midi_hooks;
}
#endif
*/ if (!strcmp(cards[ix].name, name)) {
return &ice_1712_hooks;
}
}
PRINT_ICE(("ice1712: find_device(%s) failed\n", name));
return NULL;
}
@@ -0,0 +1,216 @@
/*
* ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller
*
* Copyright (c) 2002, Jerome Duval ([email protected])
* Copyright (c) 2003, Marcus Overhagen ([email protected])
* Copyright (c) 2007, Jerome Leveque ([email protected])
*
* All rights reserved
* Distributed under the terms of the MIT license.
*/
#ifndef _ICE1712_H_
#define _ICE1712_H_
#include <PCI.h>
#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
@@ -0,0 +1,167 @@
/*
* ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller
*
* Copyright (c) 2007, Jerome Leveque ([email protected])
*
* 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
@@ -0,0 +1,459 @@
/*
* ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller
*
* Copyright (c) 2002, Jerome Duval ([email protected])
* Copyright (c) 2003, Marcus Overhagen ([email protected])
* Copyright (c) 2007, Jerome Leveque ([email protected])
*
* 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);
}
@@ -0,0 +1,102 @@
/*
* ice1712 BeOS/Haiku Driver for VIA - VT1712 Multi Channel Audio Controller
*
* Copyright (c) 2002, Jerome Duval ([email protected])
* Copyright (c) 2003, Marcus Overhagen ([email protected])
* Copyright (c) 2007, Jerome Leveque ([email protected])
*
* All rights reserved
* Distributed under the terms of the MIT license.
*/
#ifndef _IO_H_
#define _IO_H_
#include "ice1712.h"
#include <SupportDefs.h>
//------------------------------------------------------
//------------------------------------------------------
//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
@@ -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 <string.h>
#include <stdlib.h>
#include <signal.h>
#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);
}
@@ -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 <string.h>
#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;
}
@@ -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);
@@ -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 <Errors.h>
#include <OS.h>
#include <string.h>
//#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;
}
@@ -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 <KernelExport.h>
area_id alloc_mem(void **phy, void **log, size_t size, const char *name);
cpu_status lock(void);
void unlock(cpu_status status);
#endif