diff --git a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/ichaudio.c b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/ichaudio.c index 6d7494bc36..c020e7a7f8 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/ichaudio.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/ichaudio.c @@ -2,9 +2,15 @@ #include "ichaudio.h" #include "io.h" -status_t ichaudio_attach(audio_drv_t *drv); -status_t ichaudio_powerctl(audio_drv_t *drv); -status_t ichaudio_detach(audio_drv_t *drv); +status_t ichaudio_attach(audio_drv_t *drv, void **cookie); +status_t ichaudio_powerctl(audio_drv_t *drv, void *cookie); +status_t ichaudio_detach(audio_drv_t *drv, void *cookie); +status_t ichaudio_stream_attach(audio_drv_t *drv, void **cookie, void *param); +status_t ichaudio_stream_detach(audio_drv_t *drv, void *cookie); +status_t ichaudio_stream_control(audio_drv_t *drv, void *cookie, int op); +status_t ichaudio_stream_set_buffers(audio_drv_t *drv, void *cookie, uint32 *buffer_size, stream_buffer_desc_t *desc); +status_t ichaudio_stream_set_frame_rate(audio_drv_t *drv, void *cookie, uint32 *frame_rate); + id_table_t ichaudio_id_table[] = { { 0x8086, 0x7195, -1, -1, -1, -1, -1, "Intel 82443MX AC97 audio" }, @@ -12,9 +18,9 @@ id_table_t ichaudio_id_table[] = { { 0x8086, 0x2425, -1, -1, -1, -1, -1, "Intel 82801AB (ICH0) AC97 audio" }, { 0x8086, 0x2445, -1, -1, -1, -1, -1, "Intel 82801BA (ICH2) AC97 audio" }, { 0x8086, 0x2485, -1, -1, -1, -1, -1, "Intel 82801CA (ICH3) AC97 audio" }, - { 0x8086, 0x24C5, -1, -1, -1, -1, -1, "Intel 82801DB (ICH4) AC97 audio", TYPE_ICH4 }, - { 0x8086, 0x24D5, -1, -1, -1, -1, -1, "Intel 82801EB (ICH5) AC97 audio", TYPE_ICH4 }, - { 0x1039, 0x7012, -1, -1, -1, -1, -1, "SiS SI7012 AC97 audio", TYPE_SIS7012 }, + { 0x8086, 0x24C5, -1, -1, -1, -1, -1, "Intel 82801DB (ICH4) AC97 audio", (void *)TYPE_ICH4 }, + { 0x8086, 0x24D5, -1, -1, -1, -1, -1, "Intel 82801EB (ICH5) AC97 audio", (void *)TYPE_ICH4 }, + { 0x1039, 0x7012, -1, -1, -1, -1, -1, "SiS SI7012 AC97 audio", (void *)TYPE_SIS7012 }, { 0x10DE, 0x01B1, -1, -1, -1, -1, -1, "NVIDIA nForce (MCP) AC97 audio" }, { 0x10DE, 0x006A, -1, -1, -1, -1, -1, "NVIDIA nForce 2 (MCP2) AC97 audio" }, { 0x10DE, 0x00DA, -1, -1, -1, -1, -1, "NVIDIA nForce 3 (MCP3) AC97 audio" }, @@ -29,30 +35,72 @@ id_table_t ichaudio_id_table[] = { driver_info_t driver_info = { - .table = ichaudio_id_table, + .id_table = ichaudio_id_table, .basename = "audio/lala/ichaudio", - .cookie_size = sizeof(ichaudio_cookie), .attach = ichaudio_attach, .detach = ichaudio_detach, .powerctl = ichaudio_powerctl, }; +stream_info_t po_stream = { + .flags = B_PLAYBACK_STREAM | B_BUFFER_SIZE_EXPONETIAL | B_SAMPLE_TYPE_INT16, + .cookie_size = sizeof(ichaudio_stream_cookie), + .sample_bits = 16, + .channel_count = 2, + .channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT, + .frame_rate_min = 0, // is setup later after device probing + .frame_rate_max = 0, // is setup later after device probing + .frame_rate_mask = 0, // is setup later after device probing + .buffer_size_min = 256, + .buffer_size_max = 32768, + .buffer_count = 2, + .attach = ichaudio_stream_attach, + .detach = ichaudio_stream_detach, + .control = ichaudio_stream_control, + .set_buffers = ichaudio_stream_set_buffers, + .set_frame_rate = ichaudio_stream_set_frame_rate, +}; + + +stream_info_t pi_stream = { + .flags = B_RECORDING_STREAM | B_BUFFER_SIZE_EXPONETIAL | B_SAMPLE_TYPE_INT16, + .sample_bits = 16, + .channel_count = 2, + .channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT, + .frame_rate_min = 0, // is setup later after device probing + .frame_rate_max = 0, // is setup later after device probing + .frame_rate_mask = 0, // is setup later after device probing + .buffer_size_min = 256, + .buffer_size_max = 32768, + .buffer_count = 2, + .attach = ichaudio_stream_attach, + .detach = ichaudio_stream_detach, + .control = ichaudio_stream_control, + .set_buffers = ichaudio_stream_set_buffers, + .set_frame_rate = ichaudio_stream_set_frame_rate, +}; + status_t -ichaudio_attach(audio_drv_t *drv) +ichaudio_attach(audio_drv_t *drv, void **_cookie) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; + ichaudio_cookie *cookie; uint32 value; int i; bigtime_t start; bool s0cr, s1cr, s2cr; dprintf("ichaudio_attach\n"); + + *_cookie = cookie = (ichaudio_cookie *) malloc(sizeof(ichaudio_cookie)); + + cookie->pci = drv->pci; + cookie->flags = (uint32)drv->param; // For old ICHs enable programmed IO and busmaster access, // for ICH4 and up enable memory mapped IO and busmaster access value = drv->pci->read_pci_config(drv->bus, drv->device, drv->function, PCI_command, 2); - value |= PCI_PCICMD_BME | (drv->flags & TYPE_ICH4) ? PCI_PCICMD_MSE : PCI_PCICMD_IOS; + value |= PCI_PCICMD_BME | (cookie->flags & TYPE_ICH4) ? PCI_PCICMD_MSE : PCI_PCICMD_IOS; drv->pci->write_pci_config(drv->bus, drv->device, drv->function, PCI_command, 2, value); // get IRQ, we can compensate it later if IRQ is not available (hack!) @@ -60,17 +108,17 @@ ichaudio_attach(audio_drv_t *drv) if (cookie->irq == 0xff) cookie->irq = 0; if (cookie->irq == 0) dprintf("ichaudio_attach: no interrupt configured\n"); - if (drv->flags & TYPE_ICH4) { + if (cookie->flags & TYPE_ICH4) { // memory mapped access - uint32 phy_mmbar = PCI_address_memory_32_mask & drv->pci->read_pci_config(drv->bus, drv->device, drv->function, 0x18, 4); - uint32 phy_mbbar = PCI_address_memory_32_mask & drv->pci->read_pci_config(drv->bus, drv->device, drv->function, 0x1C, 4); - if (!phy_mmbar || !phy_mbbar) { + uint32 phys_mmbar = PCI_address_memory_32_mask & drv->pci->read_pci_config(drv->bus, drv->device, drv->function, 0x18, 4); + uint32 phys_mbbar = PCI_address_memory_32_mask & drv->pci->read_pci_config(drv->bus, drv->device, drv->function, 0x1C, 4); + if (!phys_mmbar || !phys_mbbar) { dprintf("ichaudio_attach: memory mapped io unconfigured\n"); goto err; } // map into memory - cookie->area_mmbar = map_mem(&cookie->mmbar, (void *)phy_mmbar, ICH4_MMBAR_SIZE, 0, "ichaudio mmbar io"); - cookie->area_mbbar = map_mem(&cookie->mbbar, (void *)phy_mbbar, ICH4_MBBAR_SIZE, 0, "ichaudio mbbar io"); + cookie->area_mmbar = map_mem(&cookie->mmbar, (void *)phys_mmbar, ICH4_MMBAR_SIZE, 0, "ichaudio mmbar io"); + cookie->area_mbbar = map_mem(&cookie->mbbar, (void *)phys_mbbar, ICH4_MBBAR_SIZE, 0, "ichaudio mbbar io"); if (cookie->area_mmbar < B_OK || cookie->area_mbbar < B_OK) { dprintf("ichaudio_attach: mapping io into memory failed\n"); goto err; @@ -97,34 +145,34 @@ ichaudio_attach(audio_drv_t *drv) * reset does also reset GPIO pins, but the ICH hardware does only execute * the reset request if BIT_CLOCK is not running and if it's really required. */ - LOG(("reset starting, ICH_REG_GLOB_CNT = 0x%08x\n", ich_reg_read_32(drv, ICH_REG_GLOB_CNT))); - DEBUG_ONLY(start = system_time()); + LOG(("reset starting, ICH_REG_GLOB_CNT = 0x%08lx\n", ich_reg_read_32(cookie, ICH_REG_GLOB_CNT))); + start = system_time(); // finish cold reset by writing a 1 and clear all other bits to 0 - ich_reg_write_32(drv, ICH_REG_GLOB_CNT, CNT_COLD); - ich_reg_read_32(drv, ICH_REG_GLOB_CNT); // force PCI-to-PCI bridge cache flush + ich_reg_write_32(cookie, ICH_REG_GLOB_CNT, CNT_COLD); + ich_reg_read_32(cookie, ICH_REG_GLOB_CNT); // force PCI-to-PCI bridge cache flush snooze(20000); // request warm reset by setting the bit, it will clear when reset is done - ich_reg_write_32(drv, ICH_REG_GLOB_CNT, ich_reg_read_32(drv, ICH_REG_GLOB_CNT) | CNT_WARM); - ich_reg_read_32(drv, ICH_REG_GLOB_CNT); // force PCI-to-PCI bridge cache flush + ich_reg_write_32(cookie, ICH_REG_GLOB_CNT, ich_reg_read_32(cookie, ICH_REG_GLOB_CNT) | CNT_WARM); + ich_reg_read_32(cookie, ICH_REG_GLOB_CNT); // force PCI-to-PCI bridge cache flush snooze(20000); // wait up to 1 second for warm reset to be finished for (i = 0; i < 20; i++) { - value = ich_reg_read_32(drv, ICH_REG_GLOB_CNT); + value = ich_reg_read_32(cookie, ICH_REG_GLOB_CNT); if ((value & CNT_WARM) == 0 && (value & CNT_COLD) != 0) break; snooze(50000); } if (i == 20) { - LOG(("reset failed, ICH_REG_GLOB_CNT = 0x%08x\n", value)); + LOG(("reset failed, ICH_REG_GLOB_CNT = 0x%08lx\n", value)); goto err; } - LOG(("reset finished after %Ld, ICH_REG_GLOB_CNT = 0x%08x\n", system_time() - start, value)); + LOG(("reset finished after %Ld, ICH_REG_GLOB_CNT = 0x%08lx\n", system_time() - start, value)); /* detect which codecs are ready */ s0cr = s1cr = s2cr = false; start = system_time(); do { - value = ich_reg_read_32(drv, ICH_REG_GLOB_STA); + value = ich_reg_read_32(cookie, ICH_REG_GLOB_STA); if (!s0cr && (value & STA_S0CR)) { s0cr = true; LOG(("AC_SDIN0 codec ready after %Ld us\n", system_time() - start)); @@ -155,40 +203,40 @@ ichaudio_attach(audio_drv_t *drv) goto err; } - if (drv->flags & TYPE_ICH4) { + if (cookie->flags & TYPE_ICH4) { /* we are using a ICH4 chipset, and assume that the codec beeing ready * is the primary one. */ uint8 sdin; uint16 reset; uint8 id; - reset = ich_codec_read(drv, 0x00); /* access the primary codec */ + reset = ich_codec_read(cookie, 0x00); /* access the primary codec */ if (reset == 0 || reset == 0xFFFF) { LOG(("primary codec not present\n")); } else { - sdin = 0x02 & ich_reg_read_8(drv, ICH_REG_SDM); - id = 0x02 & (ich_codec_read(drv, 0x00 + 0x28) >> 14); + sdin = 0x02 & ich_reg_read_8(cookie, ICH_REG_SDM); + id = 0x02 & (ich_codec_read(cookie, 0x00 + 0x28) >> 14); LOG(("primary codec id %d is connected to AC_SDIN%d\n", id, sdin)); } - reset = ich_codec_read(drv, 0x80); /* access the secondary codec */ + reset = ich_codec_read(cookie, 0x80); /* access the secondary codec */ if (reset == 0 || reset == 0xFFFF) { LOG(("secondary codec not present\n")); } else { - sdin = 0x02 & ich_reg_read_8(drv, ICH_REG_SDM); - id = 0x02 & (ich_codec_read(drv, 0x80 + 0x28) >> 14); + sdin = 0x02 & ich_reg_read_8(cookie, ICH_REG_SDM); + id = 0x02 & (ich_codec_read(cookie, 0x80 + 0x28) >> 14); LOG(("secondary codec id %d is connected to AC_SDIN%d\n", id, sdin)); } - reset = ich_codec_read(drv, 0x100); /* access the tertiary codec */ + reset = ich_codec_read(cookie, 0x100); /* access the tertiary codec */ if (reset == 0 || reset == 0xFFFF) { LOG(("tertiary codec not present\n")); } else { - sdin = 0x02 & ich_reg_read_8(drv, ICH_REG_SDM); - id = 0x02 & (ich_codec_read(drv, 0x100 + 0x28) >> 14); + sdin = 0x02 & ich_reg_read_8(cookie, ICH_REG_SDM); + id = 0x02 & (ich_codec_read(cookie, 0x100 + 0x28) >> 14); LOG(("tertiary codec id %d is connected to AC_SDIN%d\n", id, sdin)); } /* XXX this may be wrong */ - ich_reg_write_8(drv, ICH_REG_SDM, (ich_reg_read_8(drv, ICH_REG_SDM) & 0x0F) | 0x08 | 0x90); + ich_reg_write_8(cookie, ICH_REG_SDM, (ich_reg_read_8(cookie, ICH_REG_SDM) & 0x0F) | 0x08 | 0x90); } else { /* we are using a pre-ICH4 chipset, that has a fixed mapping of * AC_SDIN0 = primary, AC_SDIN1 = secondary codec. @@ -200,36 +248,168 @@ ichaudio_attach(audio_drv_t *drv) } } + cookie->po_stream_id = create_stream(&po_stream, (void *)ICH_REG_PO_BASE); + cookie->pi_stream_id = create_stream(&pi_stream, (void *)ICH_REG_PI_BASE); + if (cookie->po_stream_id < 0 || cookie->pi_stream_id < 0) + goto err; return B_OK; err: + // delete streams + if (cookie->po_stream_id > 0) delete_stream(cookie->po_stream_id); + if (cookie->pi_stream_id > 0) delete_stream(cookie->pi_stream_id); // unmap io memory if (cookie->area_mmbar > 0) delete_area(cookie->area_mmbar); if (cookie->area_mbbar > 0) delete_area(cookie->area_mbbar); + free(cookie); return B_ERROR; } status_t -ichaudio_detach(audio_drv_t *drv) +ichaudio_detach(audio_drv_t *drv, void *_cookie) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; + ichaudio_cookie *cookie = (ichaudio_cookie *)_cookie; dprintf("ichaudio_detach\n"); + // delete streams + if (cookie->po_stream_id > 0) delete_stream(cookie->po_stream_id); + if (cookie->pi_stream_id > 0) delete_stream(cookie->pi_stream_id); // unmap io memory if (cookie->area_mmbar > 0) delete_area(cookie->area_mmbar); if (cookie->area_mbbar > 0) delete_area(cookie->area_mbbar); + free(cookie); return B_OK; } status_t -ichaudio_powerctl(audio_drv_t *drv) +ichaudio_powerctl(audio_drv_t *drv, void *_cookie) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; + ichaudio_cookie *cookie = (ichaudio_cookie *)_cookie; return B_OK; } +void +stream_reset(ichaudio_stream_cookie *cookie) +{ + int i; + + ich_reg_write_8(cookie, cookie->regbase + ICH_REG_X_CR, 0); + ich_reg_read_8(cookie, cookie->regbase + ICH_REG_X_CR); // force PCI-to-PCI bridge cache flush + snooze(10000); // 10 ms + ich_reg_write_8(cookie, cookie->regbase + ICH_REG_X_CR, CR_RR); + for (i = 0; i < 100; i++) { + uint8 cr = ich_reg_read_8(cookie, cookie->regbase + ICH_REG_X_CR); + if (cr == 0) { + LOG(("channel reset finished, %d\n",i)); + return; + } + snooze(100); + } + LOG(("channel reset failed after 10ms\n")); +} + +status_t +ichaudio_stream_attach(audio_drv_t *drv, void **_cookie, void *param) +{ + ichaudio_stream_cookie *cookie; + void *bd_virt_base; + void *bd_phys_base; + int i; + + *_cookie = cookie = (ichaudio_stream_cookie *) malloc(sizeof(ichaudio_stream_cookie)); + + cookie->regbase = (uint32) param; + cookie->lastindex = 0; + cookie->processed_samples = 0; + + stream_reset(cookie); + + // allocate memory for buffer descriptors + cookie->bd_area = alloc_mem(&bd_virt_base, &bd_phys_base, ICH_BD_COUNT * sizeof(ich_bd), 0, "ich_ac97 buffer descriptor"); + if (cookie->bd_area < B_OK) + goto err; + + // set physical buffer descriptor base address + ich_reg_write_32(cookie->regbase, (uint32)bd_phys_base); + + // setup descriptor pointers + for (i = 0; i < ICH_BD_COUNT; i++) + cookie->bd[i] = (ich_bd *) ((char *)bd_virt_base + i * sizeof(ich_bd)); + + return B_OK; + +err: + free(cookie); + return B_ERROR; +} + + +status_t +ichaudio_stream_detach(audio_drv_t *drv, void *_cookie) +{ + ichaudio_stream_cookie *cookie = (ichaudio_stream_cookie *)_cookie; + + stream_reset(cookie); + + if (cookie->buffer_area > 0) delete_area(cookie->buffer_area); + if (cookie->bd_area > 0) delete_area(cookie->bd_area); + free(cookie); + + return B_OK; +} + + +status_t +ichaudio_stream_control(audio_drv_t *drv, void *_cookie, int op) +{ +} + + +status_t +ichaudio_stream_set_buffers(audio_drv_t *drv, void *_cookie, uint32 *buffer_size, stream_buffer_desc_t *desc) +{ + ichaudio_stream_cookie *cookie = (ichaudio_stream_cookie *)_cookie; + + void *buffer_virt_base; + void *buffer_phys_base; + area_id buffer_area; + int i; + + // round down (could force another size here) + *buffer_size &= ~3; + + // allocate memory buffers + buffer_area = alloc_mem(&buffer_virt_base, &buffer_phys_base, 2 * *buffer_size, B_READ_AREA | B_WRITE_AREA, "ich_ac97 buffers"); + + // report buffers + desc[0].base = (char *)buffer_virt_base; + desc[0].stride = 4; + desc[1].base = (char *)buffer_virt_base + 2; + desc[1].stride = 4; + + // initalize buffer descriptors + for (i = 0; i < ICH_BD_COUNT; i++) { + cookie->bd[i].buffer = (uint32)buffer_phy_base + (i % 2) * *buffer_size; + cookie->bd[i].length = *buffer_size / GET_HW_SAMPLE_SIZE(cookie); + cookie->bd[i].flags = ICH_BDC_FLAG_IOC; + } + + // free old buffer memory + if (cookie->buffer_area > 0) + delete_area(cookie->buffer_area); + + cookie->buffer_area = buffer_area; + return B_OK; +} + + +status_t +ichaudio_stream_set_frame_rate(audio_drv_t *drv, void *_cookie, uint32 *frame_rate) +{ +} + diff --git a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/ichaudio.h b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/ichaudio.h index e9e0eed62a..9f5e3fb4d2 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/ichaudio.h +++ b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/ichaudio.h @@ -1,5 +1,6 @@ #include #include "hardware.h" +#include "lala/lala.h" typedef struct { @@ -14,16 +15,37 @@ typedef struct uint32 codecoffset; uint32 input_rate; uint32 output_rate; + + stream_id po_stream_id; + stream_id pi_stream_id; + + pci_module_info * pci; + uint32 flags; } ichaudio_cookie; +typedef struct +{ + uint32 regbase; + ich_bd * bd[ICH_BD_COUNT]; + void * buffer[ICH_BD_COUNT]; + + area_id bd_area; + area_id buffer_area; + + volatile int lastindex; + volatile int64 processed_samples; + +} ichaudio_stream_cookie; + + #define TYPE_ICH4 0x01 #define TYPE_SIS7012 0x02 /* The SIS7012 chipset has SR and PICB registers swapped when compared to Intel */ -#define GET_REG_X_PICB(cfg) (((cfg)->type == TYPE_SIS7012) ? _ICH_REG_X_SR : _ICH_REG_X_PICB) -#define GET_REG_X_SR(cfg) (((cfg)->type == TYPE_SIS7012) ? _ICH_REG_X_PICB : _ICH_REG_X_SR) +#define GET_REG_X_PICB(cookie) (((cookie)->flags & TYPE_SIS7012) ? _ICH_REG_X_SR : _ICH_REG_X_PICB) +#define GET_REG_X_SR(cookie) (((cookie)->flags & TYPE_SIS7012) ? _ICH_REG_X_PICB : _ICH_REG_X_SR) /* Each 16 bit sample is counted as 1 in SIS7012 chipsets, 2 in all others */ -#define GET_HW_SAMPLE_SIZE(cfg) (((cfg)->type == TYPE_SIS7012) ? 1 : 2) +#define GET_HW_SAMPLE_SIZE(cookie) (((cookie)->flags & TYPE_SIS7012) ? 1 : 2) diff --git a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/io.c b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/io.c index 80d7919b93..431f3aabae 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/io.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/io.c @@ -32,96 +32,84 @@ #include "ichaudio.h" #include "io.h" -status_t ich_codec_wait(audio_drv_t *drv); +status_t ich_codec_wait(ichaudio_cookie *cookie); uint8 -ich_reg_read_8(audio_drv_t *drv, int regno) +ich_reg_read_8(ichaudio_cookie *cookie, int regno) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; - ASSERT(regno >= 0); - ASSERT(((drv->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); - if (drv->flags & TYPE_ICH4) + ASSERT(((cookie->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); + if (cookie->flags & TYPE_ICH4) return *(uint8 *)((char *)cookie->mbbar + regno); else - return drv->pci->read_io_8(cookie->nabmbar + regno); + return cookie->pci->read_io_8(cookie->nabmbar + regno); } uint16 -ich_reg_read_16(audio_drv_t *drv, int regno) +ich_reg_read_16(ichaudio_cookie *cookie, int regno) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; - ASSERT(regno >= 0); - ASSERT(((drv->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); - if (drv->flags & TYPE_ICH4) + ASSERT(((cookie->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); + if (cookie->flags & TYPE_ICH4) return *(uint16 *)((char *)cookie->mbbar + regno); else - return drv->pci->read_io_16(cookie->nabmbar + regno); + return cookie->pci->read_io_16(cookie->nabmbar + regno); } uint32 -ich_reg_read_32(audio_drv_t *drv, int regno) +ich_reg_read_32(ichaudio_cookie *cookie, int regno) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; - ASSERT(regno >= 0); - ASSERT(((drv->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); + ASSERT(((cookie->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); - if (drv->flags & TYPE_ICH4) + if (cookie->flags & TYPE_ICH4) return *(uint32 *)((char *)cookie->mbbar + regno); else - return drv->pci->read_io_32(cookie->nabmbar + regno); + return cookie->pci->read_io_32(cookie->nabmbar + regno); } void -ich_reg_write_8(audio_drv_t *drv, int regno, uint8 value) +ich_reg_write_8(ichaudio_cookie *cookie, int regno, uint8 value) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; - ASSERT(regno >= 0); - ASSERT(((drv->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); + ASSERT(((cookie->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); - if (drv->flags & TYPE_ICH4) + if (cookie->flags & TYPE_ICH4) *(uint8 *)((char *)cookie->mbbar + regno) = value; else - drv->pci->write_io_8(cookie->nabmbar + regno, value); + cookie->pci->write_io_8(cookie->nabmbar + regno, value); } void -ich_reg_write_16(audio_drv_t *drv, int regno, uint16 value) +ich_reg_write_16(ichaudio_cookie *cookie, int regno, uint16 value) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; - ASSERT(regno >= 0); - ASSERT(((drv->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); + ASSERT(((cookie->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); - if (drv->flags & TYPE_ICH4) + if (cookie->flags & TYPE_ICH4) *(uint16 *)((char *)cookie->mbbar + regno) = value; else - drv->pci->write_io_16(cookie->nabmbar + regno, value); + cookie->pci->write_io_16(cookie->nabmbar + regno, value); } void -ich_reg_write_32(audio_drv_t *drv, int regno, uint32 value) +ich_reg_write_32(ichaudio_cookie *cookie, int regno, uint32 value) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; - ASSERT(regno >= 0); - ASSERT(((drv->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); + ASSERT(((cookie->flags & TYPE_ICH4) != 0 && regno <= 255) || regno <= 63); - if (drv->flags & TYPE_ICH4) + if (cookie->flags & TYPE_ICH4) *(uint32 *)((char *)cookie->mbbar + regno) = value; else - drv->pci->write_io_32(cookie->nabmbar + regno, value); + cookie->pci->write_io_32(cookie->nabmbar + regno, value); } status_t -ich_codec_wait(audio_drv_t *drv) +ich_codec_wait(ichaudio_cookie *cookie) { int i; for (i = 0; i < 1100; i++) { - if ((ich_reg_read_8(drv, ICH_REG_ACC_SEMA) & 0x01) == 0) + if ((ich_reg_read_8(cookie, ICH_REG_ACC_SEMA) & 0x01) == 0) return B_OK; if (i > 100) snooze(1); @@ -130,39 +118,39 @@ ich_codec_wait(audio_drv_t *drv) } uint16 -ich_codec_read(audio_drv_t *drv, int regno) +ich_codec_read(void *_cookie, int regno) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; + ichaudio_cookie *cookie = (ichaudio_cookie *)_cookie; ASSERT(regno >= 0); ASSERT((regno & 1) == 0); - ASSERT(((drv->flags & TYPE_ICH4) != 0 && regno <= 511) || regno <= 255); + ASSERT(((cookie->flags & TYPE_ICH4) != 0 && regno <= 511) || regno <= 255); if (regno == 0x54) // intel uses 0x54 for GPIO access, we filter it! return 0; - if (B_OK != ich_codec_wait(drv)) + if (B_OK != ich_codec_wait(cookie)) PRINT(("semaphore timeout reading register %#x\n", regno)); - if (drv->flags & TYPE_ICH4) + if (cookie->flags & TYPE_ICH4) return *(uint16 *)(((char *)cookie->mmbar) + regno); else - return drv->pci->read_io_16(cookie->nambar + regno); + return cookie->pci->read_io_16(cookie->nambar + regno); } void -ich_codec_write(audio_drv_t *drv, int regno, uint16 value) +ich_codec_write(void *_cookie, int regno, uint16 value) { - ichaudio_cookie *cookie = (ichaudio_cookie *)drv->cookie; + ichaudio_cookie *cookie = (ichaudio_cookie *)_cookie; ASSERT(regno >= 0); ASSERT((regno & 1) == 0); - ASSERT(((drv->flags & TYPE_ICH4) != 0 && regno <= 511) || regno <= 255); + ASSERT(((cookie->flags & TYPE_ICH4) != 0 && regno <= 511) || regno <= 255); if (regno == 0x54) // intel uses 0x54 for GPIO access, we filter it! return; - if (B_OK != ich_codec_wait(drv)) + if (B_OK != ich_codec_wait(cookie)) PRINT(("semaphore timeout writing register %#x\n", regno)); - if (drv->flags & TYPE_ICH4) + if (cookie->flags & TYPE_ICH4) *(uint16 *)(((char *)cookie->mmbar) + regno) = value; else - drv->pci->write_io_16(cookie->nambar + regno, value); + cookie->pci->write_io_16(cookie->nambar + regno, value); } diff --git a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/io.h b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/io.h index ee0aa51d00..12da0bf47c 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/io.h +++ b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/io.h @@ -30,15 +30,15 @@ #include "lala/lala.h" -uint8 ich_reg_read_8(audio_drv_t *drv, int regno); -uint16 ich_reg_read_16(audio_drv_t *drv, int regno); -uint32 ich_reg_read_32(audio_drv_t *drv, int regno); +uint8 ich_reg_read_8(ichaudio_cookie *cookie, int regno); +uint16 ich_reg_read_16(ichaudio_cookie *cookie, int regno); +uint32 ich_reg_read_32(ichaudio_cookie *cookie, int regno); -void ich_reg_write_8(audio_drv_t *drv, int regno, uint8 value); -void ich_reg_write_16(audio_drv_t *drv, int regno, uint16 value); -void ich_reg_write_32(audio_drv_t *drv, int regno, uint32 value); +void ich_reg_write_8(ichaudio_cookie *cookie, int regno, uint8 value); +void ich_reg_write_16(ichaudio_cookie *cookie, int regno, uint16 value); +void ich_reg_write_32(ichaudio_cookie *cookie, int regno, uint32 value); -uint16 ich_codec_read(audio_drv_t *drv, int regno); -void ich_codec_write(audio_drv_t *drv, int regno, uint16 value); +uint16 ich_codec_read(void *_cookie, int regno); +void ich_codec_write(void *_cookie, int regno, uint16 value); #endif diff --git a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/lala/driver.c b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/lala/driver.c index 26cf0a5ebc..f3f93ae120 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/lala/driver.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/lala/driver.c @@ -16,10 +16,13 @@ int32 api_version = B_CUR_DRIVER_API_VERSION; sem_id drv_sem; char * drv_path[MAX_DEVICES + 1]; audio_drv_t * drv_data[MAX_DEVICES]; +int drv_open_count[MAX_DEVICES]; +void * drv_cookie[MAX_DEVICES]; int drv_count; pci_module_info *pcimodule; +extern driver_info_t driver_info; status_t init_hardware(void) @@ -53,25 +56,25 @@ init_driver(void) // pciinfo->vendor_id, pciinfo->device_id, pciinfo->bus, pciinfo->device, pciinfo->function, // pciinfo->revision, pciinfo->class_api, pciinfo->class_sub, pciinfo->class_base); - for (devindex = 0; driver_info.table[devindex].vendor != 0; devindex++) { - if (driver_info.table[devindex].vendor != -1 && driver_info.table[devindex].vendor != pciinfo->vendor_id) + for (devindex = 0; driver_info.id_table[devindex].vendor != 0; devindex++) { + if (driver_info.id_table[devindex].vendor != -1 && driver_info.id_table[devindex].vendor != pciinfo->vendor_id) continue; - if (driver_info.table[devindex].device != -1 && driver_info.table[devindex].device != pciinfo->device_id) + if (driver_info.id_table[devindex].device != -1 && driver_info.id_table[devindex].device != pciinfo->device_id) continue; - if (driver_info.table[devindex].revision != -1 && driver_info.table[devindex].revision != pciinfo->revision) + if (driver_info.id_table[devindex].revision != -1 && driver_info.id_table[devindex].revision != pciinfo->revision) continue; - if (driver_info.table[devindex].class != -1 && driver_info.table[devindex].class != pciinfo->class_base) + if (driver_info.id_table[devindex].class != -1 && driver_info.id_table[devindex].class != pciinfo->class_base) continue; - if (driver_info.table[devindex].subclass != -1 && driver_info.table[devindex].subclass != pciinfo->class_sub) + if (driver_info.id_table[devindex].subclass != -1 && driver_info.id_table[devindex].subclass != pciinfo->class_sub) continue; if (pciinfo->header_type == 0) { - if (driver_info.table[devindex].subsystem_vendor != -1 && driver_info.table[devindex].subsystem_vendor != pciinfo->u.h0.subsystem_vendor_id) + if (driver_info.id_table[devindex].subsystem_vendor != -1 && driver_info.id_table[devindex].subsystem_vendor != pciinfo->u.h0.subsystem_vendor_id) continue; - if (driver_info.table[devindex].subsystem_device != -1 && driver_info.table[devindex].subsystem_device != pciinfo->u.h0.subsystem_id) + if (driver_info.id_table[devindex].subsystem_device != -1 && driver_info.id_table[devindex].subsystem_device != pciinfo->u.h0.subsystem_id) continue; } - dprintf("found device '%s'\n", driver_info.table[devindex].name); + dprintf("found device '%s'\n", driver_info.id_table[devindex].name); drv_path[drv_count] = (char *) malloc(strlen(driver_info.basename) + 5); sprintf(drv_path[drv_count], "%s/%d", driver_info.basename, drv_count + 1); @@ -81,10 +84,9 @@ init_driver(void) drv_data[drv_count]->bus = pciinfo->bus; drv_data[drv_count]->device = pciinfo->device; drv_data[drv_count]->function = pciinfo->function; - drv_data[drv_count]->name = driver_info.table[devindex].name; - drv_data[drv_count]->flags = driver_info.table[devindex].flags; - drv_data[drv_count]->open_count = 0; - drv_data[drv_count]->cookie = malloc(driver_info.cookie_size); + drv_data[drv_count]->name = driver_info.id_table[devindex].name; + drv_data[drv_count]->param = driver_info.id_table[devindex].param; + drv_open_count[drv_count] = 0; drv_count++; break; @@ -106,7 +108,6 @@ uninit_driver(void) for (i = 0; i < drv_count; i++) { free(drv_path[i]); - free(drv_data[i]->cookie); free(drv_data[i]); } delete_sem(drv_sem); @@ -130,13 +131,12 @@ ich_open(const char *name, uint32 flags, void** cookie) } *cookie = (void *) index; - if (drv_data[index]->open_count == 0) { - memset(drv_data[index]->cookie, 0, driver_info.cookie_size); - res = driver_info.attach(drv_data[index]); - drv_data[index]->open_count = (res == B_OK) ? 1 : 0; + if (drv_open_count[index] == 0) { + res = driver_info.attach(drv_data[index], &drv_cookie[index]); + drv_open_count[index] = (res == B_OK) ? 1 : 0; } else { res = B_OK; - drv_data[index]->open_count++; + drv_open_count[index]++; } release_sem(drv_sem); @@ -163,10 +163,10 @@ ich_free(void* cookie) acquire_sem(drv_sem); - drv_data[index]->open_count--; + drv_open_count[index]--; - if (drv_data[index]->open_count == 0) - res = driver_info.detach(drv_data[index]); + if (drv_open_count[index] == 0) + res = driver_info.detach(drv_data[index], drv_cookie[index]); else res = B_OK; diff --git a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/lala/lala.h b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/lala/lala.h index b8d4eb5fd8..74cf65a3dd 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ichaudio/lala/lala.h +++ b/src/add-ons/kernel/drivers/audio/ac97/ichaudio/lala/lala.h @@ -16,40 +16,36 @@ typedef struct uint8 function; const char * name; - uint32 flags; - - void * cookie; - -// private: - int32 open_count; + void * param; } audio_drv_t; -typedef void stream_id; -typedef void control_id; - -typedef struct { - int32 vendor; - int32 device; - int32 revision; - int32 class; - int32 subclass; - int32 subsystem_vendor; - int32 subsystem_device; - const char *name; - uint32 flags; +typedef struct +{ + int32 vendor; + int32 device; + int32 revision; + int32 class; + int32 subclass; + int32 subsystem_vendor; + int32 subsystem_device; + const char * name; + void * param; } id_table_t; -typedef status_t (*drv_attach) (audio_drv_t *drv); -typedef status_t (*drv_powerctl) (audio_drv_t *drv); -typedef status_t (*drv_detach) (audio_drv_t *drv); +typedef int32 stream_id; +typedef int32 control_id; + + +typedef status_t (*drv_attach) (audio_drv_t *drv, void **cookie); +typedef status_t (*drv_powerctl) (audio_drv_t *drv, void *cookie); +typedef status_t (*drv_detach) (audio_drv_t *drv, void *cookie); typedef struct { - id_table_t * table; + id_table_t * id_table; const char * basename; - size_t cookie_size; uint32 _reserved1[16]; @@ -61,69 +57,81 @@ typedef struct } driver_info_t; -typedef struct { +typedef struct +{ char * base; /* pointer to first sample for channel for buffer */ size_t stride; /* offset to next sample */ uint32 _reserved[4]; } stream_buffer_desc_t; -typedef struct { - uint32 frame_rate; - uint32 buffer_size; - uint32 _reserved[16]; -} stream_config_t; +typedef status_t (*stream_attach) (audio_drv_t *drv, void **cookie, void *param); +typedef status_t (*stream_detach) (audio_drv_t *drv, void *cookie); +typedef status_t (*stream_control) (audio_drv_t *drv, void *cookie, int op); +typedef status_t (*stream_process) (audio_drv_t *drv, void *cookie, int buffer); +typedef status_t (*stream_set_buffers) (audio_drv_t *drv, void *cookie, uint32 *buffer_size, stream_buffer_desc_t *desc); +typedef status_t (*stream_set_frame_rate) (audio_drv_t *drv, void *cookie, uint32 *frame_rate); +enum { + B_RECORDING_STREAM = 0x00000001, + B_PLAYBACK_STREAM = 0x00000002, + B_BUFFER_SIZE_LINEAR = 0x00001000, + B_BUFFER_SIZE_EXPONETIAL = 0x00002000, + B_SAMPLE_TYPE_INT16 = 0x00010000, + B_SAMPLE_TYPE_INT32 = 0x00020000, + B_SAMPLE_TYPE_FLOAT32 = 0x00040000, +}; -typedef status_t (*stream_attach) (audio_drv_t *drv, void *stream_cookie); -typedef status_t (*stream_detach) (audio_drv_t *drv, void *stream_cookie); -typedef status_t (*stream_control) (audio_drv_t *drv, void *stream_cookie, int op); -typedef status_t (*stream_get_buffer_info) (audio_drv_t *drv, void *stream_cookie, stream_buffer_desc_t *desc); -typedef status_t (*stream_set_config) (audio_drv_t *drv, void *stream_cookie, stream_config_t *config); +enum { + B_CHANNEL_LEFT = 0x0001, + B_CHANNEL_RIGHT = 0x0002, +}; +enum { + B_FRAME_RATE_32000 = 0x0100, + B_FRAME_RATE_44100 = 0x0200, + B_FRAME_RATE_48000 = 0x0400, + B_FRAME_RATE_96000 = 0x0800, + B_FRAME_RATE_VARIABLE = 0x20000000, +}; typedef struct { uint32 flags; uint32 cookie_size; - uint32 user_param; - uint32 user_cookie; uint32 sample_bits; - uint32 sample_flags; uint32 channel_count; - uint32 channel_flags; + uint32 channel_mask; uint32 frame_rate_min; uint32 frame_rate_max; - uint32 frame_rate_flags; + uint32 frame_rate_mask; uint32 buffer_size_min; uint32 buffer_size_max; - uint32 buffer_size_flags; + uint32 buffer_count; uint32 _reserved1[32]; stream_attach attach; stream_detach detach; stream_control control; + stream_process process; - stream_get_buffer_info get_buffer_info; - - stream_set_config set_config; + stream_set_buffers set_buffers; + stream_set_frame_rate set_frame_rate; uint32 _reserved2[16]; } stream_info_t; -extern driver_info_t driver_info; // protection is 0 for kernel only access, or B_READ_AREA, B_WRITE_AREA for user space access area_id alloc_mem(void **virt, void **phy, size_t size, uint32 protection, const char *name); area_id map_mem(void **virt, void *phy, size_t size, uint32 protection, const char *name); -stream_id create_stream(audio_drv_t *dev, stream_info_t *info, void *config); +stream_id create_stream(stream_info_t *info, void *param); status_t delete_stream(stream_id stream); -void report_stream_event(stream_id stream, int ); - +void report_stream_buffer_ready(stream_id stream, int buffer, bigtime_t end_time, int64 total_frames); control_id create_control_group(control_id parent, audio_drv_t *dev); control_id create_control(control_id parent, uint32 flags, void *get, void *set, const char *name);