Commit a9e4e4e0 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] update emu10k1 driver (SB Live, Audigy etc)

parent 349a40c8
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
********************************************************************** **********************************************************************
*/ */
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -983,11 +982,11 @@ static struct page *emu10k1_mm_nopage (struct vm_area_struct * vma, unsigned lon ...@@ -983,11 +982,11 @@ static struct page *emu10k1_mm_nopage (struct vm_area_struct * vma, unsigned lon
unsigned long pgoff; unsigned long pgoff;
int rd, wr; int rd, wr;
DPF(4, "emu10k1_mm_nopage()\n"); DPF(3, "emu10k1_mm_nopage()\n");
DPD(4, "addr: %#lx\n", address); DPD(3, "addr: %#lx\n", address);
if (address > vma->vm_end) { if (address > vma->vm_end) {
DPF(2, "EXIT, returning NOPAGE_SIGBUS\n"); DPF(1, "EXIT, returning NOPAGE_SIGBUS\n");
return NOPAGE_SIGBUS; /* Disallow mremap */ return NOPAGE_SIGBUS; /* Disallow mremap */
} }
...@@ -1009,14 +1008,14 @@ static struct page *emu10k1_mm_nopage (struct vm_area_struct * vma, unsigned lon ...@@ -1009,14 +1008,14 @@ static struct page *emu10k1_mm_nopage (struct vm_area_struct * vma, unsigned lon
pgoff -= woinst->buffer.pages; pgoff -= woinst->buffer.pages;
dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE); dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE);
} else } else
dmapage = virt_to_page (woinst->buffer.mem[0].addr[pgoff]); dmapage = virt_to_page (woinst->voice[0].mem.addr[pgoff]);
} else { } else {
dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE); dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE);
} }
get_page (dmapage); get_page (dmapage);
DPD(4, "page: %#lx\n", dmapage); DPD(3, "page: %#lx\n", (unsigned long) dmapage);
return dmapage; return dmapage;
} }
...@@ -1083,8 +1082,8 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1083,8 +1082,8 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma)
n_pages = ((vma->vm_end - vma->vm_start) + PAGE_SIZE - 1) >> PAGE_SHIFT; n_pages = ((vma->vm_end - vma->vm_start) + PAGE_SIZE - 1) >> PAGE_SHIFT;
pgoffset = vma->vm_pgoff; pgoffset = vma->vm_pgoff;
DPD(3, "vma_start: %#lx, vma_end: %#lx, vma_offset: %d\n", vma->vm_start, vma->vm_end, pgoffset); DPD(2, "vma_start: %#lx, vma_end: %#lx, vma_offset: %ld\n", vma->vm_start, vma->vm_end, pgoffset);
DPD(3, "n_pages: %d, max_pages: %d\n", n_pages, max_pages); DPD(2, "n_pages: %ld, max_pages: %ld\n", n_pages, max_pages);
if (pgoffset + n_pages > max_pages) if (pgoffset + n_pages > max_pages)
return -EINVAL; return -EINVAL;
...@@ -1092,7 +1091,6 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1092,7 +1091,6 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; vma->vm_flags |= VM_RESERVED;
vma->vm_ops = &emu10k1_mm_ops; vma->vm_ops = &emu10k1_mm_ops;
vma->vm_private_data = wave_dev; vma->vm_private_data = wave_dev;
return 0; return 0;
} }
...@@ -1136,7 +1134,8 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) ...@@ -1136,7 +1134,8 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file)
if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) { if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) {
ERROR(); ERROR();
return -ENODEV; kfree(wave_dev);
return -ENOMEM;
} }
wiinst->recsrc = card->wavein.recsrc; wiinst->recsrc = card->wavein.recsrc;
...@@ -1162,6 +1161,8 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) ...@@ -1162,6 +1161,8 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file)
wiinst->format.channels = hweight32(wiinst->fxwc); wiinst->format.channels = hweight32(wiinst->fxwc);
break; break;
default: default:
kfree(wave_dev);
kfree(wiinst);
BUG(); BUG();
break; break;
} }
...@@ -1211,7 +1212,7 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) ...@@ -1211,7 +1212,7 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file)
woinst->num_voices = 1; woinst->num_voices = 1;
for (i = 0; i < WAVEOUT_MAXVOICES; i++) { for (i = 0; i < WAVEOUT_MAXVOICES; i++) {
woinst->voice[i].usage = VOICE_USAGE_FREE; woinst->voice[i].usage = VOICE_USAGE_FREE;
woinst->buffer.mem[i].emupageindex = -1; woinst->voice[i].mem.emupageindex = -1;
} }
init_waitqueue_head(&woinst->wait_queue); init_waitqueue_head(&woinst->wait_queue);
...@@ -1330,23 +1331,13 @@ static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_stru ...@@ -1330,23 +1331,13 @@ static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_stru
if (file->f_mode & FMODE_READ) { if (file->f_mode & FMODE_READ) {
spin_lock_irqsave(&wiinst->lock, flags); spin_lock_irqsave(&wiinst->lock, flags);
if (wiinst->state == WAVE_STATE_CLOSED) { if (wiinst->state & WAVE_STATE_OPEN) {
calculate_ifrag(wiinst); emu10k1_wavein_update(wave_dev->card, wiinst);
if (emu10k1_wavein_open(wave_dev) < 0) { emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
spin_unlock_irqrestore(&wiinst->lock, flags);
return (mask |= POLLERR);
}
}
if (!(wiinst->state & WAVE_STATE_STARTED)) { if (bytestocopy >= wiinst->buffer.fragment_size)
wave_dev->enablebits |= PCM_ENABLE_INPUT; mask |= POLLIN | POLLRDNORM;
emu10k1_wavein_start(wave_dev);
} }
emu10k1_wavein_update(wave_dev->card, wiinst);
emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
if (bytestocopy >= wiinst->buffer.fragment_size)
mask |= POLLIN | POLLRDNORM;
spin_unlock_irqrestore(&wiinst->lock, flags); spin_unlock_irqrestore(&wiinst->lock, flags);
} }
...@@ -1376,6 +1367,13 @@ static void calculate_ofrag(struct woinst *woinst) ...@@ -1376,6 +1367,13 @@ static void calculate_ofrag(struct woinst *woinst)
buffer->fragment_size = 1 << buffer->ossfragshift; buffer->fragment_size = 1 << buffer->ossfragshift;
while (buffer->fragment_size * WAVEOUT_MINFRAGS > WAVEOUT_MAXBUFSIZE)
buffer->fragment_size >>= 1;
/* now we are sure that:
(2^WAVEOUT_MINFRAGSHIFT) <= (fragment_size = 2^n) <= (WAVEOUT_MAXBUFSIZE / WAVEOUT_MINFRAGS)
*/
if (!buffer->numfrags) { if (!buffer->numfrags) {
u32 numfrags; u32 numfrags;
...@@ -1390,19 +1388,14 @@ static void calculate_ofrag(struct woinst *woinst) ...@@ -1390,19 +1388,14 @@ static void calculate_ofrag(struct woinst *woinst)
} }
} }
if (buffer->numfrags < MINFRAGS) if (buffer->numfrags < WAVEOUT_MINFRAGS)
buffer->numfrags = MINFRAGS; buffer->numfrags = WAVEOUT_MINFRAGS;
if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE) { if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE)
buffer->numfrags = WAVEOUT_MAXBUFSIZE / buffer->fragment_size; buffer->numfrags = WAVEOUT_MAXBUFSIZE / buffer->fragment_size;
if (buffer->numfrags < MINFRAGS) { if (buffer->numfrags < WAVEOUT_MINFRAGS)
buffer->numfrags = MINFRAGS; BUG();
buffer->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS;
}
} else if (buffer->numfrags * buffer->fragment_size < WAVEOUT_MINBUFSIZE)
buffer->numfrags = WAVEOUT_MINBUFSIZE / buffer->fragment_size;
buffer->size = buffer->fragment_size * buffer->numfrags; buffer->size = buffer->fragment_size * buffer->numfrags;
buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0); buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0);
...@@ -1436,24 +1429,29 @@ static void calculate_ifrag(struct wiinst *wiinst) ...@@ -1436,24 +1429,29 @@ static void calculate_ifrag(struct wiinst *wiinst)
buffer->fragment_size = 1 << buffer->ossfragshift; buffer->fragment_size = 1 << buffer->ossfragshift;
while (buffer->fragment_size * WAVEIN_MINFRAGS > WAVEIN_MAXBUFSIZE)
buffer->fragment_size >>= 1;
/* now we are sure that:
(2^WAVEIN_MINFRAGSHIFT) <= (fragment_size = 2^n) <= (WAVEIN_MAXBUFSIZE / WAVEIN_MINFRAGS)
*/
if (!buffer->numfrags) if (!buffer->numfrags)
buffer->numfrags = (wiinst->format.bytespersec * WAVEIN_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1; buffer->numfrags = (wiinst->format.bytespersec * WAVEIN_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1;
if (buffer->numfrags < MINFRAGS) if (buffer->numfrags < WAVEIN_MINFRAGS)
buffer->numfrags = MINFRAGS; buffer->numfrags = WAVEIN_MINFRAGS;
if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE) { if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE)
buffer->numfrags = WAVEIN_MAXBUFSIZE / buffer->fragment_size; buffer->numfrags = WAVEIN_MAXBUFSIZE / buffer->fragment_size;
if (buffer->numfrags < MINFRAGS) { if (buffer->numfrags < WAVEIN_MINFRAGS)
buffer->numfrags = MINFRAGS; BUG();
buffer->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS;
}
} else if (buffer->numfrags * buffer->fragment_size < WAVEIN_MINBUFSIZE)
buffer->numfrags = WAVEIN_MINBUFSIZE / buffer->fragment_size;
bufsize = buffer->fragment_size * buffer->numfrags; bufsize = buffer->fragment_size * buffer->numfrags;
/* the buffer size for recording is restricted to certain values, adjust it now */
if (bufsize >= 0x10000) { if (bufsize >= 0x10000) {
buffer->size = 0x10000; buffer->size = 0x10000;
buffer->sizeregval = 0x1f; buffer->sizeregval = 0x1f;
...@@ -1479,10 +1477,12 @@ static void calculate_ifrag(struct wiinst *wiinst) ...@@ -1479,10 +1477,12 @@ static void calculate_ifrag(struct wiinst *wiinst)
} }
} }
/* adjust the fragment size so that buffer size is an integer multiple */
while (buffer->size % buffer->fragment_size)
buffer->fragment_size >>= 1;
buffer->numfrags = buffer->size / buffer->fragment_size; buffer->numfrags = buffer->size / buffer->fragment_size;
buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0); buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0);
if (buffer->size % buffer->fragment_size)
BUG();
DPD(2, " calculated recording fragment_size -> %d\n", buffer->fragment_size); DPD(2, " calculated recording fragment_size -> %d\n", buffer->fragment_size);
DPD(2, " calculated recording numfrags -> %d\n", buffer->numfrags); DPD(2, " calculated recording numfrags -> %d\n", buffer->numfrags);
......
...@@ -33,8 +33,6 @@ ...@@ -33,8 +33,6 @@
#ifndef _AUDIO_H #ifndef _AUDIO_H
#define _AUDIO_H #define _AUDIO_H
#define MINFRAGS 2 /* _don't_ got bellow 2 */
struct emu10k1_wavedevice struct emu10k1_wavedevice
{ {
struct emu10k1_card *card; struct emu10k1_card *card;
......
...@@ -96,6 +96,7 @@ void query_format(int recsrc, struct wave_format *wave_fmt) ...@@ -96,6 +96,7 @@ void query_format(int recsrc, struct wave_format *wave_fmt)
wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3; wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel; wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate; wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
wave_fmt->bytespervoicesample = wave_fmt->bytespersample;
} }
static int alloc_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer) static int alloc_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer)
...@@ -120,7 +121,7 @@ int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev) ...@@ -120,7 +121,7 @@ int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev)
struct emu10k1_card *card = wave_dev->card; struct emu10k1_card *card = wave_dev->card;
struct wiinst *wiinst = wave_dev->wiinst; struct wiinst *wiinst = wave_dev->wiinst;
struct wiinst **wiinst_tmp = NULL; struct wiinst **wiinst_tmp = NULL;
u32 delay; u16 delay;
unsigned long flags; unsigned long flags;
DPF(2, "emu10k1_wavein_open()\n"); DPF(2, "emu10k1_wavein_open()\n");
...@@ -169,6 +170,12 @@ int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev) ...@@ -169,6 +170,12 @@ int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev)
emu10k1_set_record_src(card, wiinst); emu10k1_set_record_src(card, wiinst);
emu10k1_reset_record(card, &wiinst->buffer);
wiinst->buffer.hw_pos = 0;
wiinst->buffer.pos = 0;
wiinst->buffer.bytestocopy = 0;
delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec; delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec;
emu10k1_timer_install(card, &wiinst->timer, delay / 2); emu10k1_timer_install(card, &wiinst->timer, delay / 2);
...@@ -222,10 +229,6 @@ void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev) ...@@ -222,10 +229,6 @@ void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev)
emu10k1_start_record(card, &wiinst->buffer); emu10k1_start_record(card, &wiinst->buffer);
emu10k1_timer_enable(wave_dev->card, &wiinst->timer); emu10k1_timer_enable(wave_dev->card, &wiinst->timer);
wiinst->buffer.hw_pos = 0;
wiinst->buffer.pos = 0;
wiinst->buffer.bytestocopy = 0;
wiinst->state |= WAVE_STATE_STARTED; wiinst->state |= WAVE_STATE_STARTED;
} }
...@@ -249,7 +252,7 @@ int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_fo ...@@ -249,7 +252,7 @@ int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_fo
{ {
struct emu10k1_card *card = wave_dev->card; struct emu10k1_card *card = wave_dev->card;
struct wiinst *wiinst = wave_dev->wiinst; struct wiinst *wiinst = wave_dev->wiinst;
u32 delay; u16 delay;
DPF(2, "emu10k1_wavein_setformat()\n"); DPF(2, "emu10k1_wavein_setformat()\n");
...@@ -304,10 +307,9 @@ void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size) ...@@ -304,10 +307,9 @@ void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size)
static void copy_block(u8 *dst, u8 * src, u32 str, u32 len, u8 cov) static void copy_block(u8 *dst, u8 * src, u32 str, u32 len, u8 cov)
{ {
if (cov == 1) { if (cov == 1)
if (__copy_to_user(dst, src + str, len)) __copy_to_user(dst, src + str, len);
return; else {
} else {
u8 byte; u8 byte;
u32 i; u32 i;
...@@ -315,8 +317,7 @@ static void copy_block(u8 *dst, u8 * src, u32 str, u32 len, u8 cov) ...@@ -315,8 +317,7 @@ static void copy_block(u8 *dst, u8 * src, u32 str, u32 len, u8 cov)
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
byte = src[2 * i] ^ 0x80; byte = src[2 * i] ^ 0x80;
if (__copy_to_user(dst + i, &byte, 1)) __copy_to_user(dst + i, &byte, 1);
return;
} }
} }
} }
......
...@@ -69,13 +69,14 @@ struct wiinst ...@@ -69,13 +69,14 @@ struct wiinst
u16 fxwc; u16 fxwc;
}; };
#define WAVEIN_MAXBUFSIZE 65536 #define WAVEIN_MAXBUFSIZE 65536
#define WAVEIN_MINBUFSIZE 368 #define WAVEIN_MINBUFSIZE 368
#define WAVEIN_DEFAULTFRAGLEN 100 #define WAVEIN_DEFAULTFRAGLEN 100
#define WAVEIN_DEFAULTBUFLEN 1000 #define WAVEIN_DEFAULTBUFLEN 1000
#define WAVEIN_MINFRAGSHIFT 8 #define WAVEIN_MINFRAGSHIFT 8
#define WAVEIN_MINFRAGS 2
int emu10k1_wavein_open(struct emu10k1_wavedevice *); int emu10k1_wavein_open(struct emu10k1_wavedevice *);
void emu10k1_wavein_close(struct emu10k1_wavedevice *); void emu10k1_wavein_close(struct emu10k1_wavedevice *);
......
...@@ -108,95 +108,20 @@ static void query_format(struct emu10k1_wavedevice *wave_dev, struct wave_format ...@@ -108,95 +108,20 @@ static void query_format(struct emu10k1_wavedevice *wave_dev, struct wave_format
} }
wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3; wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
if (wave_fmt->channels == 2) if (wave_fmt->channels == 2)
wave_fmt->bytespervoicesample = wave_fmt->channels * wave_fmt->bytesperchannel; wave_fmt->bytespervoicesample = wave_fmt->channels * wave_fmt->bytesperchannel;
else else
wave_fmt->bytespervoicesample = wave_fmt->bytesperchannel; wave_fmt->bytespervoicesample = wave_fmt->bytesperchannel;
wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
}
/**
* alloc_buffer -
*
* allocates the memory buffer for a voice. Two page tables are kept for each buffer.
* One (dma_handle) keeps track of the host memory pages used and the other (virtualpagetable)
* is passed to the device so that it can do DMA to host memory.
*
*/
static int alloc_buffer(struct emu10k1_card *card, struct waveout_buffer *buffer, unsigned int voicenum)
{
u32 pageindex, pagecount;
unsigned long busaddx;
int i;
DPD(2, "requested pages is: %d\n", buffer->pages);
if ((buffer->mem[voicenum].emupageindex =
emu10k1_addxmgr_alloc(buffer->pages * PAGE_SIZE, card)) < 0)
return -1;
/* Fill in virtual memory table */
for (pagecount = 0; pagecount < buffer->pages; pagecount++) {
if ((buffer->mem[voicenum].addr[pagecount] =
pci_alloc_consistent(card->pci_dev, PAGE_SIZE,
&buffer->mem[voicenum].dma_handle[pagecount])) == NULL) {
buffer->pages = pagecount;
return -1;
}
DPD(2, "Virtual Addx: %p\n", buffer->mem[voicenum].addr[pagecount]);
for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
busaddx = buffer->mem[voicenum].dma_handle[pagecount] + i * EMUPAGESIZE;
DPD(3, "Bus Addx: %#lx\n", busaddx);
pageindex = buffer->mem[voicenum].emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
((u32 *) card->virtualpagetable.addr)[pageindex] = cpu_to_le32((busaddx * 2) | pageindex);
}
}
return 0;
}
/**
* free_buffer -
*
* frees the memory buffer for a voice.
*/
static void free_buffer(struct emu10k1_card *card, struct waveout_buffer *buffer, unsigned int voicenum)
{
u32 pagecount, pageindex;
int i;
if (buffer->mem[voicenum].emupageindex < 0)
return;
for (pagecount = 0; pagecount < buffer->pages; pagecount++) {
pci_free_consistent(card->pci_dev, PAGE_SIZE,
buffer->mem[voicenum].addr[pagecount],
buffer->mem[voicenum].dma_handle[pagecount]);
for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
pageindex = buffer->mem[voicenum].emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
((u32 *) card->virtualpagetable.addr)[pageindex] =
cpu_to_le32((card->silentpage.dma_handle * 2) | pageindex);
}
}
emu10k1_addxmgr_free(card, buffer->mem[voicenum].emupageindex);
buffer->mem[voicenum].emupageindex = -1;
} }
static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned int voicenum) static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned int voicenum)
{ {
struct emu_voice *voice = &woinst->voice[voicenum]; struct emu_voice *voice = &woinst->voice[voicenum];
/* Allocate voices here, if no voices available, return error.
* Init voice_allocdesc first.*/ /* Allocate voices here, if no voices available, return error. */
voice->usage = VOICE_USAGE_PLAYBACK; voice->usage = VOICE_USAGE_PLAYBACK;
...@@ -219,7 +144,7 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned ...@@ -219,7 +144,7 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned
DPD(2, "Initial pitch --> %#x\n", voice->initial_pitch); DPD(2, "Initial pitch --> %#x\n", voice->initial_pitch);
voice->startloop = (woinst->buffer.mem[voicenum].emupageindex << 12) / voice->startloop = (voice->mem.emupageindex << 12) /
woinst->format.bytespervoicesample; woinst->format.bytespervoicesample;
voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespervoicesample; voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespervoicesample;
voice->start = voice->startloop; voice->start = voice->startloop;
...@@ -297,12 +222,12 @@ int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev) ...@@ -297,12 +222,12 @@ int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev)
struct woinst *woinst = wave_dev->woinst; struct woinst *woinst = wave_dev->woinst;
struct waveout_buffer *buffer = &woinst->buffer; struct waveout_buffer *buffer = &woinst->buffer;
unsigned int voicenum; unsigned int voicenum;
u32 delay; u16 delay;
DPF(2, "emu10k1_waveout_open()\n"); DPF(2, "emu10k1_waveout_open()\n");
for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) { for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) {
if (alloc_buffer(card, buffer, voicenum) < 0) { if (emu10k1_voice_alloc_buffer(card, &woinst->voice[voicenum].mem, woinst->buffer.pages) < 0) {
ERROR(); ERROR();
emu10k1_waveout_close(wave_dev); emu10k1_waveout_close(wave_dev);
return -1; return -1;
...@@ -324,7 +249,7 @@ int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev) ...@@ -324,7 +249,7 @@ int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev)
delay = (48000 * woinst->buffer.fragment_size) / delay = (48000 * woinst->buffer.fragment_size) /
(woinst->format.samplingrate * woinst->format.bytespervoicesample); (woinst->format.samplingrate * woinst->format.bytespervoicesample);
emu10k1_timer_install(card, &woinst->timer, delay / 2); emu10k1_timer_install(card, &woinst->timer, delay);
woinst->state = WAVE_STATE_OPEN; woinst->state = WAVE_STATE_OPEN;
...@@ -345,7 +270,7 @@ void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev) ...@@ -345,7 +270,7 @@ void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev)
for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) { for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) {
emu10k1_voice_free(&woinst->voice[voicenum]); emu10k1_voice_free(&woinst->voice[voicenum]);
free_buffer(card, &woinst->buffer, voicenum); emu10k1_voice_free_buffer(card, &woinst->voice[voicenum].mem);
} }
woinst->state = WAVE_STATE_CLOSED; woinst->state = WAVE_STATE_CLOSED;
...@@ -371,7 +296,7 @@ int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_f ...@@ -371,7 +296,7 @@ int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_f
struct emu10k1_card *card = wave_dev->card; struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst; struct woinst *woinst = wave_dev->woinst;
unsigned int voicenum; unsigned int voicenum;
u32 delay; u16 delay;
DPF(2, "emu10k1_waveout_setformat()\n"); DPF(2, "emu10k1_waveout_setformat()\n");
...@@ -404,7 +329,7 @@ int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_f ...@@ -404,7 +329,7 @@ int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_f
delay = (48000 * woinst->buffer.fragment_size) / delay = (48000 * woinst->buffer.fragment_size) /
(woinst->format.samplingrate * woinst->format.bytespervoicesample); (woinst->format.samplingrate * woinst->format.bytespervoicesample);
emu10k1_timer_install(card, &woinst->timer, delay / 2); emu10k1_timer_install(card, &woinst->timer, delay);
} }
return 0; return 0;
...@@ -449,7 +374,7 @@ void emu10k1_waveout_getxfersize(struct woinst *woinst, u32 *total_free_bytes) ...@@ -449,7 +374,7 @@ void emu10k1_waveout_getxfersize(struct woinst *woinst, u32 *total_free_bytes)
pending_bytes = buffer->size - buffer->free_bytes; pending_bytes = buffer->size - buffer->free_bytes;
buffer->fill_silence = (pending_bytes < (signed) buffer->fragment_size) ? 1 : 0; buffer->fill_silence = (pending_bytes < (signed) buffer->fragment_size * 2) ? 1 : 0;
if (pending_bytes > (signed) buffer->silence_bytes) { if (pending_bytes > (signed) buffer->silence_bytes) {
*total_free_bytes = (buffer->free_bytes + buffer->silence_bytes); *total_free_bytes = (buffer->free_bytes + buffer->silence_bytes);
...@@ -483,17 +408,14 @@ static void copy_block(void **dst, u32 str, u8 *src, u32 len) ...@@ -483,17 +408,14 @@ static void copy_block(void **dst, u32 str, u8 *src, u32 len)
if (len > PAGE_SIZE - pgoff) { if (len > PAGE_SIZE - pgoff) {
k = PAGE_SIZE - pgoff; k = PAGE_SIZE - pgoff;
if (__copy_from_user((u8 *)dst[pg] + pgoff, src, k)) __copy_from_user((u8 *)dst[pg] + pgoff, src, k);
return;
len -= k; len -= k;
while (len > PAGE_SIZE) { while (len > PAGE_SIZE) {
if (__copy_from_user(dst[++pg], src + k, PAGE_SIZE)) __copy_from_user(dst[++pg], src + k, PAGE_SIZE);
return;
k += PAGE_SIZE; k += PAGE_SIZE;
len -= PAGE_SIZE; len -= PAGE_SIZE;
} }
if (__copy_from_user(dst[++pg], src + k, len)) __copy_from_user(dst[++pg], src + k, len);
return;
} else } else
__copy_from_user((u8 *)dst[pg] + pgoff, src, len); __copy_from_user((u8 *)dst[pg] + pgoff, src, len);
...@@ -511,15 +433,14 @@ static void copy_ilv_block(struct woinst *woinst, u32 str, u8 *src, u32 len) ...@@ -511,15 +433,14 @@ static void copy_ilv_block(struct woinst *woinst, u32 str, u8 *src, u32 len)
unsigned int pg; unsigned int pg;
unsigned int pgoff; unsigned int pgoff;
unsigned int voice_num; unsigned int voice_num;
struct waveout_mem *mem = woinst->buffer.mem; struct emu_voice *voice = woinst->voice;
pg = str / PAGE_SIZE; pg = str / PAGE_SIZE;
pgoff = str % PAGE_SIZE; pgoff = str % PAGE_SIZE;
while (len) { while (len) {
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++) { for (voice_num = 0; voice_num < woinst->num_voices; voice_num++) {
if (__copy_from_user((u8 *)(mem[voice_num].addr[pg]) + pgoff, src, woinst->format.bytespervoicesample)) __copy_from_user((u8 *)(voice[voice_num].mem.addr[pg]) + pgoff, src, woinst->format.bytespervoicesample);
return;
src += woinst->format.bytespervoicesample; src += woinst->format.bytespervoicesample;
} }
...@@ -544,7 +465,7 @@ static void fill_block(struct woinst *woinst, u32 str, u8 data, u32 len) ...@@ -544,7 +465,7 @@ static void fill_block(struct woinst *woinst, u32 str, u8 data, u32 len)
unsigned int pg; unsigned int pg;
unsigned int pgoff; unsigned int pgoff;
unsigned int voice_num; unsigned int voice_num;
struct waveout_mem *mem = woinst->buffer.mem; struct emu_voice *voice = woinst->voice;
unsigned int k; unsigned int k;
pg = str / PAGE_SIZE; pg = str / PAGE_SIZE;
...@@ -553,22 +474,22 @@ static void fill_block(struct woinst *woinst, u32 str, u8 data, u32 len) ...@@ -553,22 +474,22 @@ static void fill_block(struct woinst *woinst, u32 str, u8 data, u32 len)
if (len > PAGE_SIZE - pgoff) { if (len > PAGE_SIZE - pgoff) {
k = PAGE_SIZE - pgoff; k = PAGE_SIZE - pgoff;
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++) for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
memset((u8 *)mem[voice_num].addr[pg] + pgoff, data, k); memset((u8 *)voice[voice_num].mem.addr[pg] + pgoff, data, k);
len -= k; len -= k;
while (len > PAGE_SIZE) { while (len > PAGE_SIZE) {
pg++; pg++;
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++) for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
memset(mem[voice_num].addr[pg], data, PAGE_SIZE); memset(voice[voice_num].mem.addr[pg], data, PAGE_SIZE);
len -= PAGE_SIZE; len -= PAGE_SIZE;
} }
pg++; pg++;
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++) for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
memset(mem[voice_num].addr[pg], data, len); memset(voice[voice_num].mem.addr[pg], data, len);
} else { } else {
for (voice_num = 0; voice_num < woinst->num_voices; voice_num++) for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
memset((u8 *)mem[voice_num].addr[pg] + pgoff, data, len); memset((u8 *)voice[voice_num].mem.addr[pg] + pgoff, data, len);
} }
} }
...@@ -582,6 +503,7 @@ static void fill_block(struct woinst *woinst, u32 str, u8 data, u32 len) ...@@ -582,6 +503,7 @@ static void fill_block(struct woinst *woinst, u32 str, u8 data, u32 len)
void emu10k1_waveout_xferdata(struct woinst *woinst, u8 *data, u32 *size) void emu10k1_waveout_xferdata(struct woinst *woinst, u8 *data, u32 *size)
{ {
struct waveout_buffer *buffer = &woinst->buffer; struct waveout_buffer *buffer = &woinst->buffer;
struct voice_mem *mem = &woinst->voice[0].mem;
u32 sizetocopy, sizetocopy_now, start; u32 sizetocopy, sizetocopy_now, start;
unsigned long flags; unsigned long flags;
...@@ -610,14 +532,14 @@ void emu10k1_waveout_xferdata(struct woinst *woinst, u8 *data, u32 *size) ...@@ -610,14 +532,14 @@ void emu10k1_waveout_xferdata(struct woinst *woinst, u8 *data, u32 *size)
copy_ilv_block(woinst, start, data, sizetocopy_now); copy_ilv_block(woinst, start, data, sizetocopy_now);
copy_ilv_block(woinst, 0, data + sizetocopy_now * woinst->num_voices, sizetocopy); copy_ilv_block(woinst, 0, data + sizetocopy_now * woinst->num_voices, sizetocopy);
} else { } else {
copy_block(buffer->mem[0].addr, start, data, sizetocopy_now); copy_block(mem->addr, start, data, sizetocopy_now);
copy_block(buffer->mem[0].addr, 0, data + sizetocopy_now, sizetocopy); copy_block(mem->addr, 0, data + sizetocopy_now, sizetocopy);
} }
} else { } else {
if (woinst->num_voices > 1) if (woinst->num_voices > 1)
copy_ilv_block(woinst, start, data, sizetocopy); copy_ilv_block(woinst, start, data, sizetocopy);
else else
copy_block(buffer->mem[0].addr, start, data, sizetocopy); copy_block(mem->addr, start, data, sizetocopy);
} }
} }
...@@ -674,7 +596,7 @@ void emu10k1_waveout_update(struct woinst *woinst) ...@@ -674,7 +596,7 @@ void emu10k1_waveout_update(struct woinst *woinst)
{ {
u32 hw_pos; u32 hw_pos;
u32 diff; u32 diff;
/* There is no actual start yet */ /* There is no actual start yet */
if (!(woinst->state & WAVE_STATE_STARTED)) { if (!(woinst->state & WAVE_STATE_STARTED)) {
hw_pos = woinst->buffer.hw_pos; hw_pos = woinst->buffer.hw_pos;
......
...@@ -39,20 +39,13 @@ ...@@ -39,20 +39,13 @@
/* setting this to other than a power of two may break some applications */ /* setting this to other than a power of two may break some applications */
#define WAVEOUT_MAXBUFSIZE MAXBUFSIZE #define WAVEOUT_MAXBUFSIZE MAXBUFSIZE
#define WAVEOUT_MINBUFSIZE 64
#define WAVEOUT_DEFAULTFRAGLEN 20 /* Time to play a fragment in ms (latency) */ #define WAVEOUT_DEFAULTFRAGLEN 20 /* Time to play a fragment in ms (latency) */
#define WAVEOUT_DEFAULTBUFLEN 500 /* Time to play the entire buffer in ms */ #define WAVEOUT_DEFAULTBUFLEN 500 /* Time to play the entire buffer in ms */
#define WAVEOUT_MINFRAGSHIFT 6 #define WAVEOUT_MINFRAGSHIFT 6 /* Minimum fragment size in bytes is 2^6 */
#define WAVEOUT_MAXVOICES 6 #define WAVEOUT_MINFRAGS 3 /* _don't_ go bellow 3, it would break silence filling */
#define WAVEOUT_MAXVOICES 6
/* waveout_mem is cardwo internal */
struct waveout_mem {
int emupageindex;
void *addr[BUFMAXPAGES];
dma_addr_t dma_handle[BUFMAXPAGES];
};
struct waveout_buffer { struct waveout_buffer {
u16 ossfragshift; u16 ossfragshift;
...@@ -60,7 +53,6 @@ struct waveout_buffer { ...@@ -60,7 +53,6 @@ struct waveout_buffer {
u32 fragment_size; /* in bytes units */ u32 fragment_size; /* in bytes units */
u32 size; /* in bytes units */ u32 size; /* in bytes units */
u32 pages; /* buffer size in page units*/ u32 pages; /* buffer size in page units*/
struct waveout_mem mem[WAVEOUT_MAXVOICES];
u32 silence_pos; /* software cursor position (including silence bytes) */ u32 silence_pos; /* software cursor position (including silence bytes) */
u32 hw_pos; /* hardware cursor position */ u32 hw_pos; /* hardware cursor position */
u32 free_bytes; /* free bytes available on the buffer (not including silence bytes) */ u32 free_bytes; /* free bytes available on the buffer (not including silence bytes) */
......
...@@ -38,7 +38,7 @@ int emu10k1_find_control_gpr(struct patch_manager *mgr, const char *patch_name, ...@@ -38,7 +38,7 @@ int emu10k1_find_control_gpr(struct patch_manager *mgr, const char *patch_name,
struct dsp_patch *patch; struct dsp_patch *patch;
struct dsp_rpatch *rpatch; struct dsp_rpatch *rpatch;
char s[PATCH_NAME_SIZE + 4]; char s[PATCH_NAME_SIZE + 4];
u32 *gpr_used; unsigned long *gpr_used;
int i; int i;
DPD(2, "emu10k1_find_control_gpr(): %s %s\n", patch_name, gpr_name); DPD(2, "emu10k1_find_control_gpr(): %s %s\n", patch_name, gpr_name);
...@@ -103,7 +103,7 @@ void emu10k1_set_oss_vol(struct emu10k1_card *card, int oss_mixer, ...@@ -103,7 +103,7 @@ void emu10k1_set_oss_vol(struct emu10k1_card *card, int oss_mixer,
card->ac97.mixer_state[oss_mixer] = (right << 8) | left; card->ac97.mixer_state[oss_mixer] = (right << 8) | left;
if (!card->isaps) if (!card->is_aps)
card->ac97.write_mixer(&card->ac97, oss_mixer, left, right); card->ac97.write_mixer(&card->ac97, oss_mixer, left, right);
emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][0], left, emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][0], left,
...@@ -171,9 +171,8 @@ void emu10k1_set_volume_gpr(struct emu10k1_card *card, int addr, s32 vol, int sc ...@@ -171,9 +171,8 @@ void emu10k1_set_volume_gpr(struct emu10k1_card *card, int addr, s32 vol, int sc
{ {
struct patch_manager *mgr = &card->mgr; struct patch_manager *mgr = &card->mgr;
unsigned long flags; unsigned long flags;
int muting;
const s32 log2lin[5] ={ // attenuation (dB) static const s32 log2lin[4] ={ // attenuation (dB)
0x7fffffff, // 0.0 0x7fffffff, // 0.0
0x7fffffff * 0.840896415253715 , // 1.5 0x7fffffff * 0.840896415253715 , // 1.5
0x7fffffff * 0.707106781186548, // 3.0 0x7fffffff * 0.707106781186548, // 3.0
...@@ -183,12 +182,10 @@ void emu10k1_set_volume_gpr(struct emu10k1_card *card, int addr, s32 vol, int sc ...@@ -183,12 +182,10 @@ void emu10k1_set_volume_gpr(struct emu10k1_card *card, int addr, s32 vol, int sc
if (addr < 0) if (addr < 0)
return; return;
muting = (scale == 0x10) ? 0x7f: scale;
vol = (100 - vol ) * scale / 100; vol = (100 - vol ) * scale / 100;
// Thanks to the comp.dsp newsgroup for this neat trick: // Thanks to the comp.dsp newsgroup for this neat trick:
vol = (vol >= muting) ? 0 : (log2lin[vol & 3] >> (vol >> 2)); vol = (vol >= scale) ? 0 : (log2lin[vol & 3] >> (vol >> 2));
spin_lock_irqsave(&mgr->lock, flags); spin_lock_irqsave(&mgr->lock, flags);
emu10k1_set_control_gpr(card, addr, vol, 0); emu10k1_set_control_gpr(card, addr, vol, 0);
......
...@@ -35,9 +35,9 @@ ...@@ -35,9 +35,9 @@
#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c)) #define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c))
#define OP(op, z, w, x, y) \ #define OP(op, z, w, x, y) \
do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \ do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \
WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \ WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \
++pc; } while (0) ++pc; } while (0)
#define NUM_INPUTS 0x20 #define NUM_INPUTS 0x20
#define NUM_OUTPUTS 0x20 #define NUM_OUTPUTS 0x20
...@@ -47,52 +47,52 @@ ...@@ -47,52 +47,52 @@
struct dsp_rpatch { struct dsp_rpatch {
char name[PATCH_NAME_SIZE]; char name[PATCH_NAME_SIZE];
u16 code_start; u16 code_start;
u16 code_size; u16 code_size;
u32 gpr_used[NUM_GPRS / 32]; unsigned long gpr_used[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
u32 gpr_input[NUM_GPRS / 32]; unsigned long gpr_input[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
u32 route[NUM_OUTPUTS]; unsigned long route[NUM_OUTPUTS];
u32 route_v[NUM_OUTPUTS]; unsigned long route_v[NUM_OUTPUTS];
}; };
struct dsp_patch { struct dsp_patch {
char name[PATCH_NAME_SIZE]; char name[PATCH_NAME_SIZE];
u8 id; u8 id;
u32 input; /* bitmap of the lines used as inputs */ unsigned long input; /* bitmap of the lines used as inputs */
u32 output; /* bitmap of the lines used as outputs */ unsigned long output; /* bitmap of the lines used as outputs */
u16 code_start; u16 code_start;
u16 code_size; u16 code_size;
u32 gpr_used[NUM_GPRS / 32]; /* bitmap of used gprs */ unsigned long gpr_used[NUM_GPRS / (sizeof(unsigned long) * 8) + 1]; /* bitmap of used gprs */
u32 gpr_input[NUM_GPRS / 32]; unsigned long gpr_input[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
u8 traml_istart; /* starting address of the internal tram lines used */ u8 traml_istart; /* starting address of the internal tram lines used */
u8 traml_isize; /* number of internal tram lines used */ u8 traml_isize; /* number of internal tram lines used */
u8 traml_estart; u8 traml_estart;
u8 traml_esize; u8 traml_esize;
u16 tramb_istart; /* starting address of the internal tram memory used */ u16 tramb_istart; /* starting address of the internal tram memory used */
u16 tramb_isize; /* amount of internal memory used */ u16 tramb_isize; /* amount of internal memory used */
u32 tramb_estart; u32 tramb_estart;
u32 tramb_esize; u32 tramb_esize;
}; };
struct dsp_gpr { struct dsp_gpr {
u8 type; /* gpr type, STATIC, DYNAMIC, INPUT, OUTPUT, CONTROL */ u8 type; /* gpr type, STATIC, DYNAMIC, INPUT, OUTPUT, CONTROL */
char name[GPR_NAME_SIZE]; /* gpr value, only valid for control gprs */ char name[GPR_NAME_SIZE]; /* gpr value, only valid for control gprs */
s32 min, max; /* value range for this gpr, only valid for control gprs */ s32 min, max; /* value range for this gpr, only valid for control gprs */
u8 line; /* which input/output line is the gpr attached, only valid for input/output gprs */ u8 line; /* which input/output line is the gpr attached, only valid for input/output gprs */
u8 usage; u8 usage;
}; };
enum { enum {
GPR_TYPE_NULL = 0, GPR_TYPE_NULL = 0,
GPR_TYPE_IO, GPR_TYPE_IO,
GPR_TYPE_STATIC, GPR_TYPE_STATIC,
GPR_TYPE_DYNAMIC, GPR_TYPE_DYNAMIC,
GPR_TYPE_CONTROL, GPR_TYPE_CONTROL,
GPR_TYPE_CONSTANT GPR_TYPE_CONSTANT
}; };
#define GPR_BASE 0x100 #define GPR_BASE 0x100
...@@ -101,15 +101,14 @@ enum { ...@@ -101,15 +101,14 @@ enum {
#define MAX_PATCHES_PAGES 32 #define MAX_PATCHES_PAGES 32
struct patch_manager { struct patch_manager {
void *patch[MAX_PATCHES_PAGES]; void *patch[MAX_PATCHES_PAGES];
int current_pages; int current_pages;
struct dsp_rpatch rpatch; struct dsp_rpatch rpatch;
struct dsp_gpr gpr[NUM_GPRS]; /* gpr usage table */ struct dsp_gpr gpr[NUM_GPRS]; /* gpr usage table */
spinlock_t lock; spinlock_t lock;
s16 ctrl_gpr[SOUND_MIXER_NRDEVICES][2]; s16 ctrl_gpr[SOUND_MIXER_NRDEVICES][2];
}; };
#define PATCHES_PER_PAGE (PAGE_SIZE / sizeof(struct dsp_patch)) #define PATCHES_PER_PAGE (PAGE_SIZE / sizeof(struct dsp_patch))
#define PATCH(mgr, i) ((struct dsp_patch *) (mgr)->patch[(i) / PATCHES_PER_PAGE] + (i) % PATCHES_PER_PAGE) #define PATCH(mgr, i) ((struct dsp_patch *) (mgr)->patch[(i) / PATCHES_PER_PAGE] + (i) % PATCHES_PER_PAGE)
......
...@@ -187,6 +187,15 @@ u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg) ...@@ -187,6 +187,15 @@ u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg)
} }
} }
void emu10k1_timer_set(struct emu10k1_card * card, u16 data)
{
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
outw(data & TIMER_RATE_MASK, card->iobase + TIMER);
spin_unlock_irqrestore(&card->lock, flags);
}
/************************************************************************ /************************************************************************
* write/read Emu10k1 pointer-offset register set, accessed through * * write/read Emu10k1 pointer-offset register set, accessed through *
* the PTR and DATA registers * * the PTR and DATA registers *
......
...@@ -126,6 +126,7 @@ struct mixer_private_ioctl { ...@@ -126,6 +126,7 @@ struct mixer_private_ioctl {
#define CMD_SETMCH_FX _IOW('D', 17, struct mixer_private_ioctl) #define CMD_SETMCH_FX _IOW('D', 17, struct mixer_private_ioctl)
#define CMD_SETPASSTHROUGH _IOW('D', 18, struct mixer_private_ioctl) #define CMD_SETPASSTHROUGH _IOW('D', 18, struct mixer_private_ioctl)
#define CMD_PRIVATE3_VERSION _IOW('D', 19, struct mixer_private_ioctl) #define CMD_PRIVATE3_VERSION _IOW('D', 19, struct mixer_private_ioctl)
#define CMD_AC97_BOOST _IOW('D', 20, struct mixer_private_ioctl)
//up this number when breaking compatibility //up this number when breaking compatibility
#define PRIVATE3_VERSION 1 #define PRIVATE3_VERSION 1
...@@ -144,7 +145,7 @@ struct emu10k1_card ...@@ -144,7 +145,7 @@ struct emu10k1_card
u16 emupagetable[MAXPAGES]; u16 emupagetable[MAXPAGES];
struct list_head timers; struct list_head timers;
unsigned timer_delay; u16 timer_delay;
spinlock_t timer_lock; spinlock_t timer_lock;
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
...@@ -181,7 +182,7 @@ struct emu10k1_card ...@@ -181,7 +182,7 @@ struct emu10k1_card
u8 chiprev; /* Chip revision */ u8 chiprev; /* Chip revision */
int isaps; u8 is_aps;
struct patch_manager mgr; struct patch_manager mgr;
struct pt_data pt; struct pt_data pt;
...@@ -190,8 +191,6 @@ struct emu10k1_card ...@@ -190,8 +191,6 @@ struct emu10k1_card
int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *); int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *);
void emu10k1_addxmgr_free(struct emu10k1_card *, int); void emu10k1_addxmgr_free(struct emu10k1_card *, int);
int emu10k1_find_control_gpr(struct patch_manager *, const char *, const char *); int emu10k1_find_control_gpr(struct patch_manager *, const char *, const char *);
void emu10k1_set_control_gpr(struct emu10k1_card *, int , s32, int ); void emu10k1_set_control_gpr(struct emu10k1_card *, int , s32, int );
...@@ -211,12 +210,14 @@ extern struct list_head emu10k1_devs; ...@@ -211,12 +210,14 @@ extern struct list_head emu10k1_devs;
/* Hardware Abstraction Layer access functions */ /* Hardware Abstraction Layer access functions */
void emu10k1_writefn0(struct emu10k1_card *, u32 , u32 ); void emu10k1_writefn0(struct emu10k1_card *, u32, u32);
u32 emu10k1_readfn0(struct emu10k1_card *, u32 ); u32 emu10k1_readfn0(struct emu10k1_card *, u32);
void emu10k1_timer_set(struct emu10k1_card *, u16);
void sblive_writeptr(struct emu10k1_card *, u32 , u32 , u32 ); void sblive_writeptr(struct emu10k1_card *, u32, u32, u32);
void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...); void sblive_writeptr_tag(struct emu10k1_card *, u32, ...);
#define TAGLIST_END 0 #define TAGLIST_END 0
u32 sblive_readptr(struct emu10k1_card *, u32 , u32 ); u32 sblive_readptr(struct emu10k1_card *, u32 , u32 );
......
/* /*
********************************************************************** **********************************************************************
* irqmgr.c - IRQ manager for emu10k1 driver * irqmgr.c - IRQ manager for emu10k1 driver
...@@ -41,7 +40,7 @@ ...@@ -41,7 +40,7 @@
void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct emu10k1_card *card = (struct emu10k1_card *) dev_id; struct emu10k1_card *card = (struct emu10k1_card *) dev_id;
u32 irqstatus; u32 irqstatus, irqstatus_tmp;
DPD(4, "emu10k1_interrupt called, irq = %u\n", irq); DPD(4, "emu10k1_interrupt called, irq = %u\n", irq);
...@@ -60,8 +59,7 @@ void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -60,8 +59,7 @@ void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
while ((irqstatus = inl(card->iobase + IPR))) { while ((irqstatus = inl(card->iobase + IPR))) {
DPD(4, "irq status %#x\n", irqstatus); DPD(4, "irq status %#x\n", irqstatus);
/* acknowledge interrupt */ irqstatus_tmp = irqstatus;
outl(irqstatus, card->iobase + IPR);
if (irqstatus & IRQTYPE_TIMER) { if (irqstatus & IRQTYPE_TIMER) {
emu10k1_timer_irqhandler(card); emu10k1_timer_irqhandler(card);
...@@ -98,7 +96,15 @@ void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -98,7 +96,15 @@ void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
irqstatus &=~IPR_VOLDECR; irqstatus &=~IPR_VOLDECR;
} }
if (irqstatus) if (irqstatus){
emu10k1_irq_disable(card, irqstatus); printk(KERN_ERR "emu10k1: Warning, unhandled interrupt: %#08x\n", irqstatus);
//make sure any interrupts we don't handle are disabled:
emu10k1_irq_disable(card, ~(INTE_MIDIRXENABLE | INTE_MIDITXENABLE | INTE_INTERVALTIMERENB |
INTE_VOLDECRENABLE | INTE_VOLINCRENABLE | INTE_MUTEENABLE |
INTE_FXDSPENABLE));
}
/* acknowledge interrupt */
outl(irqstatus_tmp, card->iobase + IPR);
} }
} }
/* /*
********************************************************************** **********************************************************************
* main.c - Creative EMU10K1 audio driver * main.c - Creative EMU10K1 audio driver
* Copyright 1999, 2000 Creative Labs, Inc. * Copyright 1999, 2000 Creative Labs, Inc.
...@@ -69,7 +69,20 @@ ...@@ -69,7 +69,20 @@
* 0.16 Mixer improvements, added old treble/bass support (Daniel Bertrand) * 0.16 Mixer improvements, added old treble/bass support (Daniel Bertrand)
* Small code format cleanup. * Small code format cleanup.
* Deadlock bug fix for emu10k1_volxxx_irqhandler(). * Deadlock bug fix for emu10k1_volxxx_irqhandler().
* * 0.17 Fix for mixer SOUND_MIXER_INFO ioctl.
* Fix for HIGHMEM machines (emu10k1 can only do 31 bit bus master)
* midi poll initial implementation.
* Small mixer fixes/cleanups.
* Improved support for 5.1 cards.
* 0.18 Fix for possible leak in pci_alloc_consistent()
* Cleaned up poll() functions (audio and midi). Don't start input.
* Restrict DMA pages used to 512Mib range.
* New AC97_BOOST mixer ioctl.
* 0.19 Real fix for kernel with highmem support (cast dma_handle to u32).
* Fix recording buffering parameters calculation.
* Use unsigned long for variables in bit ops.
* 0.20 Fixed recording startup
* Fixed timer rate setting (it's a 16-bit register)
*********************************************************************/ *********************************************************************/
/* These are only included once per module */ /* These are only included once per module */
...@@ -102,11 +115,10 @@ ...@@ -102,11 +115,10 @@
#define SNDCARD_EMU10K1 46 #define SNDCARD_EMU10K1 46
#endif #endif
#define DRIVER_VERSION "0.16" #define DRIVER_VERSION "0.20"
/* FIXME: is this right? */ /* the emu10k1 _seems_ to only supports 29 bit (512MiB) bit bus master */
/* does the card support 32 bit bus master?*/ #define EMU10K1_DMA_MASK 0x1fffffff /* DMA buffer mask for pci_alloc_consist */
#define EMU10K1_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */
#ifndef PCI_VENDOR_ID_CREATIVE #ifndef PCI_VENDOR_ID_CREATIVE
#define PCI_VENDOR_ID_CREATIVE 0x1102 #define PCI_VENDOR_ID_CREATIVE 0x1102
...@@ -188,7 +200,7 @@ static int __devinit emu10k1_audio_init(struct emu10k1_card *card) ...@@ -188,7 +200,7 @@ static int __devinit emu10k1_audio_init(struct emu10k1_card *card)
/* Assign default recording parameters */ /* Assign default recording parameters */
/* FIXME */ /* FIXME */
if(card->isaps) if (card->is_aps)
card->wavein.recsrc = WAVERECORD_FX; card->wavein.recsrc = WAVERECORD_FX;
else else
card->wavein.recsrc = WAVERECORD_AC97; card->wavein.recsrc = WAVERECORD_AC97;
...@@ -211,6 +223,8 @@ static void __devinit emu10k1_audio_cleanup(struct emu10k1_card *card) ...@@ -211,6 +223,8 @@ static void __devinit emu10k1_audio_cleanup(struct emu10k1_card *card)
static int __devinit emu10k1_mixer_init(struct emu10k1_card *card) static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
{ {
char s[32]; char s[32];
struct ac97_codec *codec = &card->ac97;
card->ac97.dev_mixer = register_sound_mixer(&emu10k1_mixer_fops, -1); card->ac97.dev_mixer = register_sound_mixer(&emu10k1_mixer_fops, -1);
if (card->ac97.dev_mixer < 0) { if (card->ac97.dev_mixer < 0) {
printk(KERN_ERR "emu10k1: cannot register mixer device\n"); printk(KERN_ERR "emu10k1: cannot register mixer device\n");
...@@ -219,7 +233,7 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card) ...@@ -219,7 +233,7 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
card->ac97.private_data = card; card->ac97.private_data = card;
if (!card->isaps) { if (!card->is_aps) {
card->ac97.id = 0; card->ac97.id = 0;
card->ac97.codec_read = emu10k1_ac97_read; card->ac97.codec_read = emu10k1_ac97_read;
card->ac97.codec_write = emu10k1_ac97_write; card->ac97.codec_write = emu10k1_ac97_write;
...@@ -228,11 +242,14 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card) ...@@ -228,11 +242,14 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
printk(KERN_ERR "emu10k1: unable to probe AC97 codec\n"); printk(KERN_ERR "emu10k1: unable to probe AC97 codec\n");
goto err_out; goto err_out;
} }
/* 5.1: Enable the additional AC97 Slots. If the emu10k1 version /* 5.1: Enable the additional AC97 Slots and unmute extra channels on AC97 codec */
does not support this, it shouldn't do any harm */ if (codec->codec_read(codec, AC97_EXTENDED_ID) & 0x0080){
sblive_writeptr(card, AC97SLOT, 0, AC97SLOT_CNTR | AC97SLOT_LFE); printk(KERN_INFO "emu10k1: SBLive! 5.1 card detected\n");
sblive_writeptr(card, AC97SLOT, 0, AC97SLOT_CNTR | AC97SLOT_LFE);
codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0);
}
// Force 5bit // Force 5bit:
//card->ac97.bit_resolution=5; //card->ac97.bit_resolution=5;
if (!proc_mkdir ("driver/emu10k1", 0)) { if (!proc_mkdir ("driver/emu10k1", 0)) {
...@@ -274,7 +291,7 @@ static void __devinit emu10k1_mixer_cleanup(struct emu10k1_card *card) ...@@ -274,7 +291,7 @@ static void __devinit emu10k1_mixer_cleanup(struct emu10k1_card *card)
{ {
char s[32]; char s[32];
if (!card->isaps) { if (!card->is_aps) {
sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name); sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name);
remove_proc_entry(s, NULL); remove_proc_entry(s, NULL);
...@@ -586,15 +603,15 @@ static int __devinit fx_init(struct emu10k1_card *card) ...@@ -586,15 +603,15 @@ static int __devinit fx_init(struct emu10k1_card *card)
CONNECT(PCM1_IN_R, ANALOG_REAR_R); CONNECT(PCM1_IN_R, ANALOG_REAR_R);
/* Digital In + PCM + AC97 In + MULTI_FRONT --> Digital out */ /* Digital In + PCM + AC97 In + MULTI_FRONT --> Digital out */
OP(6, 0x10b, 0x100, 0x102, 0x10c); OP(6, 0x10a, 0x100, 0x102, 0x10c);
OP(6, 0x10b, 0x10b, 0x113, 0x40); OP(6, 0x10a, 0x10a, 0x113, 0x40);
CONNECT(MULTI_FRONT_L, DIGITAL_OUT_L); CONNECT(MULTI_FRONT_L, DIGITAL_OUT_L);
CONNECT(PCM_IN_L, DIGITAL_OUT_L); CONNECT(PCM_IN_L, DIGITAL_OUT_L);
CONNECT(AC97_IN_L, DIGITAL_OUT_L); CONNECT(AC97_IN_L, DIGITAL_OUT_L);
CONNECT(SPDIF_CD_L, DIGITAL_OUT_L); CONNECT(SPDIF_CD_L, DIGITAL_OUT_L);
OP(6, 0x10a, 0x101, 0x103, 0x10e); OP(6, 0x10b, 0x101, 0x103, 0x10e);
OP(6, 0x10b, 0x10b, 0x114, 0x40); OP(6, 0x10b, 0x10b, 0x114, 0x40);
CONNECT(MULTI_FRONT_R, DIGITAL_OUT_R); CONNECT(MULTI_FRONT_R, DIGITAL_OUT_R);
...@@ -768,7 +785,7 @@ static int __devinit hw_init(struct emu10k1_card *card) ...@@ -768,7 +785,7 @@ static int __devinit hw_init(struct emu10k1_card *card)
VTFT, 0xffff, VTFT, 0xffff,
CVCF, 0xffff, CVCF, 0xffff,
PTRX, 0, PTRX, 0,
CPF, 0, //CPF, 0,
CCR, 0, CCR, 0,
PSST, 0, PSST, 0,
...@@ -794,7 +811,9 @@ static int __devinit hw_init(struct emu10k1_card *card) ...@@ -794,7 +811,9 @@ static int __devinit hw_init(struct emu10k1_card *card)
ENVVOL, 0, ENVVOL, 0,
ENVVAL, 0, ENVVAL, 0,
TAGLIST_END); TAGLIST_END);
sblive_writeptr(card, CPF, nCh, 0);
} }
/* /*
** Init to 0x02109204 : ** Init to 0x02109204 :
...@@ -852,19 +871,19 @@ static int __devinit hw_init(struct emu10k1_card *card) ...@@ -852,19 +871,19 @@ static int __devinit hw_init(struct emu10k1_card *card)
} }
for (pagecount = 0; pagecount < MAXPAGES; pagecount++) for (pagecount = 0; pagecount < MAXPAGES; pagecount++)
((u32 *) card->virtualpagetable.addr)[pagecount] = cpu_to_le32((card->silentpage.dma_handle * 2) | pagecount); ((u32 *) card->virtualpagetable.addr)[pagecount] = cpu_to_le32(((u32) card->silentpage.dma_handle * 2) | pagecount);
/* Init page table & tank memory base register */ /* Init page table & tank memory base register */
sblive_writeptr_tag(card, 0, sblive_writeptr_tag(card, 0,
PTB, card->virtualpagetable.dma_handle, PTB, (u32) card->virtualpagetable.dma_handle,
TCB, 0, TCB, 0,
TCBS, 0, TCBS, 0,
TAGLIST_END); TAGLIST_END);
for (nCh = 0; nCh < NUM_G; nCh++) { for (nCh = 0; nCh < NUM_G; nCh++) {
sblive_writeptr_tag(card, nCh, sblive_writeptr_tag(card, nCh,
MAPA, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), MAPA, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), MAPB, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
TAGLIST_END); TAGLIST_END);
} }
...@@ -951,8 +970,9 @@ static void __devinit emu10k1_cleanup(struct emu10k1_card *card) ...@@ -951,8 +970,9 @@ static void __devinit emu10k1_cleanup(struct emu10k1_card *card)
VTFT, 0, VTFT, 0,
CVCF, 0, CVCF, 0,
PTRX, 0, PTRX, 0,
CPF, 0, //CPF, 0,
TAGLIST_END); TAGLIST_END);
sblive_writeptr(card, CPF, ch, 0);
} }
/* Disable audio and lock cache */ /* Disable audio and lock cache */
...@@ -999,7 +1019,7 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev ...@@ -999,7 +1019,7 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev
int ret; int ret;
if (pci_set_dma_mask(pci_dev, EMU10K1_DMA_MASK)) { if (pci_set_dma_mask(pci_dev, EMU10K1_DMA_MASK)) {
printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n"); printk(KERN_ERR "emu10k1: architecture does not support 29bit PCI busmaster DMA\n");
return -ENODEV; return -ENODEV;
} }
...@@ -1038,12 +1058,12 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev ...@@ -1038,12 +1058,12 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev
pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev); pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev);
pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &card->model); pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &card->model);
printk(KERN_INFO "emu10k1: %s rev %d model 0x%x found, IO at 0x%04lx-0x%04lx, IRQ %d\n", printk(KERN_INFO "emu10k1: %s rev %d model %#04x found, IO at %#04lx-%#04lx, IRQ %d\n",
card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase, card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase,
card->iobase + card->length - 1, card->irq); card->iobase + card->length - 1, card->irq);
pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid); pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
card->isaps = (subsysvid == EMU_APS_SUBID); card->is_aps = (subsysvid == EMU_APS_SUBID);
spin_lock_init(&card->lock); spin_lock_init(&card->lock);
init_MUTEX(&card->open_sem); init_MUTEX(&card->open_sem);
...@@ -1074,7 +1094,7 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev ...@@ -1074,7 +1094,7 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev
goto err_emu10k1_init; goto err_emu10k1_init;
} }
if (card->isaps) if (card->is_aps)
emu10k1_ecard_init(card); emu10k1_ecard_init(card);
list_add(&card->list, &emu10k1_devs); list_add(&card->list, &emu10k1_devs);
...@@ -1119,7 +1139,7 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev) ...@@ -1119,7 +1139,7 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev)
pci_set_drvdata(pci_dev, NULL); pci_set_drvdata(pci_dev, NULL);
} }
MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)"); MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@lists.sourceforge.net)");
MODULE_DESCRIPTION("Creative EMU10K1 PCI Audio Driver v" DRIVER_VERSION "\nCopyright (C) 1999 Creative Technology Ltd."); MODULE_DESCRIPTION("Creative EMU10K1 PCI Audio Driver v" DRIVER_VERSION "\nCopyright (C) 1999 Creative Technology Ltd.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
********************************************************************** **********************************************************************
*/ */
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/poll.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -371,8 +371,32 @@ static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t ...@@ -371,8 +371,32 @@ static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t
static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait) static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait)
{ {
struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
unsigned long flags;
unsigned int mask = 0;
DPF(4, "emu10k1_midi_poll() called\n"); DPF(4, "emu10k1_midi_poll() called\n");
return 0;
if (file->f_mode & FMODE_WRITE)
poll_wait(file, &midi_dev->oWait, wait);
if (file->f_mode & FMODE_READ)
poll_wait(file, &midi_dev->iWait, wait);
spin_lock_irqsave(&midi_spinlock, flags);
if (file->f_mode & FMODE_WRITE)
mask |= POLLOUT | POLLWRNORM;
if (file->f_mode & FMODE_READ) {
if (midi_dev->mistate == MIDIIN_STATE_STARTED)
if (midi_dev->icnt > 0)
mask |= POLLIN | POLLRDNORM;
}
spin_unlock_irqrestore(&midi_spinlock, flags);
return mask;
} }
int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg) int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg)
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
********************************************************************** **********************************************************************
*/ */
#define __NO_VERSION__ /* Kernel version only defined once */
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h> #include <linux/version.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -251,7 +250,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -251,7 +250,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
case CMD_SETRECSRC: case CMD_SETRECSRC:
switch (ctl->val[0]) { switch (ctl->val[0]) {
case WAVERECORD_AC97: case WAVERECORD_AC97:
if (card->isaps) { if (card->is_aps) {
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
...@@ -444,6 +443,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -444,6 +443,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
case CMD_SETGPR2OSS: case CMD_SETGPR2OSS:
id = ctl->val[0]; id = ctl->val[0];
/* 0 == left, 1 == right */
ch = ctl->val[1]; ch = ctl->val[1];
addr = ctl->val[2]; addr = ctl->val[2];
...@@ -454,19 +454,19 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -454,19 +454,19 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
card->mgr.ctrl_gpr[id][ch] = addr; card->mgr.ctrl_gpr[id][ch] = addr;
if (card->isaps) if (card->is_aps)
break; break;
if (addr >= 0) { if (addr >= 0) {
unsigned int state = card->ac97.mixer_state[id]; unsigned int state = card->ac97.mixer_state[id];
if (ch) { if (ch == 1) {
state >>= 8; state >>= 8;
card->ac97.stereo_mixers |= (1 << id); card->ac97.stereo_mixers |= (1 << id);
} else {
card->ac97.supported_mixers |= (1 << id);
} }
card->ac97.supported_mixers |= (1 << id);
if (id == SOUND_MIXER_TREBLE) { if (id == SOUND_MIXER_TREBLE) {
set_treble(card, card->ac97.mixer_state[id] & 0xff, (card->ac97.mixer_state[id] >> 8) & 0xff); set_treble(card, card->ac97.mixer_state[id] & 0xff, (card->ac97.mixer_state[id] >> 8) & 0xff);
} else if (id == SOUND_MIXER_BASS) { } else if (id == SOUND_MIXER_BASS) {
...@@ -475,10 +475,10 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -475,10 +475,10 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
emu10k1_set_volume_gpr(card, addr, state & 0xff, emu10k1_set_volume_gpr(card, addr, state & 0xff,
volume_params[id]); volume_params[id]);
} else { } else {
if (ch) { card->ac97.stereo_mixers &= ~(1 << id);
card->ac97.stereo_mixers &= ~(1 << id); card->ac97.stereo_mixers |= card->ac97_stereo_mixers;
card->ac97.stereo_mixers |= card->ac97_stereo_mixers;
} else { if (ch == 0) {
card->ac97.supported_mixers &= ~(1 << id); card->ac97.supported_mixers &= ~(1 << id);
card->ac97.supported_mixers |= card->ac97_supported_mixers; card->ac97.supported_mixers |= card->ac97_supported_mixers;
} }
...@@ -499,6 +499,12 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -499,6 +499,12 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
ret = -EFAULT; ret = -EFAULT;
break; break;
case CMD_AC97_BOOST:
if(ctl->val[0])
emu10k1_ac97_write(&card->ac97, 0x18, 0x0);
else
emu10k1_ac97_write(&card->ac97, 0x18, 0x0808);
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
break; break;
...@@ -551,7 +557,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un ...@@ -551,7 +557,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
card->tankmem.size = size; card->tankmem.size = size;
sblive_writeptr_tag(card, 0, TCB, card->tankmem.dma_handle, TCBS, size_reg, TAGLIST_END); sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS, size_reg, TAGLIST_END);
emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0); emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
} }
...@@ -572,6 +578,8 @@ static int emu10k1_dsp_mixer(struct emu10k1_card *card, unsigned int oss_mixer, ...@@ -572,6 +578,8 @@ static int emu10k1_dsp_mixer(struct emu10k1_card *card, unsigned int oss_mixer,
int val; int val;
int scale; int scale;
card->ac97.modcnt++;
if (get_user(val, (int *)arg)) if (get_user(val, (int *)arg))
return -EFAULT; return -EFAULT;
...@@ -612,7 +620,7 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -612,7 +620,7 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned
unsigned int oss_mixer = _IOC_NR(cmd); unsigned int oss_mixer = _IOC_NR(cmd);
ret = -EINVAL; ret = -EINVAL;
if (!card->isaps) { if (!card->is_aps) {
if (cmd == SOUND_MIXER_INFO) { if (cmd == SOUND_MIXER_INFO) {
mixer_info info; mixer_info info;
...@@ -626,7 +634,7 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned ...@@ -626,7 +634,7 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned
return 0; return 0;
} }
if ((_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) && oss_mixer <= SOUND_MIXER_NRDEVICES) if ((_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) && oss_mixer <= SOUND_MIXER_NRDEVICES)
ret = emu10k1_dsp_mixer(card, oss_mixer, arg); ret = emu10k1_dsp_mixer(card, oss_mixer, arg);
else else
ret = card->ac97.mixer_ioctl(&card->ac97, cmd, arg); ret = card->ac97.mixer_ioctl(&card->ac97, cmd, arg);
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
********************************************************************** **********************************************************************
*/ */
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -165,15 +164,12 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count) ...@@ -165,15 +164,12 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count)
DPD(3, "prepend size %d, prepending %d bytes\n", pt->prepend_size, needed); DPD(3, "prepend size %d, prepending %d bytes\n", pt->prepend_size, needed);
if (count < needed) { if (count < needed) {
if (copy_from_user(pt->buf + pt->prepend_size, buffer, copy_from_user(pt->buf + pt->prepend_size, buffer, count);
count))
return -EFAULT;
pt->prepend_size += count; pt->prepend_size += count;
DPD(3, "prepend size now %d\n", pt->prepend_size); DPD(3, "prepend size now %d\n", pt->prepend_size);
return count; return count;
} }
if (copy_from_user(pt->buf + pt->prepend_size, buffer, needed)) copy_from_user(pt->buf + pt->prepend_size, buffer, needed);
return -EFAULT;
r = pt_putblock(wave_dev, (u16 *) pt->buf, nonblock); r = pt_putblock(wave_dev, (u16 *) pt->buf, nonblock);
if (r) if (r)
return r; return r;
...@@ -184,8 +180,7 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count) ...@@ -184,8 +180,7 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count)
blocks_copied = 0; blocks_copied = 0;
while (blocks > 0) { while (blocks > 0) {
u16 *bufptr = (u16 *) buffer + (bytes_copied/2); u16 *bufptr = (u16 *) buffer + (bytes_copied/2);
if (copy_from_user(pt->buf, bufptr, PT_BLOCKSIZE)) copy_from_user(pt->buf, bufptr, PT_BLOCKSIZE);
return -EFAULT;
bufptr = (u16 *) pt->buf; bufptr = (u16 *) pt->buf;
r = pt_putblock(wave_dev, bufptr, nonblock); r = pt_putblock(wave_dev, bufptr, nonblock);
if (r) { if (r) {
...@@ -201,8 +196,7 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count) ...@@ -201,8 +196,7 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count)
i = count - bytes_copied; i = count - bytes_copied;
if (i) { if (i) {
pt->prepend_size = i; pt->prepend_size = i;
if (copy_from_user(pt->buf, buffer + bytes_copied, i)) copy_from_user(pt->buf, buffer + bytes_copied, i);
return -EFAULT;
bytes_copied += i; bytes_copied += i;
DPD(3, "filling prepend buffer with %d bytes", i); DPD(3, "filling prepend buffer with %d bytes", i);
} }
......
...@@ -29,19 +29,28 @@ ...@@ -29,19 +29,28 @@
********************************************************************** **********************************************************************
*/ */
#include <asm/delay.h>
#include "8010.h" #include "8010.h"
#include "recmgr.h" #include "recmgr.h"
void emu10k1_reset_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
{
DPF(2, "emu10k1_reset_record()\n");
sblive_writeptr(card, buffer->sizereg, 0, ADCBS_BUFSIZE_NONE);
sblive_writeptr(card, buffer->sizereg, 0, buffer->sizeregval);
while (sblive_readptr(card, buffer->idxreg, 0))
udelay(5);
}
void emu10k1_start_record(struct emu10k1_card *card, struct wavein_buffer *buffer) void emu10k1_start_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
{ {
DPF(2, "emu10k1_start_record()\n"); DPF(2, "emu10k1_start_record()\n");
sblive_writeptr(card, buffer->sizereg, 0, buffer->sizeregval);
if (buffer->adcctl) if (buffer->adcctl)
sblive_writeptr(card, ADCCR, 0, buffer->adcctl); sblive_writeptr(card, ADCCR, 0, buffer->adcctl);
return;
} }
void emu10k1_stop_record(struct emu10k1_card *card, struct wavein_buffer *buffer) void emu10k1_stop_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
...@@ -51,10 +60,6 @@ void emu10k1_stop_record(struct emu10k1_card *card, struct wavein_buffer *buffer ...@@ -51,10 +60,6 @@ void emu10k1_stop_record(struct emu10k1_card *card, struct wavein_buffer *buffer
/* Disable record transfer */ /* Disable record transfer */
if (buffer->adcctl) if (buffer->adcctl)
sblive_writeptr(card, ADCCR, 0, 0); sblive_writeptr(card, ADCCR, 0, 0);
sblive_writeptr(card, buffer->sizereg, 0, ADCBS_BUFSIZE_NONE);
return;
} }
void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst) void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
...@@ -130,9 +135,7 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst) ...@@ -130,9 +135,7 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
break; break;
} }
DPD(2, "bus addx: %#x\n", buffer->dma_handle); DPD(2, "bus addx: %#lx\n", (unsigned long) buffer->dma_handle);
sblive_writeptr(card, buffer->addrreg, 0, buffer->dma_handle);
return; sblive_writeptr(card, buffer->addrreg, 0, (u32)buffer->dma_handle);
} }
...@@ -40,9 +40,9 @@ ...@@ -40,9 +40,9 @@
#define WAVERECORD_MIC 0x02 #define WAVERECORD_MIC 0x02
#define WAVERECORD_FX 0x03 #define WAVERECORD_FX 0x03
void emu10k1_reset_record(struct emu10k1_card *card, struct wavein_buffer *buffer);
void emu10k1_start_record(struct emu10k1_card *, struct wavein_buffer *); void emu10k1_start_record(struct emu10k1_card *, struct wavein_buffer *);
void emu10k1_stop_record(struct emu10k1_card *, struct wavein_buffer *); void emu10k1_stop_record(struct emu10k1_card *, struct wavein_buffer *);
void emu10k1_set_record_src(struct emu10k1_card *, struct wiinst *wiinst); void emu10k1_set_record_src(struct emu10k1_card *, struct wiinst *wiinst);
#endif /* _RECORDMGR_H */ #endif /* _RECORDMGR_H */
...@@ -59,7 +59,7 @@ void emu10k1_timer_irqhandler(struct emu10k1_card *card) ...@@ -59,7 +59,7 @@ void emu10k1_timer_irqhandler(struct emu10k1_card *card)
return; return;
} }
void emu10k1_timer_install(struct emu10k1_card *card, struct emu_timer *timer, u32 delay) void emu10k1_timer_install(struct emu10k1_card *card, struct emu_timer *timer, u16 delay)
{ {
struct emu_timer *t; struct emu_timer *t;
struct list_head *entry; struct list_head *entry;
...@@ -85,7 +85,7 @@ void emu10k1_timer_install(struct emu10k1_card *card, struct emu_timer *timer, u ...@@ -85,7 +85,7 @@ void emu10k1_timer_install(struct emu10k1_card *card, struct emu_timer *timer, u
card->timer_delay = delay; card->timer_delay = delay;
delay = (delay < 1024 ? delay : 1024); delay = (delay < 1024 ? delay : 1024);
emu10k1_writefn0(card, TIMER_RATE, delay); emu10k1_timer_set(card, delay);
list_for_each(entry, &card->timers) { list_for_each(entry, &card->timers) {
t = list_entry(entry, struct emu_timer, list); t = list_entry(entry, struct emu_timer, list);
...@@ -108,7 +108,7 @@ void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer) ...@@ -108,7 +108,7 @@ void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer)
{ {
struct emu_timer *t; struct emu_timer *t;
struct list_head *entry; struct list_head *entry;
u32 delay = TIMER_STOPPED; u16 delay = TIMER_STOPPED;
unsigned long flags; unsigned long flags;
if (timer->state == TIMER_STATE_UNINSTALLED) if (timer->state == TIMER_STATE_UNINSTALLED)
...@@ -133,7 +133,7 @@ void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer) ...@@ -133,7 +133,7 @@ void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer)
else { else {
delay = (delay < 1024 ? delay : 1024); delay = (delay < 1024 ? delay : 1024);
emu10k1_writefn0(card, TIMER_RATE, delay); emu10k1_timer_set(card, delay);
list_for_each(entry, &card->timers) { list_for_each(entry, &card->timers) {
t = list_entry(entry, struct emu_timer, list); t = list_entry(entry, struct emu_timer, list);
......
...@@ -36,17 +36,17 @@ struct emu_timer ...@@ -36,17 +36,17 @@ struct emu_timer
struct list_head list; struct list_head list;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
u8 state; u8 state;
u32 count; /* current number of interrupts */ u16 count; /* current number of interrupts */
u32 count_max; /* number of interrupts needed to schedule the bh */ u16 count_max; /* number of interrupts needed to schedule the bh */
u32 delay; /* timer delay */ u16 delay; /* timer delay */
}; };
void emu10k1_timer_install(struct emu10k1_card *, struct emu_timer *, u32); void emu10k1_timer_install(struct emu10k1_card *, struct emu_timer *, u16);
void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *); void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *);
void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *); void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *);
void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *); void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *);
#define TIMER_STOPPED 0xffffffff #define TIMER_STOPPED 0xffff
#define TIMER_STATE_INSTALLED 0x01 #define TIMER_STATE_INSTALLED 0x01
#define TIMER_STATE_ACTIVE 0x02 #define TIMER_STATE_ACTIVE 0x02
#define TIMER_STATE_UNINSTALLED 0x04 #define TIMER_STATE_UNINSTALLED 0x04
......
...@@ -32,6 +32,84 @@ ...@@ -32,6 +32,84 @@
#include "voicemgr.h" #include "voicemgr.h"
#include "8010.h" #include "8010.h"
/**
* emu10k1_voice_alloc_buffer -
*
* allocates the memory buffer for a voice. Two page tables are kept for each buffer.
* One (dma_handle) keeps track of the host memory pages used and the other (virtualpagetable)
* is passed to the device so that it can do DMA to host memory.
*
*/
int emu10k1_voice_alloc_buffer(struct emu10k1_card *card, struct voice_mem *mem, u32 pages)
{
u32 pageindex, pagecount;
u32 busaddx;
int i;
DPD(2, "requested pages is: %d\n", pages);
if ((mem->emupageindex = emu10k1_addxmgr_alloc(pages * PAGE_SIZE, card)) < 0)
{
DPF(1, "couldn't allocate emu10k1 address space\n");
return -1;
}
/* Fill in virtual memory table */
for (pagecount = 0; pagecount < pages; pagecount++) {
if ((mem->addr[pagecount] = pci_alloc_consistent(card->pci_dev, PAGE_SIZE, &mem->dma_handle[pagecount]))
== NULL) {
mem->pages = pagecount;
DPF(1, "couldn't allocate dma memory\n");
return -1;
}
DPD(2, "Virtual Addx: %p\n", mem->addr[pagecount]);
for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
busaddx = (u32) mem->dma_handle[pagecount] + i * EMUPAGESIZE;
DPD(3, "Bus Addx: %#x\n", busaddx);
pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
((u32 *) card->virtualpagetable.addr)[pageindex] = cpu_to_le32((busaddx * 2) | pageindex);
}
}
mem->pages = pagecount;
return 0;
}
/**
* emu10k1_voice_free_buffer -
*
* frees the memory buffer for a voice.
*/
void emu10k1_voice_free_buffer(struct emu10k1_card *card, struct voice_mem *mem)
{
u32 pagecount, pageindex;
int i;
if (mem->emupageindex < 0)
return;
for (pagecount = 0; pagecount < mem->pages; pagecount++) {
pci_free_consistent(card->pci_dev, PAGE_SIZE,
mem->addr[pagecount],
mem->dma_handle[pagecount]);
for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
((u32 *) card->virtualpagetable.addr)[pageindex] =
cpu_to_le32(((u32) card->silentpage.dma_handle * 2) | pageindex);
}
}
emu10k1_addxmgr_free(card, mem->emupageindex);
mem->emupageindex = -1;
}
int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice) int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice)
{ {
u8 *voicetable = card->voicetable; u8 *voicetable = card->voicetable;
...@@ -96,8 +174,10 @@ void emu10k1_voice_free(struct emu_voice *voice) ...@@ -96,8 +174,10 @@ void emu10k1_voice_free(struct emu_voice *voice)
VTFT, 0x0000ffff, VTFT, 0x0000ffff,
PTRX_PITCHTARGET, 0, PTRX_PITCHTARGET, 0,
CVCF, 0x0000ffff, CVCF, 0x0000ffff,
CPF, 0, //CPF, 0,
TAGLIST_END); TAGLIST_END);
sblive_writeptr(card, CPF, voice->num + i, 0);
} }
voice->usage = VOICE_USAGE_FREE; voice->usage = VOICE_USAGE_FREE;
...@@ -151,8 +231,8 @@ void emu10k1_voice_playback_setup(struct emu_voice *voice) ...@@ -151,8 +231,8 @@ void emu10k1_voice_playback_setup(struct emu_voice *voice)
Z1, 0, Z1, 0,
Z2, 0, Z2, 0,
/* Invalidate maps */ /* Invalidate maps */
MAPA, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), MAPA, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), MAPB, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
/* modulation envelope */ /* modulation envelope */
CVCF, 0x0000ffff, CVCF, 0x0000ffff,
VTFT, 0x0000ffff, VTFT, 0x0000ffff,
......
...@@ -64,6 +64,12 @@ struct voice_param ...@@ -64,6 +64,12 @@ struct voice_param
u32 byampl_env_decay; u32 byampl_env_decay;
}; };
struct voice_mem {
int emupageindex;
void *addr[BUFMAXPAGES];
dma_addr_t dma_handle[BUFMAXPAGES];
u32 pages;
};
struct emu_voice struct emu_voice
{ {
...@@ -72,16 +78,20 @@ struct emu_voice ...@@ -72,16 +78,20 @@ struct emu_voice
u8 num; /* Voice ID */ u8 num; /* Voice ID */
u8 flags; /* Stereo/mono, 8/16 bit */ u8 flags; /* Stereo/mono, 8/16 bit */
u32 startloop; u32 startloop;
u32 endloop; u32 endloop;
u32 start; u32 start;
u32 initial_pitch; u32 initial_pitch;
u32 pitch_target; u32 pitch_target;
struct voice_param params[2]; struct voice_param params[2];
struct voice_mem mem;
}; };
int emu10k1_voice_alloc_buffer(struct emu10k1_card *, struct voice_mem *, u32);
void emu10k1_voice_free_buffer(struct emu10k1_card *, struct voice_mem *);
int emu10k1_voice_alloc(struct emu10k1_card *, struct emu_voice *); int emu10k1_voice_alloc(struct emu10k1_card *, struct emu_voice *);
void emu10k1_voice_free(struct emu_voice *); void emu10k1_voice_free(struct emu_voice *);
void emu10k1_voice_playback_setup(struct emu_voice *); void emu10k1_voice_playback_setup(struct emu_voice *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment