Commit 74521715 authored by Jaroslav Kysela's avatar Jaroslav Kysela

Merge suse.cz:/home/perex/bk/linux-sound/linux-sound

into suse.cz:/home/perex/bk/linux-sound/work
parents d99c48c6 c3c8a7e8
......@@ -207,7 +207,7 @@ MIDI CONTROLLER
---------------
The MPU401-UART interface is enabled as default only for the first
(CMIPCI) card. You need to set module option "snd_midi_port" properly
(CMIPCI) card. You need to set module option "midi_port" properly
for the 2nd (CMIPCI) card.
There is _no_ hardware wavetable function on this chip (except for
......@@ -221,7 +221,7 @@ FM OPL/3 Synth
--------------
The FM OPL/3 is also enabled as default only for the first card.
Set "snd_fm_port" module option for more cards.
Set "fm_port" module option for more cards.
The output quality of FM OPL/3 is, however, very weird.
I don't know why..
......
......@@ -1377,6 +1377,8 @@
module_init(alsa_card_mychip_init)
module_exit(alsa_card_mychip_exit)
EXPORT_NO_SYMBOLS; /* for old kernels only */
]]>
</programlisting>
</example>
......@@ -2758,6 +2760,17 @@
</para>
</section>
<section id="pcm-interface-operators-ack">
<title>ack callback</title>
<para>
This callback is also not mandatory. This callback is called
when the appl_ptr is updated in read or write operations.
Some drivers like emu10k1-fx and cs46xx need to track the
current appl_ptr for the internal buffer, and this callback
is useful only for such a purpose.
</para>
</section>
<section id="pcm-interface-operators-page-callback">
<title>page callback</title>
......
......@@ -2,7 +2,7 @@
Serial UART 16450/16550 MIDI driver
===================================
The snd_adaptor module parameter allows you to select either:
The adaptor module parameter allows you to select either:
0 - Roland Soundcanvas support (default)
1 - Midiator MS-124T support (1)
......@@ -24,37 +24,35 @@ send the F5 NN command sequence at all; perhaps it ought to.
Usage example for simple serial converter:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
snd_speed=115200
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 speed=115200
Usage example for Roland SoundCanvas with 4 MIDI ports:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 snd_outs=4
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 outs=4
In MS-124T mode, one raw MIDI substream is supported (midiCnD0); the snd_outs
In MS-124T mode, one raw MIDI substream is supported (midiCnD0); the outs
module parameter is automatically set to 1. The driver sends the same data to
all four MIDI Out connectors. Set the A-B switch and the snd_speed module
all four MIDI Out connectors. Set the A-B switch and the speed module
parameter to match (A=19200, B=9600).
Usage example for MS-124T, with A-B switch in A position:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
snd_adaptor=1 snd_speed=19200
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=1 \
speed=19200
In MS-124W S/A mode, one raw MIDI substream is supported (midiCnD0);
the snd_outs module parameter is automatically set to 1. The driver sends
the outs module parameter is automatically set to 1. The driver sends
the same data to all four MIDI Out connectors at full MIDI speed.
Usage example for S/A mode:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
snd_adaptor=2
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=2
In MS-124W M/B mode, the driver supports 16 ALSA raw MIDI substreams;
the snd_outs module parameter is automatically set to 16. The substream
the outs module parameter is automatically set to 16. The substream
number gives a bitmask of which MIDI Out connectors the data should be
sent to, with midiCnD1 sending to Out 1, midiCnD2 to Out 2, midiCnD4 to
Out 3, and midiCnD8 to Out 4. Thus midiCnD15 sends the data to all 4 ports.
......@@ -67,8 +65,7 @@ one byte every 320 us per port.
Usage example for M/B mode:
/sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
snd_adaptor=3
/sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=3
The MS-124W hardware's M/A mode is currently not supported. This mode allows
the MIDI Outs to act independently at double the aggregate throughput of M/B,
......@@ -88,4 +85,4 @@ The Generic driver supports multiple input and output substreams over a single
serial port. Similar to Roland Soundcanvas mode, F5 NN is used to select the
appropriate input or output stream (depending on the data direction).
Additionally, the CTS signal is used to regulate the data flow. The number of
inputs is specified by the snd_ins parameter.
inputs is specified by the ins parameter.
......@@ -268,6 +268,14 @@ struct _snd_ac97 {
};
/* conditions */
static inline int ac97_is_audio(ac97_t * ac97)
{
return (ac97->scaps & AC97_SCAP_AUDIO);
}
static inline int ac97_is_modem(ac97_t * ac97)
{
return (ac97->scaps & AC97_SCAP_MODEM);
}
static inline int ac97_is_rev22(ac97_t * ac97)
{
return (ac97->ext_id & AC97_EI_REV_MASK) == AC97_EI_REV_22;
......@@ -278,7 +286,8 @@ static inline int ac97_can_amap(ac97_t * ac97)
}
/* functions */
int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97);
int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97); /* create mixer controls */
int snd_ac97_modem(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97); /* create modem controls */
void snd_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short value);
unsigned short snd_ac97_read(ac97_t *ac97, unsigned short reg);
......@@ -296,6 +305,7 @@ enum { AC97_TUNE_HP_ONLY, AC97_TUNE_SWAP_HP };
struct ac97_quirk {
unsigned short vendor;
unsigned short device;
const char *name;
int type;
};
......
......@@ -93,7 +93,7 @@ struct sndrv_aes_iec958 {
* *
****************************************************************************/
#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 0)
#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1)
enum sndrv_hwdep_iface {
SNDRV_HWDEP_IFACE_OPL2 = 0,
......@@ -104,9 +104,10 @@ enum sndrv_hwdep_iface {
SNDRV_HWDEP_IFACE_YSS225, /* Yamaha FX processor */
SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */
SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */
SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */
/* Don't forget to change the following: */
SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_SSCAPE,
SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_VX,
};
struct sndrv_hwdep_info {
......@@ -118,9 +119,29 @@ struct sndrv_hwdep_info {
unsigned char reserved[64]; /* reserved for future */
};
/* generic DSP loader */
struct sndrv_hwdep_dsp_status {
unsigned int version; /* R: driver-specific version */
unsigned char id[32]; /* R: driver-specific ID string */
unsigned int num_dsps; /* R: number of DSP images to transfer */
unsigned int dsp_loaded; /* R: bit flags indicating the loaded DSPs */
unsigned int chip_ready; /* R: 1 = initialization finished */
unsigned char reserved[16]; /* reserved for future use */
};
struct sndrv_hwdep_dsp_image {
unsigned int index; /* W: DSP index */
unsigned char name[64]; /* W: ID (e.g. file name) */
unsigned char *image; /* W: binary image */
size_t length; /* W: size of image in bytes */
unsigned long driver_data; /* W: driver-specific data */
};
enum {
SNDRV_HWDEP_IOCTL_PVERSION = _IOR ('H', 0x00, int),
SNDRV_HWDEP_IOCTL_INFO = _IOR ('H', 0x01, struct sndrv_hwdep_info),
SNDRV_HWDEP_IOCTL_DSP_STATUS = _IOR('H', 0x02, struct sndrv_hwdep_dsp_status),
SNDRV_HWDEP_IOCTL_DSP_LOAD = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image)
};
/*****************************************************************************
......@@ -129,7 +150,7 @@ enum {
* *
*****************************************************************************/
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 3)
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 4)
typedef unsigned long sndrv_pcm_uframes_t;
typedef long sndrv_pcm_sframes_t;
......@@ -434,6 +455,7 @@ enum {
SNDRV_PCM_IOCTL_REWIND = _IOW('A', 0x46, sndrv_pcm_uframes_t),
SNDRV_PCM_IOCTL_RESUME = _IO('A', 0x47),
SNDRV_PCM_IOCTL_XRUN = _IO('A', 0x48),
SNDRV_PCM_IOCTL_FORWARD = _IOW('A', 0x49, sndrv_pcm_uframes_t),
SNDRV_PCM_IOCTL_WRITEI_FRAMES = _IOW('A', 0x50, struct sndrv_xferi),
SNDRV_PCM_IOCTL_READI_FRAMES = _IOR('A', 0x51, struct sndrv_xferi),
SNDRV_PCM_IOCTL_WRITEN_FRAMES = _IOW('A', 0x52, struct sndrv_xfern),
......
......@@ -27,6 +27,8 @@
typedef enum sndrv_hwdep_iface snd_hwdep_iface_t;
typedef struct sndrv_hwdep_info snd_hwdep_info_t;
typedef struct sndrv_hwdep_dsp_status snd_hwdep_dsp_status_t;
typedef struct sndrv_hwdep_dsp_image snd_hwdep_dsp_image_t;
typedef struct _snd_hwdep_ops {
long long (*llseek) (snd_hwdep_t *hw, struct file * file, long long offset, int orig);
......@@ -37,6 +39,8 @@ typedef struct _snd_hwdep_ops {
unsigned int (*poll) (snd_hwdep_t * hw, struct file * file, poll_table * wait);
int (*ioctl) (snd_hwdep_t * hw, struct file * file, unsigned int cmd, unsigned long arg);
int (*mmap) (snd_hwdep_t * hw, struct file * file, struct vm_area_struct * vma);
int (*dsp_status) (snd_hwdep_t * hw, snd_hwdep_dsp_status_t * status);
int (*dsp_load) (snd_hwdep_t * hw, snd_hwdep_dsp_image_t * image);
} snd_hwdep_ops_t;
struct _snd_hwdep {
......@@ -56,6 +60,11 @@ struct _snd_hwdep {
wait_queue_head_t open_wait;
void *private_data;
void (*private_free) (snd_hwdep_t *hwdep);
struct semaphore open_mutex;
int used;
unsigned int dsp_loaded;
unsigned int exclusive: 1;
};
extern int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep);
......
......@@ -67,7 +67,7 @@ static const char __module_generic_string_##name [] \
#define SNDRV_BOOLEAN_TRUE_DESC "allows:{{0,Disabled},{1,Enabled}},default:1,dialog:check"
#define SNDRV_BOOLEAN_FALSE_DESC "allows:{{0,Disabled},{1,Enabled}},default:0,dialog:check"
#define SNDRV_ENABLED "enable:(snd_enable)"
#define SNDRV_ENABLED "enable:(enable)"
#define SNDRV_INDEX_DESC SNDRV_ENABLED ",allows:{{0,7}},unique,skill:required,dialog:list"
#define SNDRV_ID_DESC SNDRV_ENABLED ",unique"
......
......@@ -97,6 +97,7 @@ typedef struct _snd_pcm_ops {
int (*silence)(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
int (*ack)(snd_pcm_substream_t *substream);
} snd_pcm_ops_t;
/*
......
......@@ -15,10 +15,15 @@
* features support
*/
/* $Id: uda1341.h,v 1.2 2002/04/17 07:53:22 perex Exp $ */
/* $Id: uda1341.h,v 1.4 2003/02/25 12:48:16 perex Exp $ */
#define UDA1341_ALSA_NAME "snd-uda1341"
/*
* Default rate set after inicialization
*/
#define AUDIO_RATE_DEFAULT 44100
/*
* UDA1341 L3 address and command types
*/
......
/* include/version.h. Generated by configure. */
#define CONFIG_SND_VERSION "0.9.0rc7"
#define CONFIG_SND_DATE " (Sat Feb 15 15:01:21 2003 UTC)"
#define CONFIG_SND_DATE " (Tue Feb 25 13:00:09 2003 UTC)"
......@@ -13,9 +13,48 @@
* 2002-03-29 Tomas Kasparek basic capture is working (native ALSA)
* 2002-03-29 Tomas Kasparek capture is working (OSS emulation)
* 2002-04-04 Tomas Kasparek better rates handling (allow non-standard rates)
* 2003-02-14 Brian Avery fixed full duplex mode, other updates
* 2003-02-20 Tomas Kasparek merged updates by Brian (except HAL)
*/
/* $Id: sa11xx-uda1341.c,v 1.7 2003/02/13 19:19:18 perex Exp $ */
/* $Id: sa11xx-uda1341.c,v 1.8 2003/02/25 12:48:15 perex Exp $ */
/***************************************************************************************************
*
* To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai
* available in the Alsa doc section on the website
*
* A few notes to make things clearer. The UDA1341 is hooked up to Serial port 4 on the SA1100.
* We are using SSP mode to talk to the UDA1341. The UDA1341 bit & wordselect clocks are generated
* by this UART. Unfortunately, the clock only runs if the transmit buffer has something in it.
* So, if we are just recording, we feed the transmit DMA stream a bunch of 0x0000 so that the
* transmit buffer is full and the clock keeps going. The zeroes come from FLUSH_BASE_PHYS which
* is a mem loc that always decodes to 0's w/ no off chip access.
*
* Some alsa terminology:
* frame => num_channels * sample_size e.g stereo 16 bit is 2 * 16 = 32 bytes
* period => the least number of bytes that will generate an interrupt e.g. we have a 1024 byte
* buffer and 4 periods in the runtime structure this means we'll get an int every 256
* bytes or 4 times per buffer.
* A number of the sizes are in frames rather than bytes, use frames_to_bytes and
* bytes_to_frames to convert. The easiest way to tell the units is to look at the
* type i.e. runtime-> buffer_size is in frames and its type is snd_pcm_uframes_t
*
* Notes about the pointer fxn:
* The pointer fxn needs to return the offset into the dma buffer in frames.
* Interrupts must be blocked before calling the dma_get_pos fxn to avoid race with interrupts.
*
* Notes about pause/resume
* Implementing this would be complicated so it's skipped. The problem case is:
* A full duplex connection is going, then play is paused. At this point you need to start xmitting
* 0's to keep the record active which means you cant just freeze the dma and resume it later you'd
* need to save off the dma info, and restore it properly on a resume. Yeach!
*
* Notes about transfer methods:
* The async write calls fail. I probably need to implement something else to support them?
*
***************************************************************************************************/
#include <sound/driver.h>
#include <linux/module.h>
......@@ -53,8 +92,6 @@ MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");
#define chip_t sa11xx_uda1341_t
#define SHIFT_16_STEREO 2
typedef enum stream_id_t{
PLAYBACK=0,
CAPTURE,
......@@ -62,32 +99,29 @@ typedef enum stream_id_t{
}stream_id_t;
typedef struct audio_stream {
char *id; /* identification string */
char *id; /* identification string */
int stream_id; /* numeric identification */
dma_device_t dma_dev; /* device identifier for DMA */
dma_regs_t *dma_regs; /* points to our DMA registers */
int active:1; /* we are using this stream for transfer now */
int active:1; /* we are using this stream for transfer now */
int sent_periods; /* # of sent periods from actual DMA buffer */
int sent_total; /* # of sent periods total (just for info & debug) */
int sync; /* are we recoding - flag used to do DMA trans. for sync */
spinlock_t dma_lock; /* for locking in DMA operations (see dma-sa1100.c in the kernel) */
snd_pcm_substream_t *stream;
}audio_stream_t;
/* I do not want to have substream = NULL when syncing - ALSA does not like it */
#define SYNC_SUBSTREAM ((void *) -1)
typedef struct snd_card_sa11xx_uda1341 {
struct pm_dev *pm_dev;
snd_card_t *card;
struct l3_client *uda1341;
long samplerate;
audio_stream_t *s[MAX_STREAMS];
snd_info_entry_t *proc_entry;
}sa11xx_uda1341_t;
static struct snd_card_sa11xx_uda1341 *sa11xx_uda1341 = NULL;
......@@ -217,7 +251,9 @@ static void sa11xx_uda1341_set_samplerate(sa11xx_uda1341_t *sa11xx_uda1341, long
break;
}
/* FMT setting should be moved away when other FMTs are added (FIXME) */
l3_command(sa11xx_uda1341->uda1341, CMD_FORMAT, (void *)LSB16);
l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk);
Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
DEBUG(KERN_DEBUG "set_samplerate done (new rate: %ld)\n", rate);
......@@ -237,11 +273,13 @@ static void sa11xx_uda1341_audio_init(sa11xx_uda1341_t *sa11xx_uda1341)
/* Setup DMA stuff */
if (sa11xx_uda1341->s[PLAYBACK]) {
sa11xx_uda1341->s[PLAYBACK]->id = "UDA1341 out";
sa11xx_uda1341->s[PLAYBACK]->stream_id = PLAYBACK;
sa11xx_uda1341->s[PLAYBACK]->dma_dev = DMA_Ser4SSPWr;
}
if (sa11xx_uda1341->s[CAPTURE]) {
sa11xx_uda1341->s[CAPTURE]->id = "UDA1341 in";
sa11xx_uda1341->s[CAPTURE]->stream_id = CAPTURE;
sa11xx_uda1341->s[CAPTURE]->dma_dev = DMA_Ser4SSPRd;
}
......@@ -255,22 +293,24 @@ static void sa11xx_uda1341_audio_init(sa11xx_uda1341_t *sa11xx_uda1341)
Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8);
Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
Ser4SSCR0 |= SSCR0_SSE;
local_irq_restore(flags);
/* Enable the audio power */
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
local_irq_restore(flags);
/* Initialize the UDA1341 internal state */
l3_open(sa11xx_uda1341->uda1341);
/* external clock configuration */
sa11xx_uda1341_set_samplerate(sa11xx_uda1341, 44100); /* default sample rate */
/* external clock configuration (after l3_open - regs must be
* initialized */
sa11xx_uda1341_set_samplerate(sa11xx_uda1341, AUDIO_RATE_DEFAULT);
/* Wait for the UDA1341 to wake up */
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
mdelay(1);
/* make the left and right channels unswapped (flip the WS latch ) */
Ser4SSDR = 0;
......@@ -280,11 +320,16 @@ static void sa11xx_uda1341_audio_init(sa11xx_uda1341_t *sa11xx_uda1341)
static void sa11xx_uda1341_audio_shutdown(sa11xx_uda1341_t *sa11xx_uda1341)
{
/* mute on */
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
/* disable the audio power and all signals leading to the audio chip */
l3_close(sa11xx_uda1341->uda1341);
Ser4SSCR0 = 0;
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
/* power off */
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
/* mute off */
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
}
......@@ -292,26 +337,29 @@ static void sa11xx_uda1341_audio_shutdown(sa11xx_uda1341_t *sa11xx_uda1341)
/* {{{ DMA staff */
#define SYNC_ADDR (dma_addr_t)FLUSH_BASE_PHYS
#define SYNC_SIZE 4096 // was 2048
#define DMA_REQUEST(s, cb) sa1100_request_dma((s)->dma_dev, (s)->id, cb, s, \
&((s)->dma_regs))
#define DMA_FREE(s) {sa1100_free_dma((s)->dma_regs); (s)->dma_regs = 0;}
#define DMA_START(s, d, l) sa1100_start_dma((s)->dma_regs, d, l)
#define DMA_STOP(s) sa1100_stop_dma((s)->dma_regs)
#define DMA_CLEAR(s) sa1100_clear_dma((s)->dma_regs)
#define DMA_RESET(s) sa1100_reset_dma((s)->dma_regs)
#define DMA_POS(s) sa1100_get_dma_pos((s)->dma_regs)
/*
* these are the address and sizes used to fill the xmit buffer
* so we can get a clock in record only mode
*/
#define FORCE_CLOCK_ADDR (dma_addr_t)FLUSH_BASE_PHYS
#define FORCE_CLOCK_SIZE 4096 // was 2048
static void audio_dma_request(audio_stream_t *s, void (*callback)(void *))
{
DMA_REQUEST(s, callback);
int ret;
DEBUG_NAME(KERN_DEBUG "audio_dma_request");
DEBUG("\t request id <%s>\n", s->id);
DEBUG("\t request dma_dev = 0x%x \n", s->dma_dev);
ret = sa1100_request_dma((s)->dma_dev, (s)->id, callback, s, &((s)->dma_regs));
DEBUG("\t request ret = %d\n", ret);
}
static void audio_dma_free(audio_stream_t *s)
{
DMA_FREE(s);
sa1100_free_dma((s)->dma_regs);
(s)->dma_regs = 0;
}
static u_int audio_get_dma_pos(audio_stream_t *s)
......@@ -319,12 +367,17 @@ static u_int audio_get_dma_pos(audio_stream_t *s)
snd_pcm_substream_t * substream = s->stream;
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned int offset;
unsigned long flags;
DEBUG_NAME(KERN_DEBUG "get_dma_pos");
offset = DMA_POS(s) - substream->runtime->dma_addr;
// this must be called w/ interrupts locked out see dma-sa1100.c in the kernel
spin_lock_irqsave(&s->dma_lock, flags);
offset = sa1100_get_dma_pos((s)->dma_regs) - runtime->dma_addr;
spin_unlock_irqrestore(&s->dma_lock, flags);
DEBUG(" %d ->", offset);
offset >>= SHIFT_16_STEREO;
offset = bytes_to_frames(runtime,offset);
DEBUG(" %d [fr]\n", offset);
if (offset >= runtime->buffer_size){
......@@ -339,27 +392,33 @@ static u_int audio_get_dma_pos(audio_stream_t *s)
return offset;
}
/*
* this stops the dma and clears the dma ptrs
*/
static void audio_stop_dma(audio_stream_t *s)
{
long flags;
DEBUG_NAME(KERN_DEBUG "stop_dma\n");
if (!s->stream)
/*
* zero filling streams (sync=1) don;t have alsa streams attached
* but the 0 fill dma xfer still needs to be stopped
*/
if (!(s->stream || s->sync))
return;
local_irq_save(flags);
spin_lock_irqsave(&(s->dma_lock), flags);
s->active = 0;
s->sent_periods = 0;
s->sent_total = 0;
s->sent_total = 0;
s->sync = 0;
DMA_STOP(s);
DMA_CLEAR(s);
local_irq_restore(flags);
/* this stops the dma channel and clears the buffer ptrs */
sa1100_clear_dma((s)->dma_regs);
spin_unlock_irqrestore(&(s->dma_lock), flags);
}
static void audio_reset(audio_stream_t *s)
{
DEBUG_NAME(KERN_DEBUG "dma_reset\n");
......@@ -375,40 +434,58 @@ static void audio_process_dma(audio_stream_t *s)
{
snd_pcm_substream_t * substream = s->stream;
snd_pcm_runtime_t *runtime;
int ret,i;
int ret;
DEBUG_NAME(KERN_DEBUG "process_dma\n");
if(!s->active){
DEBUG("!!!want to process DMA when stopped!!!\n");
return;
}
/* we are requested to process synchronization DMA transfer */
if (s->sync) {
if(!s->active && s->sync){
snd_assert(s->stream_id == PLAYBACK,return);
/* fill the xmit dma buffers and return */
while (1) {
DEBUG(KERN_DEBUG "sent sync period (dma_size[B]: %d)\n", SYNC_SIZE);
ret = DMA_START(s, SYNC_ADDR, SYNC_SIZE);
DEBUG(KERN_DEBUG "sent zero dma period (dma_size[B]: %d)\n", FORCE_CLOCK_SIZE);
ret = sa1100_start_dma((s)->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
if (ret)
return;
}
}
/* must be set here - for sync there is no runtime struct */
/* must be set here - only valid for running streams, not for forced_clock dma fills */
runtime = substream->runtime;
while(1) {
unsigned int dma_size = runtime->period_size << SHIFT_16_STEREO;
unsigned int offset = dma_size * s->sent_periods;
DEBUG("audio_process_dma hw_ptr_base = 0x%x w_ptr_interrupt = 0x%x "
"period_size = %d periods = %d buffer_size = %d sync=0x%x dma_area = 0x%x\n",
runtime->hw_ptr_base,
runtime->hw_ptr_interrupt,
runtime->period_size,
runtime->periods,
runtime->buffer_size,
runtime->sync,
runtime->dma_area);
DEBUG("audio_process_dma sent_total = %d sent_period = %d\n",
s->sent_total,
s->sent_periods);
while(s->active) {
unsigned int dma_size;
unsigned int offset ;
dma_size = frames_to_bytes(runtime,runtime->period_size) ;
offset = dma_size * s->sent_periods;
if (dma_size > MAX_DMA_SIZE){
/* this should not happen! */
DEBUG(KERN_DEBUG "-----> cut dma_size: %d -> ", dma_size);
printk(KERN_ERR "---> cut dma_size: %d -> ", dma_size);
dma_size = CUT_DMA_SIZE;
DEBUG("%d <-----\n", dma_size);
printk("%d <---\n", dma_size);
}
ret = DMA_START(s, runtime->dma_addr + offset, dma_size);
/*
* the first time this while loop will run 3 times, i.e. it'll fill the 2 dma
* buffers then get a -EBUSY, every other time it'll refill the completed buffer
* and then get the -EBUSY so it'll just run twice
*/
ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size);
if (ret)
return;
......@@ -429,7 +506,6 @@ static void audio_process_dma(audio_stream_t *s)
}
}
static void audio_dma_callback(void *data)
{
audio_stream_t *s = data;
......@@ -438,24 +514,26 @@ static void audio_dma_callback(void *data)
DEBUG_NAME(KERN_DEBUG "dma_callback\n");
/* when syncing we do not have any real stream from ALSA! */
if (!s->sync) {
snd_pcm_period_elapsed(s->stream);
DEBUG(KERN_DEBUG "----> period done <----\n");
DEBUG(KERN_DEBUG "----> period done <----\n");
#ifdef DEBUG_MODE
printk(KERN_DEBUG " dma_area:");
buf = (char *)s->stream->runtime->dma_addr +
((s->sent_periods - 1 ) *
(s->stream->runtime->period_size << SHIFT_16_STEREO));
for (i=0; i < 32; i++) {
printk(" %02x", *(char *)(buf + i));
}
printk("\n");
#endif
printk(KERN_DEBUG " dma_area:");
buf = (char *)s->stream->runtime->dma_addr + ((s->sent_periods - 1 ) *
frames_to_bytes( s->stream->runtime, s->stream->runtime->period_size));
for (i=0; i < 32; i++) {
printk(" %02x", *(char *)(buf + i));
}
printk("\n");
#endif
if (s->active)
audio_process_dma(s);
/*
* If we are getting a callback for an active stream then we inform
* the PCM middle layer we've finished a period
*/
if (s->active)
snd_pcm_period_elapsed(s->stream);
audio_process_dma(s);
}
/* }}} */
......@@ -491,18 +569,21 @@ static int snd_card_sa11xx_uda1341_pcm_trigger(stream_id_t stream_id,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
/* want to capture and have no playback - run DMA syncing */
/* now we need to make sure a record only stream has a clock */
if (stream_id == CAPTURE && !chip->s[PLAYBACK]->active) {
/* we need synchronization DMA transfer (zeros) */
DEBUG(KERN_DEBUG "starting synchronization DMA transfer\n");
/* we need to force fill the xmit DMA with zeros */
DEBUG(KERN_DEBUG "starting zero fill DMA transfer\n");
chip->s[PLAYBACK]->sync = 1;
chip->s[PLAYBACK]->active = 1;
chip->s[PLAYBACK]->stream = SYNC_SUBSTREAM; /* not really used! */
audio_process_dma(chip->s[PLAYBACK]);
}
/* want to playback and have capture - stop syncing */
if(stream_id == PLAYBACK && chip->s[PLAYBACK]->sync) {
chip->s[PLAYBACK]->sync = 0;
/* this case is when you were recording then you turn on a
* playback stream so we
* stop (also clears it) the dma first, clear the sync flag
* and then we let it get turned on
*/
else if (stream_id == PLAYBACK && chip->s[PLAYBACK]->sync) {
chip->s[PLAYBACK]->sync = 0;
audio_stop_dma(chip->s[PLAYBACK]);
}
/* requested stream startup */
......@@ -512,27 +593,30 @@ static int snd_card_sa11xx_uda1341_pcm_trigger(stream_id_t stream_id,
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/* want to stop capture and use syncing - stop DMA syncing */
if (stream_id == CAPTURE && chip->s[PLAYBACK]->sync) {
/* we do not need synchronization DMA transfer now */
DEBUG(KERN_DEBUG "stopping synchronization DMA transfer\n");
chip->s[PLAYBACK]->sync = 0;
chip->s[PLAYBACK]->active = 0;
audio_stop_dma(chip->s[PLAYBACK]);
}
/* want to stop playback and have capture - run DMA syncing */
if(stream_id == PLAYBACK && chip->s[CAPTURE]->active) {
/* we need synchronization DMA transfer (zeros) */
DEBUG(KERN_DEBUG "starting synchronization DMA transfer\n");
chip->s[PLAYBACK]->sync = 1;
chip->s[PLAYBACK]->active = 1;
chip->s[PLAYBACK]->stream = SYNC_SUBSTREAM; /* not really used! */
audio_process_dma(chip->s[PLAYBACK]);
}
/* requested stream shutdown */
chip->s[stream_id]->active = 0;
audio_stop_dma(chip->s[stream_id]);
/*
* now we need to make sure a record only stream has a clock
* so if we're stopping a playback with an active capture
* we need to turn the 0 fill dma on for the xmit side
*/
if (stream_id == PLAYBACK && chip->s[CAPTURE]->active) {
/* we need to force fill the xmit DMA with zeros */
DEBUG(KERN_DEBUG "starting zero fill DMA transfer\n");
chip->s[PLAYBACK]->sync = 1;
chip->s[PLAYBACK]->active = 0;
audio_process_dma(chip->s[PLAYBACK]);
}
/*
* we killed a capture only stream, so we should also kill
* the zero fill transmit
*/
else if (stream_id == CAPTURE && chip->s[PLAYBACK]->sync) {
audio_stop_dma(chip->s[PLAYBACK]);
}
break;
default:
return -EINVAL;
......@@ -601,7 +685,11 @@ static int snd_card_sa11xx_uda1341_playback_open(snd_pcm_substream_t * substream
chip->s[PLAYBACK]->sent_periods = 0;
chip->s[PLAYBACK]->sent_total = 0;
audio_reset(chip->s[PLAYBACK]);
/* no reset here since we may be zero filling the DMA
* if we are, the dma stream will get reset in the pcm_trigger
* i.e. when it actually starts to play
*/
/* audio_reset(chip->s[PLAYBACK]); */
runtime->hw = snd_sa11xx_uda1341_playback;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
......@@ -652,10 +740,13 @@ static int snd_card_sa11xx_uda1341_playback_trigger(snd_pcm_substream_t * substr
static snd_pcm_uframes_t snd_card_sa11xx_uda1341_playback_pointer(snd_pcm_substream_t * substream)
{
snd_pcm_uframes_t pos;
sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream);
DEBUG_NAME(KERN_DEBUG "playback_pointer\n");
return audio_get_dma_pos(chip->s[PLAYBACK]);
pos = audio_get_dma_pos(chip->s[PLAYBACK]);
return pos;
}
/* }}} */
......@@ -674,7 +765,7 @@ static int snd_card_sa11xx_uda1341_capture_open(snd_pcm_substream_t * substream)
chip->s[CAPTURE]->sent_periods = 0;
chip->s[CAPTURE]->sent_total = 0;
audio_reset(chip->s[PLAYBACK]);
audio_reset(chip->s[CAPTURE]);
runtime->hw = snd_sa11xx_uda1341_capture;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
......@@ -725,10 +816,12 @@ static int snd_card_sa11xx_uda1341_capture_trigger(snd_pcm_substream_t * substre
static snd_pcm_uframes_t snd_card_sa11xx_uda1341_capture_pointer(snd_pcm_substream_t * substream)
{
snd_pcm_uframes_t pos;
sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream);
DEBUG_NAME(KERN_DEBUG "record_pointer\n");
return audio_get_dma_pos(chip->s[CAPTURE]);
pos = audio_get_dma_pos(chip->s[CAPTURE]);
return pos;
}
/* }}} */
......@@ -784,6 +877,13 @@ static int __init snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341_t *sa11xx_uda1341,
substreams, substreams, &pcm)) < 0)
return err;
/*
* this sets up our initial buffers and sets the dma_type to isa.
* isa works but I'm not sure why (or if) it's the right choice
* this may be too large, trying it for now
*/
snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 64*1024);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);
pcm->private_data = sa11xx_uda1341;
......@@ -816,6 +916,10 @@ static int sa11xx_uda1341_pm_callback(struct pm_dev *pm_dev, pm_request_t req, v
DEBUG_NAME(KERN_DEBUG "pm_callback\n");
/* pause resume is broken see note */
printk("Pause/Resume support currently broken... \n");
return -1;
is = sa11xx_uda1341->s[PLAYBACK];
os = sa11xx_uda1341->s[CAPTURE];
......
......@@ -107,7 +107,12 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
#endif
init_waitqueue_entry(&wait, current);
add_wait_queue(&hw->open_wait, &wait);
down(&hw->open_mutex);
while (1) {
if (hw->exclusive && hw->used > 0) {
err = -EBUSY;
break;
}
err = hw->ops.open(hw, file);
if (err >= 0)
break;
......@@ -127,20 +132,26 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&hw->open_wait, &wait);
if (err >= 0)
if (err >= 0) {
file->private_data = hw;
hw->used++;
}
up(&hw->open_mutex);
return err;
}
static int snd_hwdep_release(struct inode *inode, struct file * file)
{
int err;
int err = -ENXIO;
snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO);
down(&hw->open_mutex);
if (hw->ops.release) {
err = hw->ops.release(hw, file);
wake_up(&hw->open_wait);
return err;
}
if (hw->used > 0)
hw->used--;
up(&hw->open_mutex);
return -ENXIO;
}
......@@ -166,14 +177,58 @@ static int snd_hwdep_info(snd_hwdep_t *hw, snd_hwdep_info_t *_info)
return 0;
}
static int snd_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *_info)
{
snd_hwdep_dsp_status_t info;
int err;
if (! hw->ops.dsp_status)
return -ENXIO;
memset(&info, 0, sizeof(info));
info.dsp_loaded = hw->dsp_loaded;
if ((err = hw->ops.dsp_status(hw, &info)) < 0)
return err;
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
return 0;
}
static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *_info)
{
snd_hwdep_dsp_image_t info;
int err;
if (! hw->ops.dsp_load || ! hw->ops.dsp_status)
return -ENXIO;
memset(&info, 0, sizeof(info));
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
/* check whether the dsp was already loaded */
if (hw->dsp_loaded & (1 << info.index))
return -EBUSY;
if (verify_area(VERIFY_READ, info.image, info.length))
return -EFAULT;
err = hw->ops.dsp_load(hw, &info);
if (err < 0)
return err;
hw->dsp_loaded |= (1 << info.index);
return 0;
}
static int snd_hwdep_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO);
if (cmd == SNDRV_HWDEP_IOCTL_PVERSION)
switch (cmd) {
case SNDRV_HWDEP_IOCTL_PVERSION:
return put_user(SNDRV_HWDEP_VERSION, (int *)arg);
if (cmd == SNDRV_HWDEP_IOCTL_INFO)
case SNDRV_HWDEP_IOCTL_INFO:
return snd_hwdep_info(hw, (snd_hwdep_info_t *)arg);
case SNDRV_HWDEP_IOCTL_DSP_STATUS:
return snd_hwdep_dsp_status(hw, (snd_hwdep_dsp_status_t *)arg);
case SNDRV_HWDEP_IOCTL_DSP_LOAD:
return snd_hwdep_dsp_load(hw, (snd_hwdep_dsp_image_t *)arg);
}
if (hw->ops.ioctl)
return hw->ops.ioctl(hw, file, cmd, arg);
return -ENOTTY;
......@@ -298,6 +353,7 @@ int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep
return err;
}
init_waitqueue_head(&hwdep->open_wait);
init_MUTEX(&hwdep->open_mutex);
*rhwdep = hwdep;
return 0;
}
......
......@@ -20,13 +20,52 @@
#include <sound/driver.h>
#include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <sound/hwdep.h>
#include <asm/uaccess.h>
#include "ioctl32.h"
struct sndrv_hwdep_dsp_image32 {
u32 index;
unsigned char name[64];
u32 image; /* pointer */
u32 length;
} /* don't set packed attribute here */;
static int _snd_ioctl32_hwdep_dsp_image(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
{
struct sndrv_hwdep_dsp_image data;
struct sndrv_hwdep_dsp_image data32;
mm_segment_t oldseg;
int err;
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
return -EFAULT;
memset(&data, 0, sizeof(data));
data.index = data32.index;
memcpy(data.name, data32.name, sizeof(data.name));
data.image = A(data32.image);
data.length = data32.length;
oldseg = get_fs();
set_fs(KERNEL_DS);
err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
set_fs(oldseg);
return err;
}
DEFINE_ALSA_IOCTL_ENTRY(hwdep_dsp_image, hwdep_dsp_image, SNDRV_HWDEP_IOCTL_DSP_LOAD);
#define AP(x) snd_ioctl32_##x
enum {
SNDRV_HWDEP_IOCTL_DSP_LOAD32 = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
};
struct ioctl32_mapper hwdep_mappers[] = {
{ SNDRV_HWDEP_IOCTL_PVERSION, NULL },
{ SNDRV_HWDEP_IOCTL_INFO, NULL },
MAP_COMPAT(SNDRV_HWDEP_IOCTL_PVERSION),
MAP_COMPAT(SNDRV_HWDEP_IOCTL_INFO),
MAP_COMPAT(SNDRV_HWDEP_IOCTL_DSP_STATUS),
{ SNDRV_HWDEP_IOCTL_DSP_LOAD32, AP(hwdep_dsp_image) },
{ 0 },
};
......@@ -77,27 +77,6 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
va_end(args);
tmpbuf[sizeof(tmpbuf)-1] = '\0';
printk(tmpbuf);
}
#endif
#if defined(CONFIG_SND_DEBUG) && !defined(CONFIG_SND_VERBOSE_PRINTK)
void snd_printd(const char *format, ...)
{
va_list args;
char tmpbuf[512];
if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
char tmp[] = "<0>";
tmp[1] = format[1];
printk("%sALSA: ", tmp);
format += 3;
} else {
printk(KERN_DEBUG "ALSA: ");
}
va_start(args, format);
vsnprintf(tmpbuf, sizeof(tmpbuf)-1, format, args);
va_end(args);
tmpbuf[sizeof(tmpbuf)-1] = '\0';
printk(tmpbuf);
}
#endif
......@@ -2186,6 +2186,8 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
} else {
runtime->control->appl_ptr = appl_ptr;
}
if (substream->ops->ack)
substream->ops->ack(substream);
offset += frames;
size -= frames;
......@@ -2478,6 +2480,8 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream, void
} else {
runtime->control->appl_ptr = appl_ptr;
}
if (substream->ops->ack)
substream->ops->ack(substream);
offset += frames;
size -= frames;
......
......@@ -527,7 +527,7 @@ u_int8_t snd_pcm_format_silence(snd_pcm_format_t format)
*
* Sets the silence data on the buffer for the given samples.
*
* Returns zero if sucessful, or a negative error code on failure.
* Returns zero if successful, or a negative error code on failure.
*/
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
{
......
......@@ -1982,6 +1982,106 @@ snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream, snd_pcm
return ret;
}
snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_sframes_t appl_ptr;
snd_pcm_sframes_t ret;
snd_pcm_sframes_t avail;
if (frames == 0)
return 0;
spin_lock_irq(&runtime->lock);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_PAUSED:
break;
case SNDRV_PCM_STATE_DRAINING:
case SNDRV_PCM_STATE_RUNNING:
if (snd_pcm_update_hw_ptr(substream) >= 0)
break;
/* Fall through */
case SNDRV_PCM_STATE_XRUN:
ret = -EPIPE;
goto __end;
default:
ret = -EBADFD;
goto __end;
}
avail = snd_pcm_playback_avail(runtime);
if (avail <= 0) {
ret = 0;
goto __end;
}
if (frames > (snd_pcm_uframes_t)avail)
frames = avail;
else
frames -= frames % runtime->xfer_align;
appl_ptr = runtime->control->appl_ptr + frames;
if (appl_ptr >= runtime->boundary)
appl_ptr -= runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
runtime->sleep_min)
snd_pcm_tick_prepare(substream);
ret = frames;
__end:
spin_unlock_irq(&runtime->lock);
return ret;
}
snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
{
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_sframes_t appl_ptr;
snd_pcm_sframes_t ret;
snd_pcm_sframes_t avail;
if (frames == 0)
return 0;
spin_lock_irq(&runtime->lock);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_DRAINING:
case SNDRV_PCM_STATE_PAUSED:
break;
case SNDRV_PCM_STATE_RUNNING:
if (snd_pcm_update_hw_ptr(substream) >= 0)
break;
/* Fall through */
case SNDRV_PCM_STATE_XRUN:
ret = -EPIPE;
goto __end;
default:
ret = -EBADFD;
goto __end;
}
avail = snd_pcm_capture_avail(runtime);
if (avail <= 0) {
ret = 0;
goto __end;
}
if (frames > (snd_pcm_uframes_t)avail)
frames = avail;
else
frames -= frames % runtime->xfer_align;
appl_ptr = runtime->control->appl_ptr + frames;
if (appl_ptr >= runtime->boundary)
appl_ptr -= runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
runtime->sleep_min)
snd_pcm_tick_prepare(substream);
ret = frames;
__end:
spin_unlock_irq(&runtime->lock);
return ret;
}
static int snd_pcm_hwsync(snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
......@@ -2169,6 +2269,18 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
__put_user(result, _frames);
return result < 0 ? result : 0;
}
case SNDRV_PCM_IOCTL_FORWARD:
{
snd_pcm_uframes_t frames, *_frames = arg;
snd_pcm_sframes_t result;
if (get_user(frames, _frames))
return -EFAULT;
if (put_user(0, _frames))
return -EFAULT;
result = snd_pcm_playback_forward(substream, frames);
__put_user(result, _frames);
return result < 0 ? result : 0;
}
case SNDRV_PCM_IOCTL_PAUSE:
{
int res;
......@@ -2244,6 +2356,18 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
__put_user(result, _frames);
return result < 0 ? result : 0;
}
case SNDRV_PCM_IOCTL_FORWARD:
{
snd_pcm_uframes_t frames, *_frames = arg;
snd_pcm_sframes_t result;
if (get_user(frames, _frames))
return -EFAULT;
if (put_user(0, _frames))
return -EFAULT;
result = snd_pcm_capture_forward(substream, frames);
__put_user(result, _frames);
return result < 0 ? result : 0;
}
case SNDRV_PCM_IOCTL_DRAIN:
return snd_pcm_capture_drain(substream);
case SNDRV_PCM_IOCTL_DROP:
......
......@@ -358,10 +358,18 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
if (snd_rawmidi_info_select(card, &info) >= 0)
strcpy(port.name, info.subname);
if (! port.name[0]) {
if (ports > 1)
sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p);
else
sprintf(port.name, "MIDI %d-%d", card->number, device);
if (info.name[0]) {
if (ports > 1)
snprintf(port.name, sizeof(port.name), "%s-%d", info.name, p);
else
snprintf(port.name, sizeof(port.name), "%s", info.name);
} else {
/* last resort */
if (ports > 1)
sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p);
else
sprintf(port.name, "MIDI %d-%d", card->number, device);
}
}
if ((info.flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
port.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
......
......@@ -521,9 +521,6 @@ EXPORT_SYMBOL(snd_verbose_printk);
#endif
#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
EXPORT_SYMBOL(snd_verbose_printd);
#endif
#if defined(CONFIG_SND_DEBUG) && !defined(CONFIG_SND_VERBOSE_PRINTK)
EXPORT_SYMBOL(snd_printd);
#endif
/* wrappers */
#ifdef CONFIG_SND_DEBUG_MEMORY
......
......@@ -474,7 +474,7 @@ int snd_mpu401_uart_new(snd_card_t * card, int device,
}
mpu->irq = irq;
mpu->irq_flags = irq_flags;
strcpy(rmidi->name, "MPU-401 (UART)");
sprintf(rmidi->name, "MPU-401 (UART) %d-%d", card->number, device);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mpu401_uart_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
......
......@@ -802,7 +802,7 @@ module_exit(alsa_card_mtpav_exit)
#ifndef MODULE
/* format is: snd-mtpav=snd_enable,index,id,
/* format is: snd-mtpav=enable,index,id,
port,irq,hwports */
static int __init alsa_card_mtpav_setup(char *str)
......
......@@ -379,7 +379,7 @@ module_exit(alsa_card_dt019x_exit)
#ifndef MODULE
/* format is: snd-dt019x=enable,index,id,snd_isapnp,
/* format is: snd-dt019x=enable,index,id,
port,mpu_port,fm_port,
irq,mpu_irq,dma8,dma8_size */
......
......@@ -277,7 +277,7 @@ module_exit(alsa_card_es968_exit)
#ifndef MODULE
/* format is: snd-es968=enable,index,id,
port,irq,snd_dma1 */
port,irq,dma1 */
static int __init alsa_card_es968_setup(char *str)
{
......
......@@ -213,7 +213,10 @@ static int snd_sb_csp_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cm
info.run_width = p->run_width;
info.version = p->version;
info.state = p->running;
err = copy_to_user((void *) arg, &info, sizeof(info));
if (copy_to_user((void *) arg, &info, sizeof(info)))
err = -EFAULT;
else
err = 0;
break;
/* load CSP microcode */
......
......@@ -44,7 +44,7 @@ MODULE_DEVICES("{{Aztech Systems,Sound Galaxy}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */
static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */
......@@ -300,7 +300,7 @@ static int __init alsa_card_sgalaxy_init(void)
{
int dev, cards;
for (dev = cards = 0; dev < SNDRV_CARDS && snd_enable[dev]; dev++) {
for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
if (snd_sgalaxy_probe(dev) >= 0)
cards++;
}
......@@ -327,7 +327,7 @@ module_exit(alsa_card_sgalaxy_exit)
#ifndef MODULE
/* format is: snd-sgalaxy=snd_enable,index,id,
/* format is: snd-sgalaxy=enable,index,id,
sbport,wssport,
irq,dma1 */
......@@ -337,7 +337,7 @@ static int __init alsa_card_sgalaxy_setup(char *str)
if (nr_dev >= SNDRV_CARDS)
return 0;
(void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
(void)(get_option(&str,&enable[nr_dev]) == 2 &&
get_option(&str,&index[nr_dev]) == 2 &&
get_id(&str,&id[nr_dev]) == 2 &&
get_option(&str,(int *)&sbport[nr_dev]) == 2 &&
......
......@@ -56,110 +56,111 @@ static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97);
typedef struct {
unsigned int id;
unsigned int mask;
char *name;
const char *name;
int (*patch)(ac97_t *ac97);
int (*mpatch)(ac97_t *ac97);
} ac97_codec_id_t;
static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = {
{ 0x414b4d00, 0xffffff00, "Asahi Kasei", NULL },
{ 0x41445300, 0xffffff00, "Analog Devices", NULL },
{ 0x414c4300, 0xffffff00, "Realtek", NULL },
{ 0x414c4700, 0xffffff00, "Avance Logic", NULL },
{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL },
{ 0x43525900, 0xffffff00, "Cirrus Logic", NULL },
{ 0x43585400, 0xffffff00, "Conexant", NULL },
{ 0x44543000, 0xffffff00, "Diamond Technology", NULL },
{ 0x454d4300, 0xffffff00, "eMicro", NULL },
{ 0x45838300, 0xffffff00, "ESS Technology", NULL },
{ 0x48525300, 0xffffff00, "Intersil", NULL },
{ 0x49434500, 0xffffff00, "ICEnsemble", NULL },
{ 0x49544500, 0xffffff00, "ITE Tech.Inc", NULL },
{ 0x4e534300, 0xffffff00, "National Semiconductor", NULL },
{ 0x50534300, 0xffffff00, "Philips", NULL },
{ 0x53494c00, 0xffffff00, "Silicon Laboratory", NULL },
{ 0x54524100, 0xffffff00, "TriTech", NULL },
{ 0x54584e00, 0xffffff00, "Texas Instruments", NULL },
{ 0x56494100, 0xffffff00, "VIA Technologies", NULL },
{ 0x57454300, 0xffffff00, "Winbond", NULL },
{ 0x574d4c00, 0xffffff00, "Wolfson", NULL },
{ 0x594d4800, 0xffffff00, "Yamaha", NULL },
{ 0x83847600, 0xffffff00, "SigmaTel", NULL },
{ 0, 0, NULL, NULL }
{ 0x414b4d00, 0xffffff00, "Asahi Kasei", NULL, NULL },
{ 0x41445300, 0xffffff00, "Analog Devices", NULL, NULL },
{ 0x414c4300, 0xffffff00, "Realtek", NULL, NULL },
{ 0x414c4700, 0xffffff00, "Avance Logic", NULL, NULL },
{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL, NULL },
{ 0x43525900, 0xffffff00, "Cirrus Logic", NULL, NULL },
{ 0x43585400, 0xffffff00, "Conexant", NULL, NULL },
{ 0x44543000, 0xffffff00, "Diamond Technology", NULL, NULL },
{ 0x454d4300, 0xffffff00, "eMicro", NULL, NULL },
{ 0x45838300, 0xffffff00, "ESS Technology", NULL, NULL },
{ 0x48525300, 0xffffff00, "Intersil", NULL, NULL },
{ 0x49434500, 0xffffff00, "ICEnsemble", NULL, NULL },
{ 0x49544500, 0xffffff00, "ITE Tech.Inc", NULL, NULL },
{ 0x4e534300, 0xffffff00, "National Semiconductor", NULL, NULL },
{ 0x50534300, 0xffffff00, "Philips", NULL, NULL },
{ 0x53494c00, 0xffffff00, "Silicon Laboratory", NULL, NULL },
{ 0x54524100, 0xffffff00, "TriTech", NULL, NULL },
{ 0x54584e00, 0xffffff00, "Texas Instruments", NULL, NULL },
{ 0x56494100, 0xffffff00, "VIA Technologies", NULL, NULL },
{ 0x57454300, 0xffffff00, "Winbond", NULL, NULL },
{ 0x574d4c00, 0xffffff00, "Wolfson", NULL, NULL },
{ 0x594d4800, 0xffffff00, "Yamaha", NULL, NULL },
{ 0x83847600, 0xffffff00, "SigmaTel", NULL, NULL },
{ 0, 0, NULL, NULL, NULL }
};
static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x014b0502, 0xffffffff, "NM256AV", NULL }, // FIXME: which real one?
{ 0x414b4d00, 0xffffffff, "AK4540", NULL },
{ 0x414b4d01, 0xffffffff, "AK4542", NULL },
{ 0x414b4d02, 0xffffffff, "AK4543", NULL },
{ 0x414b4d06, 0xffffffff, "AK4544A", NULL },
{ 0x414b4d07, 0xffffffff, "AK4545", NULL },
{ 0x41445303, 0xffffffff, "AD1819", patch_ad1819 },
{ 0x41445340, 0xffffffff, "AD1881", patch_ad1881 },
{ 0x41445348, 0xffffffff, "AD1881A", patch_ad1881 },
{ 0x41445360, 0xffffffff, "AD1885", patch_ad1885 },
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886 },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881 },
{ 0x41445363, 0xffffffff, "AD1886A", patch_ad1881 },
{ 0x41445370, 0xffffffff, "AD1980", patch_ad1980 },
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1881 },
{ 0x414c4300, 0xfffffff0, "RL5306", NULL },
{ 0x414c4310, 0xfffffff0, "RL5382", NULL },
{ 0x414c4320, 0xfffffff0, "RL5383", NULL },
{ 0x414c4710, 0xfffffff0, "ALC200/200P", NULL },
{ 0x414c4720, 0xfffffff0, "ALC650", patch_alc650 },
{ 0x414c4730, 0xffffffff, "ALC101", NULL },
{ 0x414c4740, 0xfffffff0, "ALC202", NULL },
{ 0x414c4750, 0xfffffff0, "ALC250", NULL },
{ 0x434d4941, 0xffffffff, "CMI9738", NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", NULL },
{ 0x43525900, 0xfffffff8, "CS4297", NULL },
{ 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif },
{ 0x43525920, 0xfffffff8, "CS4294/4298", NULL },
{ 0x43525928, 0xfffffff8, "CS4294", NULL },
{ 0x43525930, 0xfffffff8, "CS4299", patch_cirrus_cs4299 },
{ 0x43525948, 0xfffffff8, "CS4201", NULL },
{ 0x43525958, 0xfffffff8, "CS4205", patch_cirrus_spdif },
{ 0x43525960, 0xfffffff8, "CS4291", NULL },
{ 0x43585421, 0xffffffff, "HSD11246", NULL }, // SmartMC II
{ 0x43585428, 0xfffffff8, "Cx20468", patch_conexant }, // SmartAMC fixme: the mask might be different
{ 0x44543031, 0xfffffff0, "DT0398", NULL },
{ 0x454d4328, 0xffffffff, "28028", NULL }, // same as TR28028?
{ 0x45838308, 0xffffffff, "ESS1988", NULL },
{ 0x48525300, 0xffffff00, "HMP9701", NULL },
{ 0x49434501, 0xffffffff, "ICE1230", NULL },
{ 0x49434511, 0xffffffff, "ICE1232", NULL }, // alias VIA VT1611A?
{ 0x49434551, 0xffffffff, "VT1616", NULL },
{ 0x49544520, 0xffffffff, "IT2226E", NULL },
{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL }, // only guess --jk
{ 0x4e534331, 0xffffffff, "LM4549", NULL },
{ 0x50534304, 0xffffffff, "UCB1400", NULL },
{ 0x53494c22, 0xffffffff, "Si3036", NULL },
{ 0x53494c23, 0xffffffff, "Si3038", NULL },
{ 0x54524102, 0xffffffff, "TR28022", NULL },
{ 0x54524106, 0xffffffff, "TR28026", NULL },
{ 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028 }, // added by xin jin [07/09/99]
{ 0x54524123, 0xffffffff, "TR28602", NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
{ 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL },
{ 0x56494161, 0xffffffff, "VIA1612A", NULL }, // modified ICE1232 with S/PDIF
{ 0x57454301, 0xffffffff, "W83971D", NULL },
{ 0x574d4c00, 0xffffffff, "WM9701A", patch_wolfson00 },
{ 0x574d4c03, 0xffffffff, "WM9703/9707", patch_wolfson03 },
{ 0x574d4c04, 0xffffffff, "WM9704/quad", patch_wolfson04 },
{ 0x574d4c05, 0xffffffff, "WM9705", NULL }, // patch?
{ 0x594d4800, 0xffffffff, "YMF743", NULL },
{ 0x594d4802, 0xffffffff, "YMF752", NULL },
{ 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753 },
{ 0x83847600, 0xffffffff, "STAC9700/83/84", NULL },
{ 0x83847604, 0xffffffff, "STAC9701/3/4/5", NULL },
{ 0x83847605, 0xffffffff, "STAC9704", NULL },
{ 0x83847608, 0xffffffff, "STAC9708/11", patch_sigmatel_stac9708 },
{ 0x83847609, 0xffffffff, "STAC9721/23", patch_sigmatel_stac9721 },
{ 0x83847644, 0xffffffff, "STAC9744", patch_sigmatel_stac9744 },
{ 0x83847650, 0xffffffff, "STAC9750/51", NULL }, // patch?
{ 0x83847656, 0xffffffff, "STAC9756/57", patch_sigmatel_stac9756 },
{ 0x83847666, 0xffffffff, "STAC9766/67", NULL }, // patch?
{ 0, 0, NULL, NULL }
{ 0x014b0502, 0xffffffff, "NM256AV", NULL, NULL }, // FIXME: which real one?
{ 0x414b4d00, 0xffffffff, "AK4540", NULL, NULL },
{ 0x414b4d01, 0xffffffff, "AK4542", NULL, NULL },
{ 0x414b4d02, 0xffffffff, "AK4543", NULL, NULL },
{ 0x414b4d06, 0xffffffff, "AK4544A", NULL, NULL },
{ 0x414b4d07, 0xffffffff, "AK4545", NULL, NULL },
{ 0x41445303, 0xffffffff, "AD1819", patch_ad1819, NULL },
{ 0x41445340, 0xffffffff, "AD1881", patch_ad1881, NULL },
{ 0x41445348, 0xffffffff, "AD1881A", patch_ad1881, NULL },
{ 0x41445360, 0xffffffff, "AD1885", patch_ad1885, NULL },
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886, NULL },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881, NULL },
{ 0x41445363, 0xffffffff, "AD1886A", patch_ad1881, NULL },
{ 0x41445370, 0xffffffff, "AD1980", patch_ad1980, NULL },
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1881, NULL },
{ 0x414c4300, 0xfffffff0, "RL5306", NULL, NULL },
{ 0x414c4310, 0xfffffff0, "RL5382", NULL, NULL },
{ 0x414c4320, 0xfffffff0, "RL5383", NULL, NULL },
{ 0x414c4710, 0xfffffff0, "ALC200/200P", NULL, NULL },
{ 0x414c4720, 0xfffffff0, "ALC650", patch_alc650, NULL },
{ 0x414c4730, 0xffffffff, "ALC101", NULL, NULL },
{ 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL },
{ 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL },
{ 0x434d4941, 0xffffffff, "CMI9738", NULL, NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", NULL, NULL },
{ 0x43525900, 0xfffffff8, "CS4297", NULL, NULL },
{ 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif, NULL },
{ 0x43525920, 0xfffffff8, "CS4294/4298", NULL, NULL },
{ 0x43525928, 0xfffffff8, "CS4294", NULL, NULL },
{ 0x43525930, 0xfffffff8, "CS4299", patch_cirrus_cs4299, NULL },
{ 0x43525948, 0xfffffff8, "CS4201", NULL, NULL },
{ 0x43525958, 0xfffffff8, "CS4205", patch_cirrus_spdif, NULL },
{ 0x43525960, 0xfffffff8, "CS4291", NULL, NULL },
{ 0x43585421, 0xffffffff, "HSD11246", NULL, NULL }, // SmartMC II
{ 0x43585428, 0xfffffff8, "Cx20468", patch_conexant, NULL }, // SmartAMC fixme: the mask might be different
{ 0x44543031, 0xfffffff0, "DT0398", NULL, NULL },
{ 0x454d4328, 0xffffffff, "28028", NULL, NULL }, // same as TR28028?
{ 0x45838308, 0xffffffff, "ESS1988", NULL, NULL },
{ 0x48525300, 0xffffff00, "HMP9701", NULL, NULL },
{ 0x49434501, 0xffffffff, "ICE1230", NULL, NULL },
{ 0x49434511, 0xffffffff, "ICE1232", NULL, NULL }, // alias VIA VT1611A?
{ 0x49434551, 0xffffffff, "VT1616", NULL, NULL },
{ 0x49544520, 0xffffffff, "IT2226E", NULL, NULL },
{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk
{ 0x4e534331, 0xffffffff, "LM4549", NULL, NULL },
{ 0x50534304, 0xffffffff, "UCB1400", NULL, NULL },
{ 0x53494c22, 0xffffffff, "Si3036", NULL, NULL },
{ 0x53494c23, 0xffffffff, "Si3038", NULL, NULL },
{ 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
{ 0x54524106, 0xffffffff, "TR28026", NULL, NULL },
{ 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99]
{ 0x54524123, 0xffffffff, "TR28602", NULL, NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
{ 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL },
{ 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF
{ 0x57454301, 0xffffffff, "W83971D", NULL, NULL },
{ 0x574d4c00, 0xffffffff, "WM9701A", patch_wolfson00,NULL },
{ 0x574d4c03, 0xffffffff, "WM9703/9707", patch_wolfson03,NULL },
{ 0x574d4c04, 0xffffffff, "WM9704/quad", patch_wolfson04,NULL },
{ 0x574d4c05, 0xffffffff, "WM9705", NULL, NULL }, // patch?
{ 0x594d4800, 0xffffffff, "YMF743", NULL, NULL },
{ 0x594d4802, 0xffffffff, "YMF752", NULL, NULL },
{ 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL },
{ 0x83847600, 0xffffffff, "STAC9700/83/84", NULL, NULL },
{ 0x83847604, 0xffffffff, "STAC9701/3/4/5", NULL, NULL },
{ 0x83847605, 0xffffffff, "STAC9704", NULL, NULL },
{ 0x83847608, 0xffffffff, "STAC9708/11", patch_sigmatel_stac9708, NULL },
{ 0x83847609, 0xffffffff, "STAC9721/23", patch_sigmatel_stac9721, NULL },
{ 0x83847644, 0xffffffff, "STAC9744", patch_sigmatel_stac9744, NULL },
{ 0x83847650, 0xffffffff, "STAC9750/51", NULL, NULL }, // patch?
{ 0x83847656, 0xffffffff, "STAC9756/57", patch_sigmatel_stac9756, NULL },
{ 0x83847666, 0xffffffff, "STAC9766/67", NULL, NULL }, // patch?
{ 0, 0, NULL, NULL, NULL }
};
static const char *snd_ac97_stereo_enhancements[] =
......@@ -325,7 +326,7 @@ static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned
* Compares the value with the register cache and updates the value
* only when the value is changed.
*
* Retruns 1 if the value is changed, 0 if no change, or a negative
* Returns 1 if the value is changed, 0 if no change, or a negative
* code on failure.
*/
int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value)
......@@ -352,7 +353,7 @@ int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value)
* @mask: the bit-mask to change
* @value: the value to set
*
* Updates the masked-bits on the given register onle when the value
* Updates the masked-bits on the given register only when the value
* is changed.
*
* Returns 1 if the bits are changed, 0 if no change, or a negative
......@@ -1022,6 +1023,50 @@ static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_lfe[1] = {
AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 31)
};
static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
static char *texts[2] = { "AC-Link", "A/D Converter" };
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = 2;
if (uinfo->value.enumerated.item > 1)
uinfo->value.enumerated.item = 1;
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
return 0;
}
static int snd_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
val = ac97->regs[AC97_AD_SERIAL_CFG];
ucontrol->value.enumerated.item[0] = (val >> 2) & 1;
return 0;
}
static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
unsigned short val;
if (ucontrol->value.enumerated.item[0] > 1)
return -EINVAL;
val = ucontrol->value.enumerated.item[0] << 2;
return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val);
}
static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source =
{
iface: SNDRV_CTL_ELEM_IFACE_MIXER,
name: SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
info: snd_ac97_ad1980_spdif_source_info,
get: snd_ac97_ad1980_spdif_source_get,
put: snd_ac97_ad1980_spdif_source_put,
};
/*
* ALC650
*/
......@@ -1032,8 +1077,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0),
/* 4: Analog Input To Surround */
/* 5: Analog Input To Center/LFE */
/* 6: Indepedent Master Volume Right */
/* 7: Indepedent Master Volume Left */
/* 6: Independent Master Volume Right */
/* 7: Independent Master Volume Left */
/* 8: reserved */
AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0),
......@@ -1140,7 +1185,7 @@ static int snd_ac97_ymf753_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_e
}
/* The AC'97 spec states that the S/PDIF signal is to be output at pin 48.
The YMF753 will ouput the S/PDIF signal to pin 43, 47 (EAPD), or 48.
The YMF753 will output the S/PDIF signal to pin 43, 47 (EAPD), or 48.
By default, no output pin is selected, and the S/PDIF signal is not output.
There is also a bit to mute S/PDIF output in a vendor-specific register. */
static int snd_ac97_ymf753_spdif_output_pin_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
......@@ -1680,6 +1725,9 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
for (idx = 0; idx < 3; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_spdif[idx], ac97))) < 0)
return err;
} else if (ac97->id == AC97_ID_AD1980) {
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ad1980_spdif_source, ac97))) < 0)
return err;
}
/* set default PCM S/PDIF params */
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
......@@ -1735,6 +1783,12 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
return 0;
}
static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97)
{
/* TODO */
return 0;
}
static int snd_ac97_test_rate(ac97_t *ac97, int reg, int rate)
{
unsigned short val;
......@@ -1771,7 +1825,7 @@ static void snd_ac97_determine_rates(ac97_t *ac97, int reg, unsigned int *r_resu
*r_result = result;
}
static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name)
static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name, int modem)
{
const ac97_codec_id_t *pid;
......@@ -1782,8 +1836,12 @@ static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name)
for (pid = snd_ac97_codec_id_vendors; pid->id; pid++)
if (pid->id == (id & pid->mask)) {
strcpy(name, pid->name);
if (ac97 && pid->patch)
pid->patch(ac97);
if (ac97) {
if (!modem && pid->patch)
pid->patch(ac97);
else if (modem && pid->mpatch)
pid->mpatch(ac97);
}
goto __vendor_ok;
}
return;
......@@ -1795,8 +1853,12 @@ static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name)
strcat(name, pid->name);
if (pid->mask != 0xffffffff)
sprintf(name + strlen(name), " rev %d", id & ~pid->mask);
if (ac97 && pid->patch)
pid->patch(ac97);
if (ac97) {
if (!modem && pid->patch)
pid->patch(ac97);
else if (modem && pid->mpatch)
pid->mpatch(ac97);
}
return;
}
sprintf(name + strlen(name), " id %x", id & 0xff);
......@@ -1850,7 +1912,7 @@ static int ac97_reset_wait(ac97_t *ac97, int timeout, int with_modem)
* The template must include the valid callbacks (at least read and
* write), the codec number (num) and address (addr), and the private
* data (private_data). The other callbacks, wait and reset, are not
* mandantory.
* mandatory.
*
* The clock is set to 48000. If another clock is needed, reset
* ac97->clock manually afterwards.
......@@ -1858,9 +1920,11 @@ static int ac97_reset_wait(ac97_t *ac97, int timeout, int with_modem)
* The ac97 instance is registered as a low-level device, so you don't
* have to release it manually.
*
* Returns zero if sucessful, or a negative error code on failure.
* The MCs (Modem Codecs only) are only detected but valid. The PCM driver
* have to check for MCs using the !ac97_is_audio() function.
*
* Returns zero if successful, or a negative error code on failure.
*/
int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
{
int err;
......@@ -1929,8 +1993,8 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
goto __ready_ok;
/* FIXME: add powerdown control */
/* nothing should be in powerdown mode */
if (ac97->scaps & AC97_SCAP_AUDIO) {
if (ac97_is_audio(ac97)) {
/* nothing should be in powerdown mode */
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
snd_ac97_write_cache_test(ac97, AC97_RESET, 0); /* reset to defaults */
udelay(100);
......@@ -1950,7 +2014,7 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
__ready_ok:
if (ac97->clock == 0)
ac97->clock = 48000; /* standard value */
if (ac97->scaps & AC97_SCAP_AUDIO)
if (ac97_is_audio(ac97))
ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT;
else
ac97->addr = (ac97->ext_mid & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT;
......@@ -1985,8 +2049,8 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
/* additional initializations */
if (ac97->init)
ac97->init(ac97);
snd_ac97_get_name(ac97, ac97->id, name);
snd_ac97_get_name(NULL, ac97->id, name); // ac97->id might be changed in the special setup code
snd_ac97_get_name(ac97, ac97->id, name, 0);
snd_ac97_get_name(NULL, ac97->id, name, 0); // ac97->id might be changed in the special setup code
if (card->mixername[0] == '\0') {
strcpy(card->mixername, name);
} else {
......@@ -1995,19 +2059,188 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
strcat(card->mixername, name);
}
}
if (ac97->scaps & AC97_SCAP_AUDIO) {
if (ac97_is_audio(ac97)) {
if ((err = snd_component_add(card, "AC97a")) < 0) {
snd_ac97_free(ac97);
return err;
}
}
if (ac97_is_audio(ac97) && snd_ac97_mixer_build(card, ac97) < 0) {
snd_ac97_free(ac97);
return -ENOMEM;
}
snd_ac97_proc_init(card, ac97);
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) {
snd_ac97_free(ac97);
return err;
}
*rac97 = ac97;
return 0;
}
/* wait for a while until registers are accessible after RESET
* return 0 if ok, negative not ready
*/
static int ac97_modem_reset_wait(ac97_t *ac97, int timeout)
{
signed long end_time;
end_time = jiffies + timeout;
do {
unsigned short ext_mid;
/* use preliminary reads to settle the communication */
snd_ac97_read(ac97, AC97_EXTENDED_MID);
snd_ac97_read(ac97, AC97_VENDOR_ID1);
snd_ac97_read(ac97, AC97_VENDOR_ID2);
ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID);
if (ext_mid != 0xffff && (ext_mid & 1) != 0)
return 0;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100);
} while (time_after_eq(end_time, jiffies));
return -ENODEV;
}
/**
* snd_ac97_modem - create an MC97 codec component
* @card: the card instance
* @_ac97: the template of ac97, including index, callbacks and
* the private data.
* @rac97: the pointer to store the new ac97 instance.
*
* Creates an MC97 codec component. An ac97_t instance is newly
* allocated and initialized from the template (_ac97). The codec
* is then initialized by the standard procedure.
*
* The template must include the valid callbacks (at least read and
* write), the codec number (num) and address (addr), and the private
* data (private_data). The other callbacks, wait and reset, are not
* mandatory.
*
* The clock is set to 48000. If another clock is needed, reset
* ac97->clock manually afterwards.
*
* The ac97 instance is registered as a low-level device, so you don't
* have to release it manually.
*
* The ACs (Audio Codecs only) are only detected but valid. The PCM driver
* have to check for ACs using the !ac97_is_modem() function.
*
* Returns zero if successful, or a negative error code on failure.
*/
int snd_ac97_modem(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
{
int err;
ac97_t *ac97;
char name[64];
// signed long end_time;
unsigned short tmp;
static snd_device_ops_t ops = {
.dev_free = snd_ac97_dev_free,
};
snd_assert(rac97 != NULL, return -EINVAL);
*rac97 = NULL;
snd_assert(card != NULL && _ac97 != NULL, return -EINVAL);
ac97 = snd_magic_kcalloc(ac97_t, 0, GFP_KERNEL);
if (ac97 == NULL)
return -ENOMEM;
*ac97 = *_ac97;
ac97->card = card;
spin_lock_init(&ac97->reg_lock);
if (ac97->reset) {
ac97->reset(ac97);
goto __access_ok;
}
snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); /* reset to defaults */
if (ac97->wait)
ac97->wait(ac97);
else {
udelay(50);
if (ac97_modem_reset_wait(ac97, HZ/2) < 0) {
snd_printk("MC'97 %d:%d does not respond - MODEM RESET\n", ac97->num, ac97->addr);
snd_ac97_free(ac97);
return -ENXIO;
}
}
__access_ok:
ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;
ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
if (ac97->id == 0x00000000 || ac97->id == 0xffffffff) {
snd_printk("AC'97 %d:%d access is not valid [0x%x], removing modem controls.\n", ac97->num, ac97->addr, ac97->id);
snd_ac97_free(ac97);
return -EIO;
}
/* test for MC'97 */
ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID);
if (ac97->ext_mid == 0xffff) /* invalid combination */
ac97->ext_mid = 0;
if (ac97->ext_mid & 1)
ac97->scaps |= AC97_SCAP_MODEM;
/* non-destructive test for AC'97 */
tmp = snd_ac97_read(ac97, AC97_RESET);
if (tmp == 0 || tmp == 0xffff) {
tmp = snd_ac97_read(ac97, AC97_EXTENDED_ID);
if (tmp == 0 || tmp == 0xffff) {
tmp = snd_ac97_read(ac97, AC97_REC_GAIN);
if (tmp == 0 || tmp == 0xffff)
tmp = snd_ac97_read(ac97, AC97_POWERDOWN);
}
}
if ((tmp != 0 && tmp != 0xffff) || !(ac97->scaps & AC97_SCAP_MODEM))
ac97->scaps |= AC97_SCAP_AUDIO;
if (ac97->reset) // FIXME: always skipping?
goto __ready_ok;
/* FIXME: add powerdown control */
if (ac97->scaps & AC97_SCAP_MODEM) {
#if 0 /* FIXME - add modem powerup */
/* nothing should be in powerdown mode */
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
snd_ac97_write_cache_test(ac97, AC97_RESET, 0); /* reset to defaults */
udelay(100);
/* nothing should be in powerdown mode */
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
snd_ac97_write_cache_test(ac97, AC97_GENERAL_PURPOSE, 0);
end_time = jiffies + (HZ / 10);
do {
if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f)
goto __ready_ok;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/10);
} while (time_after_eq(end_time, jiffies));
snd_printk("AC'97 %d:%d analog subsections not ready\n", ac97->num, ac97->addr);
#endif
}
__ready_ok:
/* additional initializations */
/* FIXME: ADD MODEM INITALIZATION */
if (ac97->init)
ac97->init(ac97);
snd_ac97_get_name(ac97, ac97->id, name, 1);
snd_ac97_get_name(NULL, ac97->id, name, 1); // ac97->id might be changed in the special setup code
if (card->mixername[0] == '\0') {
strcpy(card->mixername, name);
} else {
if (strlen(card->mixername) + 1 + strlen(name) + 1 <= sizeof(card->mixername)) {
strcat(card->mixername, ",");
strcat(card->mixername, name);
}
}
if (ac97_is_modem(ac97)) {
if ((err = snd_component_add(card, "AC97m")) < 0) {
snd_ac97_free(ac97);
return err;
}
}
if (snd_ac97_mixer_build(card, ac97) < 0) {
if (ac97_is_modem(ac97) && snd_ac97_modem_build(card, ac97) < 0) {
snd_ac97_free(ac97);
return -ENOMEM;
}
......@@ -2035,7 +2268,7 @@ static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, in
id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16;
id |= snd_ac97_read(ac97, AC97_VENDOR_ID2);
snd_ac97_get_name(NULL, id, name);
snd_ac97_get_name(NULL, id, name, 0);
snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name);
if ((ac97->scaps & AC97_SCAP_AUDIO) == 0)
goto __modem;
......@@ -2430,6 +2663,7 @@ static int remove_ctl(ac97_t *ac97, const char *name)
snd_ctl_elem_id_t id;
memset(&id, 0, sizeof(id));
strcpy(id.name, name);
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_remove_id(ac97->card, &id);
}
......@@ -2438,8 +2672,10 @@ static int rename_ctl(ac97_t *ac97, const char *src, const char *dst)
snd_ctl_elem_id_t sid, did;
memset(&sid, 0, sizeof(sid));
strcpy(sid.name, src);
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
memset(&did, 0, sizeof(did));
strcpy(did.name, dst);
did.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_rename_id(ac97->card, &sid, &did);
}
......@@ -2476,19 +2712,21 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct pci_dev *pci, struct ac97_quirk
{
unsigned short vendor, device;
snd_assert(quirk, return -EINVAL);
pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &vendor);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &device);
for (; quirk->vendor; quirk++) {
if (quirk->vendor == vendor && quirk->device == device) {
snd_printdd("ac97 quirk for %04x:%04x\n", vendor, device);
snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, vendor, device);
switch (quirk->type) {
case AC97_TUNE_HP_ONLY:
return swap_headphone(ac97, 1);
case AC97_TUNE_SWAP_HP:
return swap_headphone(ac97, 0);
}
snd_printk(KERN_ERR "invalid quirk type %d\n", quirk->type);
snd_printk(KERN_ERR "invalid quirk type %d for %s\n", quirk->type, quirk->name);
return -EINVAL;
}
}
......@@ -2506,6 +2744,7 @@ EXPORT_SYMBOL(snd_ac97_write_cache);
EXPORT_SYMBOL(snd_ac97_update);
EXPORT_SYMBOL(snd_ac97_update_bits);
EXPORT_SYMBOL(snd_ac97_mixer);
EXPORT_SYMBOL(snd_ac97_modem);
EXPORT_SYMBOL(snd_ac97_set_rate);
EXPORT_SYMBOL(snd_ac97_tune_hardware);
#ifdef CONFIG_PM
......
......@@ -31,6 +31,7 @@
#define AC97_ID_AD1886 0x41445361
#define AC97_ID_AD1887 0x41445362
#define AC97_ID_AD1886A 0x41445363
#define AC97_ID_AD1980 0x41445370
#define AC97_ID_TR28028 0x54524108
#define AC97_ID_STAC9700 0x83847600
#define AC97_ID_STAC9704 0x83847604
......
......@@ -672,28 +672,21 @@ static void snd_cs46xx_set_capture_sample_rate(cs46xx_t *chip, unsigned int rate
* PCM part
*/
static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream,
snd_pcm_uframes_t frames)
static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream)
{
/* cs46xx_t *chip = snd_pcm_substream_chip(substream); */
snd_pcm_runtime_t *runtime = substream->runtime;
cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
snd_pcm_sframes_t diff;
cs46xx_pcm_t * cpcm;
int buffer_size;
cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift;
snd_pcm_sframes_t diff = appl_ptr - cpcm->appl_ptr;
int buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift;
diff = appl_ptr - cpcm->appl_ptr;
if (diff) {
if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
diff += runtime->boundary;
frames += diff;
cpcm->sw_ready += diff * (1 << cpcm->shift);
cpcm->appl_ptr = appl_ptr;
}
cpcm->sw_ready += frames << cpcm->shift;
cpcm->appl_ptr = appl_ptr + frames;
while (cpcm->hw_ready < buffer_size &&
cpcm->sw_ready > 0) {
size_t hw_to_end = buffer_size - cpcm->hw_data;
......@@ -720,21 +713,20 @@ static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream,
return 0;
}
static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream,
snd_pcm_uframes_t frames)
static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream)
{
cs46xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
snd_pcm_sframes_t diff = appl_ptr - chip->capt.appl_ptr;
int buffer_size = runtime->period_size * CS46XX_FRAGS << chip->capt.shift;
if (diff) {
if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
diff += runtime->boundary;
frames += diff;
chip->capt.sw_ready -= diff * (1 << chip->capt.shift);
chip->capt.appl_ptr = appl_ptr;
}
chip->capt.sw_ready -= frames << chip->capt.shift;
chip->capt.appl_ptr = appl_ptr + frames;
while (chip->capt.hw_ready > 0 &&
chip->capt.sw_ready < (int)chip->capt.sw_bufsize) {
size_t hw_to_end = buffer_size - chip->capt.hw_data;
......@@ -802,7 +794,7 @@ static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(snd_pcm_substream_
cpcm->sw_io += bytes;
if (cpcm->sw_io >= cpcm->sw_bufsize)
cpcm->sw_io -= cpcm->sw_bufsize;
snd_cs46xx_playback_transfer(substream, 0);
snd_cs46xx_playback_transfer(substream);
return cpcm->sw_io >> cpcm->shift;
}
......@@ -827,57 +819,10 @@ static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t
chip->capt.sw_io += bytes;
if (chip->capt.sw_io >= chip->capt.sw_bufsize)
chip->capt.sw_io -= chip->capt.sw_bufsize;
snd_cs46xx_capture_transfer(substream, 0);
snd_cs46xx_capture_transfer(substream);
return chip->capt.sw_io >> chip->capt.shift;
}
static int snd_cs46xx_playback_copy(snd_pcm_substream_t *substream,
int channel,
snd_pcm_uframes_t hwoff,
void *src,
snd_pcm_uframes_t frames)
{
snd_pcm_runtime_t *runtime = substream->runtime;
/*cs46xx_t *chip = snd_pcm_substream_chip(substream); */
size_t hwoffb;
size_t bytes;
char *hwbuf;
cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
snd_assert(runtime->dma_area, return -EINVAL);
hwoffb = hwoff << cpcm->shift;
bytes = frames << cpcm->shift;
hwbuf = runtime->dma_area + hwoffb;
if (copy_from_user(hwbuf, src, bytes))
return -EFAULT;
spin_lock_irq(&runtime->lock);
snd_cs46xx_playback_transfer(substream, frames);
spin_unlock_irq(&runtime->lock);
return 0;
}
static int snd_cs46xx_capture_copy(snd_pcm_substream_t *substream,
int channel,
snd_pcm_uframes_t hwoff,
void *dst,
snd_pcm_uframes_t frames)
{
snd_pcm_runtime_t *runtime = substream->runtime;
cs46xx_t *chip = snd_pcm_substream_chip(substream);
size_t hwoffb = hwoff << chip->capt.shift;
size_t bytes = frames << chip->capt.shift;
char *hwbuf = runtime->dma_area + hwoffb;
if (copy_to_user(dst, hwbuf, bytes))
return -EFAULT;
spin_lock_irq(&runtime->lock);
snd_cs46xx_capture_transfer(substream, frames);
spin_unlock_irq(&runtime->lock);
return 0;
}
static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
int cmd)
{
......@@ -909,10 +854,10 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);
if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream, 0);
snd_cs46xx_playback_transfer(substream);
#else
if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream, 0);
snd_cs46xx_playback_transfer(substream);
{ unsigned int tmp;
tmp = snd_cs46xx_peek(chip, BA1_PCTL);
tmp &= 0x0000ffff;
......@@ -1587,8 +1532,8 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops = {
.hw_free = snd_cs46xx_playback_hw_free,
.prepare = snd_cs46xx_playback_prepare,
.trigger = snd_cs46xx_playback_trigger,
.copy = snd_cs46xx_playback_copy,
.pointer = snd_cs46xx_playback_indirect_pointer,
.ack = snd_cs46xx_playback_transfer,
};
snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = {
......@@ -1610,8 +1555,8 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops = {
.hw_free = snd_cs46xx_playback_hw_free,
.prepare = snd_cs46xx_playback_prepare,
.trigger = snd_cs46xx_playback_trigger,
.copy = snd_cs46xx_playback_copy,
.pointer = snd_cs46xx_playback_indirect_pointer,
.ack = snd_cs46xx_playback_transfer,
};
#endif
......@@ -1635,8 +1580,8 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_ops = {
.hw_free = snd_cs46xx_playback_hw_free,
.prepare = snd_cs46xx_playback_prepare,
.trigger = snd_cs46xx_playback_trigger,
.copy = snd_cs46xx_playback_copy,
.pointer = snd_cs46xx_playback_indirect_pointer,
.ack = snd_cs46xx_playback_transfer,
};
snd_pcm_ops_t snd_cs46xx_capture_ops = {
......@@ -1658,8 +1603,8 @@ snd_pcm_ops_t snd_cs46xx_capture_indirect_ops = {
.hw_free = snd_cs46xx_capture_hw_free,
.prepare = snd_cs46xx_capture_prepare,
.trigger = snd_cs46xx_capture_trigger,
.copy = snd_cs46xx_capture_copy,
.pointer = snd_cs46xx_capture_indirect_pointer,
.ack = snd_cs46xx_capture_transfer,
};
static void snd_cs46xx_pcm_free(snd_pcm_t *pcm)
......@@ -2505,9 +2450,6 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
strcpy(id.name, "External Amplifier Power Down");
chip->eapd_switch = snd_ctl_find_id(chip->card, &id);
/* turn on amplifier */
chip->amplifier_ctrl(chip, 1);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
/* do soundcard specific mixer setup */
if (chip->mixer_init) {
......@@ -2515,6 +2457,9 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
chip->mixer_init(chip);
}
#endif
/* turn on amplifier */
chip->amplifier_ctrl(chip, 1);
return 0;
}
......
......@@ -520,8 +520,7 @@ static void snd_emu10k1_fx8010_playback_tram_poke(emu10k1_t *emu,
*tram_pos -= frames;
}
static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream,
snd_pcm_uframes_t frames)
static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream)
{
emu10k1_t *emu = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
......@@ -529,13 +528,13 @@ static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream,
snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
snd_pcm_sframes_t diff = appl_ptr - pcm->appl_ptr;
snd_pcm_uframes_t buffer_size = pcm->buffer_size / 2;
if (diff) {
if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
diff += runtime->boundary;
frames += diff;
pcm->sw_ready += diff;
pcm->appl_ptr = appl_ptr;
}
pcm->sw_ready += frames;
pcm->appl_ptr = appl_ptr + frames;
while (pcm->hw_ready < buffer_size &&
pcm->sw_ready > 0) {
size_t hw_to_end = buffer_size - pcm->hw_data;
......@@ -632,7 +631,7 @@ static int snd_emu10k1_fx8010_playback_trigger(snd_pcm_substream_t * substream,
result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq);
if (result < 0)
goto __err;
snd_emu10k1_fx8010_playback_transfer(substream, 0); /* roll the ball */
snd_emu10k1_fx8010_playback_transfer(substream); /* roll the ball */
snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1);
break;
case SNDRV_PCM_TRIGGER_STOP:
......@@ -670,28 +669,10 @@ static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(snd_pcm_substream_t
pcm->sw_io += frames;
if (pcm->sw_io > runtime->buffer_size)
pcm->sw_io -= runtime->buffer_size;
snd_emu10k1_fx8010_playback_transfer(substream, 0);
snd_emu10k1_fx8010_playback_transfer(substream);
return pcm->sw_io;
}
static int snd_emu10k1_fx8010_playback_copy(snd_pcm_substream_t *substream,
int channel,
snd_pcm_uframes_t hwoff,
void *src,
snd_pcm_uframes_t frames)
{
snd_pcm_runtime_t *runtime = substream->runtime;
size_t hwoffb = hwoff << 2;
size_t bytes = frames << 2;
char *hwbuf = runtime->dma_area + hwoffb;
if (copy_from_user(hwbuf, src, bytes))
return -EFAULT;
spin_lock_irq(&runtime->lock);
snd_emu10k1_fx8010_playback_transfer(substream, frames);
spin_unlock_irq(&runtime->lock);
return 0;
}
static snd_pcm_hardware_t snd_emu10k1_fx8010_playback =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
......@@ -748,8 +729,8 @@ static snd_pcm_ops_t snd_emu10k1_fx8010_playback_ops = {
.hw_free = snd_emu10k1_fx8010_playback_hw_free,
.prepare = snd_emu10k1_fx8010_playback_prepare,
.trigger = snd_emu10k1_fx8010_playback_trigger,
.copy = snd_emu10k1_fx8010_playback_copy,
.pointer = snd_emu10k1_fx8010_playback_pointer,
.ack = snd_emu10k1_fx8010_playback_transfer,
};
static void snd_emu10k1_fx8010_pcm_free(snd_pcm_t *pcm)
......@@ -1221,7 +1202,7 @@ static void __devinit snd_emu10k1_init_stereo_control(emu10k1_fx8010_control_gpr
ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
ctl->min = 0;
ctl->max = 100;
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
}
static void __devinit snd_emu10k1_init_mono_onoff_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval)
......@@ -1252,12 +1233,14 @@ static void __devinit snd_emu10k1_init_stereo_onoff_control(emu10k1_fx8010_contr
* initial DSP configuration for Audigy
*/
#define A_GPR_ACCU 0xd6
static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu)
{
int err, i, gpr, tmp, playback, capture, nctl;
int err, i, z, gpr, tmp, playback, capture, nctl;
u32 ptr;
emu10k1_fx8010_code_t *icode;
emu10k1_fx8010_control_gpr_t *controls;
emu10k1_fx8010_control_gpr_t *controls, *ctl;
mm_segment_t seg;
spin_lock_init(&emu->fx8010.irq_lock);
......@@ -1269,7 +1252,7 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu)
kfree(icode);
return -ENOMEM;
}
/* clear free GPRs */
for (i = 0; i < 256; i++)
set_bit(i, icode->gpr_valid);
......@@ -1278,10 +1261,10 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu)
ptr = 0;
nctl = 0;
playback = 10;
capture = playback + 10; /* we reserve 10 voices */
capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
gpr = capture + 10;
tmp = 0x80;
tmp = 0x88;
/* stop FX processor */
snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
......@@ -1422,21 +1405,111 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
{A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
#define _A_SWITCH(icode, ptr, dst, src, sw) \
A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
#define A_SWITCH(icode, ptr, dst, src, sw) \
_A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
#define _A_SWITCH_NEG(icode, ptr, dst, src) \
A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
#define A_SWITCH_NEG(icode, ptr, dst, src) \
_A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
/*
* Process tone control
*/
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), A_GPR(playback + 2), A_C_00000000, A_C_00000000); /* rear left */
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */
ctl = &controls[nctl + 0];
ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strcpy(ctl->id.name, "Tone Control - Bass");
ctl->vcount = 2;
ctl->count = 10;
ctl->min = 0;
ctl->max = 40;
ctl->value[0] = ctl->value[1] = 20;
ctl->translation = EMU10K1_GRP_TRANSLATION_BASS;
ctl = &controls[nctl + 1];
ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strcpy(ctl->id.name, "Tone Control - Treble");
ctl->vcount = 2;
ctl->count = 10;
ctl->min = 0;
ctl->max = 40;
ctl->value[0] = ctl->value[1] = 20;
ctl->translation = EMU10K1_GRP_TRANSLATION_TREBLE;
#define BASS_GPR 0x8c
#define TREBLE_GPR 0x96
for (z = 0; z < 5; z++) {
int j;
for (j = 0; j < 2; j++) {
controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
}
}
for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
int j, k, l, d;
for (j = 0; j < 2; j++) { /* left/right */
k = 0xb0 + (z * 8) + (j * 4);
l = 0xe0 + (z * 8) + (j * 4);
d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
if (z == 2) /* center */
break;
}
}
nctl += 2;
#undef BASS_GPR
#undef TREBLE_GPR
for (z = 0; z < 6; z++) {
A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
}
snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
gpr += 2;
/* digital outputs */
A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback);
A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2);
A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4);
A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5);
A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
/* analog speakers */
//A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback);
A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback);
A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2);
A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4);
A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5);
//A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
/* headphone */
A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback);
A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
/* ADC buffer */
A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
......@@ -1561,7 +1634,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
tmp = 0x88; /* we need 4 temporary GPR */
/* from 0x8c to 0xff is the area for tone control */
/* stop FX processor */
snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
......@@ -1608,7 +1681,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
icode->gpr_map[gpr + 12] = 0;
/* if the trigger flag is not set, skip */
/* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
/* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
/* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
/* if the running flag is set, we're running */
/* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
......
......@@ -1508,12 +1508,16 @@ static struct _ac97_ali_rate_regs {
{ ALID_SPDIFIN, { 0, 0, 0 }, -1 },
};
static struct ac97_quirk ac97_quirks[] = {
{ 0x1028, 0x0126, "Dell Optiplex GX260", AC97_TUNE_HP_ONLY },
{ } /* terminator */
};
static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
{
ac97_t ac97, *x97;
ichdev_t *ichdev;
int err, i, channels = 2, codecs;
int err, i, num, channels = 2, codecs, _codecs;
unsigned int glob_sta = 0;
for (i = 0; i <= ICHD_LAST; i++) {
......@@ -1589,6 +1593,7 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0)
return err;
chip->ac97[0] = x97;
snd_ac97_tune_hardware(chip->ac97[0], chip->pci, ac97_quirks);
chip->ichd[ICHD_PCMOUT].ac97 = x97;
chip->ichd[ICHD_PCMIN].ac97 = x97;
if (x97->ext_id & AC97_EI_VRM)
......@@ -1604,20 +1609,20 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 0);
/* AnalogDevices CNR boards uses special codec chaining */
/* skip standard test method for secondary codecs in this case */
if (x97->flags & AC97_AD_MULTI) {
if (x97->flags & AC97_AD_MULTI)
codecs = 1;
goto __skip_secondary;
}
if (codecs < 2)
goto __skip_secondary;
for (i = 1; i < codecs; i++) {
ac97.num = i;
for (i = 1, num = 1, _codecs = codecs; num < _codecs; num++) {
ac97.num = num;
if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0) {
snd_printk("Unable to initialize codec #%i [device = %i, GLOB_STA = 0x%x]\n", i, chip->device_type, glob_sta);
codecs = i;
break;
codecs--;
continue;
}
chip->ac97[i] = x97;
chip->ac97[i++] = x97;
if (!ac97_is_audio(x97))
continue;
switch (chip->device_type) {
case DEVICE_INTEL_ICH4:
if (chip->ichd[ICHD_PCM2IN].ac97 == NULL)
......@@ -1656,14 +1661,16 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
}
iputbyte(chip, ICHREG(SDM), tmp);
}
for (i = 0; i < 3; i++) {
if ((x97 = chip->ac97[i]) == NULL)
for (i = 0; i < codecs; i++) {
x97 = chip->ac97[i];
if (!ac97_is_audio(x97))
continue;
if (x97->scaps & AC97_SCAP_SURROUND_DAC)
chip->multi4 = 1;
}
for (i = 0; i < 3 && chip->multi4; i++) {
if ((x97 = chip->ac97[i]) == NULL)
for (i = 0; i < codecs && chip->multi4; i++) {
x97 = chip->ac97[i];
if (!ac97_is_audio(x97))
continue;
if (x97->scaps & AC97_SCAP_CENTER_LFE_DAC)
chip->multi6 = 1;
......@@ -1674,7 +1681,10 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
if (chip->multi4)
goto __6ch;
for ( ; i < codecs; i++) {
if (ac97_is_rev22(x97 = chip->ac97[i])) {
x97 = chip->ac97[i];
if (!ac97_is_audio(x97))
continue;
if (ac97_is_rev22(x97)) {
snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 1);
chip->multi4 = 1;
break;
......@@ -1682,7 +1692,10 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
}
__6ch:
for ( ; i < codecs && chip->multi4; i++) {
if (ac97_is_rev22(x97 = chip->ac97[i])) {
x97 = chip->ac97[i];
if (!ac97_is_audio(x97))
continue;
if (ac97_is_rev22(x97)) {
snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 2);
chip->multi6 = 1;
break;
......@@ -1691,7 +1704,10 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
/* ok, some older codecs might support only AMAP */
if (!chip->multi4) {
for (i = 1; i < codecs; i++) {
if (ac97_can_amap(x97 = chip->ac97[i])) {
x97 = chip->ac97[i];
if (!ac97_is_audio(x97))
continue;
if (ac97_can_amap(x97)) {
if (x97->addr == 1) {
chip->multi4 = 1;
break;
......@@ -1699,7 +1715,9 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
}
}
for ( ; i < codecs && chip->multi4; i++) {
if (ac97_can_amap(x97 = chip->ac97[i])) {
if (!ac97_is_audio(x97))
continue;
if (ac97_can_amap(x97)) {
if (x97->addr == 2) {
chip->multi6 = 1;
break;
......
......@@ -42,6 +42,7 @@
// ----------------------------------------------------------------------------
#define K1212_DEBUG_LEVEL 0
#define K1212_DEBUG_PRINTK printk
//#define K1212_DEBUG_PRINTK(x...) printk("<0>" x)
// ----------------------------------------------------------------------------
// Record/Play Buffer Allocation Method. If K1212_LARGEALLOC is defined all
......@@ -178,13 +179,21 @@ typedef enum {
#define kAudioChannels (k16BitChannels + k32BitChannels)
#define kPlayBufferFrames 1024
#define K1212_CHANNELS 16
#define K1212_ANALOG_CHANNELS 2
#define K1212_SPDIF_CHANNELS 2
#define K1212_ADAT_CHANNELS 8
#define K1212_CHANNELS (K1212_ADAT_CHANNELS + K1212_ANALOG_CHANNELS)
#define K1212_MIN_CHANNELS 1
#define K1212_MAX_CHANNELS K1212_CHANNELS
#define K1212_FRAME_SIZE (sizeof(KorgAudioFrame))
#define K1212_MAX_SAMPLES (kPlayBufferFrames*kNumBuffers)
#define K1212_PERIODS (K1212_BUF_SIZE/K1212_BLOCK_SIZE)
#define K1212_PERIOD_BYTES (K1212_BLOCK_SIZE)
#define K1212_BLOCK_SIZE (K1212_FRAME_SIZE*kPlayBufferFrames)
#define K1212_BUF_SIZE (K1212_BLOCK_SIZE*kNumBuffers)
#define K1212_PERIODS (kNumBuffers)
#define K1212_PERIOD_BYTES (K1212_FRAME_SIZE*kPlayBufferFrames)
#define K1212_BUF_SIZE (K1212_PERIOD_BYTES*kNumBuffers)
#define K1212_ANALOG_BUF_SIZE (K1212_ANALOG_CHANNELS * 2 * kPlayBufferFrames * kNumBuffers)
#define K1212_SPDIF_BUF_SIZE (K1212_SPDIF_CHANNELS * 3 * kPlayBufferFrames * kNumBuffers)
#define K1212_ADAT_BUF_SIZE (K1212_ADAT_CHANNELS * 2 * kPlayBufferFrames * kNumBuffers)
#define K1212_MAX_BUF_SIZE (K1212_ANALOG_BUF_SIZE + K1212_ADAT_BUF_SIZE)
#define k1212MinADCSens 0x7f
#define k1212MaxADCSens 0x00
......@@ -314,9 +323,9 @@ typedef struct SensBits {
} SensBits;
struct _snd_korg1212 {
struct pci_dev *pci;
snd_card_t *card;
snd_pcm_t *pcm16;
struct pci_dev *pci;
snd_pcm_t *pcm;
int irq;
spinlock_t lock;
......@@ -362,9 +371,9 @@ struct _snd_korg1212 {
u16 * sensRegPtr; // address of the sensitivity setting register
u32 * idRegPtr; // address of the device and vendor ID registers
size_t periodsize;
size_t currentBuffer;
int channels;
int currentBuffer;
snd_pcm_substream_t *playback_substream;
snd_pcm_substream_t *capture_substream;
......@@ -383,6 +392,11 @@ struct _snd_korg1212 {
u16 leftADCInSens; // ADC left channel input sensitivity
u16 rightADCInSens; // ADC right channel input sensitivity
int opencnt; // Open/Close count
int setcnt; // SetupForPlay count
int playcnt; // TriggerPlay count
};
MODULE_DESCRIPTION("korg1212");
......@@ -465,7 +479,6 @@ u16 ClockSourceSelector[] = {0x8000, // selects source as ADAT at 44.1 kHz
static snd_korg1212rc rc;
MODULE_DEVICE_TABLE(pci, snd_korg1212_ids);
typedef union swap_u32 { unsigned char c[4]; u32 i; } swap_u32;
......@@ -521,11 +534,6 @@ static u32 EndianSwap(u32 swappee)
#endif /* not used */
void TickDelay(int time)
{
udelay(time);
}
#define SetBitInWord(theWord,bitPosition) (*theWord) |= (0x0001 << bitPosition)
#define SetBitInDWord(theWord,bitPosition) (*theWord) |= (0x00000001 << bitPosition)
#define ClearBitInWord(theWord,bitPosition) (*theWord) &= ~(0x0001 << bitPosition)
......@@ -536,76 +544,95 @@ static snd_korg1212rc snd_korg1212_Send1212Command(korg1212_t *korg1212, korg121
{
u32 retryCount;
u16 mailBox3Lo;
snd_korg1212rc rc = K1212_CMDRET_Success;
if (!korg1212->outDoorbellPtr) {
#if K1212_DEBUG_LEVEL > 1
K1212_DEBUG_PRINTK("K1212_DEBUG: CardUninitialized\n");
#endif
return K1212_CMDRET_CardUninitialized;
}
if (korg1212->outDoorbellPtr) {
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- 0x%08x 0x%08x [%s]\n", doorbellVal, mailBox0Val, stateName[korg1212->cardState]);
#endif
for (retryCount = 0; retryCount < MAX_COMMAND_RETRIES; retryCount++) {
writel(mailBox3Val, korg1212->mailbox3Ptr);
writel(mailBox2Val, korg1212->mailbox2Ptr);
writel(mailBox1Val, korg1212->mailbox1Ptr);
writel(mailBox0Val, korg1212->mailbox0Ptr);
writel(doorbellVal, korg1212->outDoorbellPtr); // interrupt the card
// --------------------------------------------------------------
// the reboot command will not give an acknowledgement.
// --------------------------------------------------------------
switch (doorbellVal) {
case K1212_DB_RebootCard:
case K1212_DB_BootFromDSPPage4:
case K1212_DB_StartDSPDownload:
return K1212_CMDRET_Success;
default:
break;
}
K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- 0x%08x 0x%08x [%s]\n", doorbellVal, mailBox0Val, stateName[korg1212->cardState]);
#endif
for (retryCount = 0; retryCount < MAX_COMMAND_RETRIES; retryCount++) {
writel(mailBox3Val, korg1212->mailbox3Ptr);
writel(mailBox2Val, korg1212->mailbox2Ptr);
writel(mailBox1Val, korg1212->mailbox1Ptr);
writel(mailBox0Val, korg1212->mailbox0Ptr);
writel(doorbellVal, korg1212->outDoorbellPtr); // interrupt the card
// --------------------------------------------------------------
// the reboot command will not give an acknowledgement.
// --------------------------------------------------------------
if ( doorbellVal == K1212_DB_RebootCard ||
doorbellVal == K1212_DB_BootFromDSPPage4 ||
doorbellVal == K1212_DB_StartDSPDownload ) {
rc = K1212_CMDRET_Success;
break;
}
// --------------------------------------------------------------
// See if the card acknowledged the command. Wait a bit, then
// read in the low word of mailbox3. If the MSB is set and the
// low byte is equal to the doorbell value, then it ack'd.
// --------------------------------------------------------------
TickDelay(COMMAND_ACK_DELAY);
mailBox3Lo = readl(korg1212->mailbox3Ptr);
if (mailBox3Lo & COMMAND_ACK_MASK) {
if ((mailBox3Lo & DOORBELL_VAL_MASK) == (doorbellVal & DOORBELL_VAL_MASK)) {
korg1212->cmdRetryCount += retryCount;
return K1212_CMDRET_Success;
}
// --------------------------------------------------------------
// See if the card acknowledged the command. Wait a bit, then
// read in the low word of mailbox3. If the MSB is set and the
// low byte is equal to the doorbell value, then it ack'd.
// --------------------------------------------------------------
udelay(COMMAND_ACK_DELAY);
mailBox3Lo = readl(korg1212->mailbox3Ptr);
if (mailBox3Lo & COMMAND_ACK_MASK) {
if ((mailBox3Lo & DOORBELL_VAL_MASK) == (doorbellVal & DOORBELL_VAL_MASK)) {
#if K1212_DEBUG_LEVEL > 1
K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- Success\n");
#endif
rc = K1212_CMDRET_Success;
break;
}
}
korg1212->cmdRetryCount += retryCount;
return K1212_CMDRET_NoAckFromCard;
} else {
return K1212_CMDRET_CardUninitialized;
}
}
korg1212->cmdRetryCount += retryCount;
if (retryCount >= MAX_COMMAND_RETRIES) {
#if K1212_DEBUG_LEVEL > 1
K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- NoAckFromCard\n");
#endif
rc = K1212_CMDRET_NoAckFromCard;
}
return rc;
}
static void snd_korg1212_WaitForCardStopAck(korg1212_t *korg1212)
{
unsigned long endtime = jiffies + 20 * HZ;
u32 endtime = jiffies + 2 * HZ;
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: WaitForCardStopAck [%s]\n", stateName[korg1212->cardState]);
K1212_DEBUG_PRINTK("K1212_DEBUG: WaitForCardStopAck.in [%s] %lu %lu\n", stateName[korg1212->cardState], jiffies, korg1212->inIRQ);
#endif
if (korg1212->inIRQ)
return;
do {
if (readl(&korg1212->sharedBufferPtr->cardCommand) == 0)
if (readl(&korg1212->sharedBufferPtr->cardCommand) == 0) {
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: WaitForCardStopAck.out [%s] %lu %lu\n", stateName[korg1212->cardState], jiffies, korg1212->inIRQ);
#endif
return;
}
if (!korg1212->inIRQ)
schedule();
} while (time_before(jiffies, endtime));
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: WaitForCardStopAck.out TO [%s] %lu %lu\n", stateName[korg1212->cardState], jiffies, korg1212->inIRQ);
#endif
writel(0, &korg1212->sharedBufferPtr->cardCommand);
}
static void snd_korg1212_TurnOnIdleMonitor(korg1212_t *korg1212)
{
TickDelay(INTERCOMMAND_DELAY);
udelay(INTERCOMMAND_DELAY);
korg1212->idleMonitorOn = 1;
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
K1212_MODE_MonitorOn, 0, 0, 0);
......@@ -641,18 +668,22 @@ static void snd_korg1212_setCardState(korg1212_t * korg1212, CardState csState)
static int snd_korg1212_OpenCard(korg1212_t * korg1212)
{
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s]\n", stateName[korg1212->cardState]);
K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt);
#endif
snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
if (korg1212->opencnt++ == 0)
snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
return 1;
}
static int snd_korg1212_CloseCard(korg1212_t * korg1212)
{
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s]\n", stateName[korg1212->cardState]);
K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt);
#endif
if (--(korg1212->opencnt))
return 0;
if (korg1212->cardState == K1212_STATE_SETUP) {
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
K1212_MODE_StopPlay, 0, 0, 0);
......@@ -676,9 +707,12 @@ static int snd_korg1212_CloseCard(korg1212_t * korg1212)
static int snd_korg1212_SetupForPlay(korg1212_t * korg1212)
{
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: SetupForPlay [%s]\n", stateName[korg1212->cardState]);
K1212_DEBUG_PRINTK("K1212_DEBUG: SetupForPlay [%s] %d\n", stateName[korg1212->cardState], korg1212->setcnt);
#endif
if (korg1212->setcnt++)
return 0;
snd_korg1212_setCardState(korg1212, K1212_STATE_SETUP);
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
K1212_MODE_SetupPlay, 0, 0, 0);
......@@ -687,17 +721,20 @@ static int snd_korg1212_SetupForPlay(korg1212_t * korg1212)
if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: SetupForPlay - RC = %d [%s]\n", rc, stateName[korg1212->cardState]);
#endif
if (rc != K1212_CMDRET_Success) {
return 0;
return 1;
}
return 1;
return 0;
}
static int snd_korg1212_TriggerPlay(korg1212_t * korg1212)
{
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: TriggerPlay [%s]\n", stateName[korg1212->cardState]);
K1212_DEBUG_PRINTK("K1212_DEBUG: TriggerPlay [%s] %d\n", stateName[korg1212->cardState], korg1212->playcnt);
#endif
if (korg1212->playcnt++)
return 0;
snd_korg1212_setCardState(korg1212, K1212_STATE_PLAYING);
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_TriggerPlay, 0, 0, 0, 0);
......@@ -706,23 +743,28 @@ static int snd_korg1212_TriggerPlay(korg1212_t * korg1212)
#endif
if (rc != K1212_CMDRET_Success) {
return 0;
return 1;
}
return 1;
return 0;
}
static int snd_korg1212_StopPlay(korg1212_t * korg1212)
{
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: StopPlay [%s]\n", stateName[korg1212->cardState]);
K1212_DEBUG_PRINTK("K1212_DEBUG: StopPlay [%s] %d\n", stateName[korg1212->cardState], korg1212->playcnt);
#endif
if (--(korg1212->playcnt))
return 0;
korg1212->setcnt = 0;
if (korg1212->cardState != K1212_STATE_ERRORSTOP) {
writel(0xffffffff, &korg1212->sharedBufferPtr->cardCommand);
snd_korg1212_WaitForCardStopAck(korg1212);
}
snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
return 1;
return 0;
}
static void snd_korg1212_EnableCardInterrupts(korg1212_t * korg1212)
......@@ -802,7 +844,7 @@ static int snd_korg1212_SetRate(korg1212_t *korg1212, int rate)
korg1212->clkSrcRate = parm;
korg1212->clkRate = rate;
TickDelay(INTERCOMMAND_DELAY);
udelay(INTERCOMMAND_DELAY);
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SetClockSourceRate,
ClockSourceSelector[korg1212->clkSrcRate],
0, 0, 0);
......@@ -869,7 +911,7 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
// flag. Also, clear out mailbox 3, so we don't lockup.
// ----------------------------------------------------------------------------
writel(0, korg1212->mailbox3Ptr);
TickDelay(LOADSHIFT_DELAY);
udelay(LOADSHIFT_DELAY);
// ----------------------------------------------------------------------------
// determine whether we are running a 48K or 44.1K clock. This info is used
......@@ -910,7 +952,7 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
ClearBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS);
ClearBitInWord(&controlValue, SET_SENS_DATA_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // load/shift goes low
TickDelay(LOADSHIFT_DELAY);
udelay(LOADSHIFT_DELAY);
for (bitPosition = 15; bitPosition >= 0; bitPosition--) { // for all the bits
if (channel == 0) {
......@@ -929,10 +971,10 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes low
TickDelay(SENSCLKPULSE_WIDTH);
udelay(SENSCLKPULSE_WIDTH);
SetBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes high
TickDelay(SENSCLKPULSE_WIDTH);
udelay(SENSCLKPULSE_WIDTH);
}
// ----------------------------------------------------------------------------
......@@ -943,19 +985,19 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
SetBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // load shift goes high - clk low
TickDelay(SENSCLKPULSE_WIDTH);
udelay(SENSCLKPULSE_WIDTH);
if (clkIs48K)
SetBitInWord(&controlValue, SET_SENS_DATA_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // set/clear data bit
TickDelay(ONE_RTC_TICK);
udelay(ONE_RTC_TICK);
SetBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes high
TickDelay(SENSCLKPULSE_WIDTH);
udelay(SENSCLKPULSE_WIDTH);
ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes low
TickDelay(SENSCLKPULSE_WIDTH);
udelay(SENSCLKPULSE_WIDTH);
}
// ----------------------------------------------------------------------------
......@@ -963,7 +1005,7 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
// Also, if the card was in monitor mode, restore it.
// ----------------------------------------------------------------------------
for (count = 0; count < 10; count++)
TickDelay(SENSCLKPULSE_WIDTH);
udelay(SENSCLKPULSE_WIDTH);
if (monModeSet) {
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
......@@ -1011,7 +1053,7 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212)
if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: Configure Buffer Memory - RC = %d [%s]\n", rc, stateName[korg1212->cardState]);
#endif
TickDelay(INTERCOMMAND_DELAY);
udelay(INTERCOMMAND_DELAY);
rc = snd_korg1212_Send1212Command(korg1212,
K1212_DB_ConfigureMiscMemory,
......@@ -1029,7 +1071,7 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212)
// --------------------------------------------------------------------------------
// Initialize the routing and volume tables, then update the card's state.
// --------------------------------------------------------------------------------
TickDelay(INTERCOMMAND_DELAY);
udelay(INTERCOMMAND_DELAY);
for (channel = 0; channel < kAudioChannels; channel++) {
korg1212->sharedBufferPtr->volumeData[channel] = k1212MaxVolume;
......@@ -1039,7 +1081,7 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212)
snd_korg1212_WriteADCSensitivity(korg1212);
TickDelay(INTERCOMMAND_DELAY);
udelay(INTERCOMMAND_DELAY);
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SetClockSourceRate,
ClockSourceSelector[korg1212->clkSrcRate],
0, 0, 0);
......@@ -1056,7 +1098,6 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212)
wake_up_interruptible(&korg1212->wait);
}
static void snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
u32 doorbellValue;
......@@ -1092,10 +1133,11 @@ static void snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs)
// an error occurred - stop the card
// ------------------------------------------------------------------------
case K1212_ISRCODE_DMAERROR:
#if K1212_DEBUG_LEVEL > 0
#if K1212_DEBUG_LEVEL > 1
K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DMAE count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]);
#endif
writel(0, &korg1212->sharedBufferPtr->cardCommand);
snd_korg1212_setCardState(korg1212, K1212_STATE_ERRORSTOP);
break;
// ------------------------------------------------------------------------
......@@ -1103,14 +1145,14 @@ static void snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs)
// the semaphore in case someone is waiting for this.
// ------------------------------------------------------------------------
case K1212_ISRCODE_CARDSTOPPED:
#if K1212_DEBUG_LEVEL > 0
#if K1212_DEBUG_LEVEL > 1
K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ CSTP count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]);
#endif
writel(0, &korg1212->sharedBufferPtr->cardCommand);
break;
default:
#if K1212_DEBUG_LEVEL > 1
#if K1212_DEBUG_LEVEL > 3
K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DFLT count - %ld, %x, cpos=%d [%s].\n", korg1212->irqcount, doorbellValue,
korg1212->currentBuffer, stateName[korg1212->cardState]);
#endif
......@@ -1170,7 +1212,7 @@ static int snd_korg1212_downloadDSPCode(korg1212_t *korg1212)
static snd_pcm_hardware_t snd_korg1212_playback_info =
{
.info = (SNDRV_PCM_INFO_MMAP |
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
......@@ -1178,11 +1220,11 @@ static snd_pcm_hardware_t snd_korg1212_playback_info =
SNDRV_PCM_RATE_48000),
.rate_min = 44100,
.rate_max = 48000,
.channels_min = K1212_CHANNELS,
.channels_max = K1212_CHANNELS,
.buffer_bytes_max = K1212_BUF_SIZE,
.period_bytes_min = K1212_PERIOD_BYTES,
.period_bytes_max = K1212_PERIOD_BYTES,
.channels_min = K1212_MIN_CHANNELS,
.channels_max = K1212_MAX_CHANNELS,
.buffer_bytes_max = K1212_MAX_BUF_SIZE,
.period_bytes_min = K1212_MIN_CHANNELS * 2 * kPlayBufferFrames,
.period_bytes_max = K1212_MAX_CHANNELS * 2 * kPlayBufferFrames,
.periods_min = K1212_PERIODS,
.periods_max = K1212_PERIODS,
.fifo_size = 0,
......@@ -1190,7 +1232,7 @@ static snd_pcm_hardware_t snd_korg1212_playback_info =
static snd_pcm_hardware_t snd_korg1212_capture_info =
{
.info = (SNDRV_PCM_INFO_MMAP |
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
......@@ -1198,36 +1240,116 @@ static snd_pcm_hardware_t snd_korg1212_capture_info =
SNDRV_PCM_RATE_48000),
.rate_min = 44100,
.rate_max = 48000,
.channels_min = K1212_CHANNELS,
.channels_max = K1212_CHANNELS,
.buffer_bytes_max = K1212_BUF_SIZE,
.period_bytes_min = K1212_PERIOD_BYTES,
.period_bytes_max = K1212_PERIOD_BYTES,
.channels_min = K1212_MIN_CHANNELS,
.channels_max = K1212_MAX_CHANNELS,
.buffer_bytes_max = K1212_MAX_BUF_SIZE,
.period_bytes_min = K1212_MIN_CHANNELS * 2 * kPlayBufferFrames,
.period_bytes_max = K1212_MAX_CHANNELS * 2 * kPlayBufferFrames,
.periods_min = K1212_PERIODS,
.periods_max = K1212_PERIODS,
.fifo_size = 0,
};
static void snd_korg1212_free_pcm(snd_pcm_t *pcm)
static int snd_korg1212_silence(korg1212_t *korg1212, int pos, int count, int offset, int size)
{
korg1212_t *korg1212 = (korg1212_t *) pcm->private_data;
KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos;
int i;
#if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_silence pos=%d offset=%d size=%d count=%d\n", pos, offset, size, count);
#endif
snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
for (i=0; i < count; i++) {
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_free_pcm [%s]\n", stateName[korg1212->cardState]);
if ( (void *) dst < (void *) korg1212->playDataBufsPtr ||
(void *) dst > (void *) korg1212->playDataBufsPtr[8].bufferData ) {
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_silence KERNEL EFAULT dst=%p iter=%d\n", dst, i);
return -EFAULT;
}
#endif
memset((void*) dst + offset, 0, size);
dst++;
}
return 0;
}
static int snd_korg1212_copy_to(korg1212_t *korg1212, void *dst, int pos, int count, int offset, int size)
{
KorgAudioFrame * src = korg1212->recordDataBufsPtr[0].bufferData + pos;
int i, rc;
#if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_to pos=%d offset=%d size=%d\n", pos, offset, size);
#endif
snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
korg1212->pcm16 = NULL;
for (i=0; i < count; i++) {
#if K1212_DEBUG_LEVEL > 0
if ( (void *) src < (void *) korg1212->recordDataBufsPtr ||
(void *) src > (void *) korg1212->recordDataBufsPtr[8].bufferData ) {
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_to KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst, i);
return -EFAULT;
}
#endif
rc = copy_to_user((void*) dst + offset, src, size);
if (rc) {
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_to USER EFAULT src=%p dst=%p iter=%d\n", src, dst, i);
#endif
return -EFAULT;
}
src++;
dst += size;
}
return 0;
}
static unsigned int period_bytes[] = { K1212_PERIOD_BYTES };
static int snd_korg1212_copy_from(korg1212_t *korg1212, void *src, int pos, int count, int offset, int size)
{
KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos;
int i, rc;
#define PERIOD_BYTES sizeof(period_bytes) / sizeof(period_bytes[0])
#if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_from pos=%d offset=%d size=%d count=%d\n", pos, offset, size, count);
#endif
static snd_pcm_hw_constraint_list_t hw_constraints_period_bytes = {
.count = PERIOD_BYTES,
.list = period_bytes,
.mask = 0
};
snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
for (i=0; i < count; i++) {
#if K1212_DEBUG_LEVEL > 0
if ( (void *) dst < (void *) korg1212->playDataBufsPtr ||
(void *) dst > (void *) korg1212->playDataBufsPtr[8].bufferData ) {
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_from KERNEL EFAULT, src=%p dst=%p iter=%d\n", src, dst, i);
return -EFAULT;
}
#endif
rc = copy_from_user((void*) dst + offset, src, size);
if (rc) {
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_copy_from USER EFAULT src=%p dst=%p iter=%d\n", src, dst, i);
#endif
return -EFAULT;
}
dst++;
src += size;
}
return 0;
}
static void snd_korg1212_free_pcm(snd_pcm_t *pcm)
{
korg1212_t *korg1212 = (korg1212_t *) pcm->private_data;
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_free_pcm [%s]\n", stateName[korg1212->cardState]);
#endif
korg1212->pcm = NULL;
}
static int snd_korg1212_playback_open(snd_pcm_substream_t *substream)
{
......@@ -1239,11 +1361,11 @@ static int snd_korg1212_playback_open(snd_pcm_substream_t *substream)
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_open [%s]\n", stateName[korg1212->cardState]);
#endif
spin_lock_irqsave(&korg1212->lock, flags);
snd_pcm_set_sync(substream); // ???
snd_korg1212_OpenCard(korg1212);
spin_lock_irqsave(&korg1212->lock, flags);
snd_pcm_set_sync(substream); // ???
snd_korg1212_OpenCard(korg1212);
runtime->hw = snd_korg1212_playback_info;
runtime->dma_area = (char *) korg1212->playDataBufsPtr;
......@@ -1251,14 +1373,15 @@ static int snd_korg1212_playback_open(snd_pcm_substream_t *substream)
korg1212->playback_substream = substream;
korg1212->periodsize = K1212_PERIODS;
korg1212->channels = K1212_CHANNELS;
spin_unlock_irqrestore(&korg1212->lock, flags);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, K1212_BUF_SIZE, K1212_BUF_SIZE);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, kPlayBufferFrames, kPlayBufferFrames);
return 0;
}
static int snd_korg1212_capture_open(snd_pcm_substream_t *substream)
{
unsigned long flags;
......@@ -1269,11 +1392,11 @@ static int snd_korg1212_capture_open(snd_pcm_substream_t *substream)
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_open [%s]\n", stateName[korg1212->cardState]);
#endif
spin_lock_irqsave(&korg1212->lock, flags);
snd_pcm_set_sync(substream); // ???
snd_korg1212_OpenCard(korg1212);
spin_lock_irqsave(&korg1212->lock, flags);
snd_pcm_set_sync(substream); // ???
snd_korg1212_OpenCard(korg1212);
runtime->hw = snd_korg1212_capture_info;
runtime->dma_area = (char *) korg1212->recordDataBufsPtr;
......@@ -1281,11 +1404,11 @@ static int snd_korg1212_capture_open(snd_pcm_substream_t *substream)
korg1212->capture_substream = substream;
korg1212->periodsize = K1212_PERIODS;
korg1212->channels = K1212_CHANNELS;
spin_unlock_irqrestore(&korg1212->lock, flags);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, K1212_BUF_SIZE, K1212_BUF_SIZE);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, kPlayBufferFrames, kPlayBufferFrames);
return 0;
}
......@@ -1298,12 +1421,14 @@ static int snd_korg1212_playback_close(snd_pcm_substream_t *substream)
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_close [%s]\n", stateName[korg1212->cardState]);
#endif
snd_korg1212_silence(korg1212, 0, K1212_MAX_SAMPLES, 0, korg1212->channels * 2);
spin_lock_irqsave(&korg1212->lock, flags);
korg1212->playback_substream = NULL;
korg1212->periodsize = 0;
snd_korg1212_CloseCard(korg1212);
snd_korg1212_CloseCard(korg1212);
spin_unlock_irqrestore(&korg1212->lock, flags);
return 0;
......@@ -1323,43 +1448,28 @@ static int snd_korg1212_capture_close(snd_pcm_substream_t *substream)
korg1212->capture_substream = NULL;
korg1212->periodsize = 0;
snd_korg1212_CloseCard(korg1212);
snd_korg1212_CloseCard(korg1212);
spin_unlock_irqrestore(&korg1212->lock, flags);
return 0;
}
static int snd_korg1212_channel_info(snd_pcm_substream_t *substream,
snd_pcm_channel_info_t *info)
{
int chn = info->channel;
// snd_assert(info->channel < kAudioChannels + 1, return -EINVAL);
info->offset = 0;
// if (chn < k16BitChannels) {
info->first = chn * 16;
// } else {
// info->first = k16BitChannels * 16 + (chn - k16BitChannels - 1) * 32;
// }
info->step = sizeof(KorgAudioFrame) * 8;
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_channel_info %d:, offset=%ld, first=%d, step=%d\n", chn, info->offset, info->first, info->step);
#endif
return 0;
}
static int snd_korg1212_ioctl(snd_pcm_substream_t *substream,
unsigned int cmd, void *arg)
{
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_ioctl: cmd=%d\n", cmd);
#endif
if (cmd == SNDRV_PCM_IOCTL1_CHANNEL_INFO ) {
snd_pcm_channel_info_t *info = arg;
return snd_korg1212_channel_info(substream, info);
info->offset = 0;
info->first = info->channel * 16;
info->step = 256;
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: channel_info %d:, offset=%ld, first=%d, step=%d\n", info->channel, info->offset, info->first, info->step);
#endif
return 0;
}
return snd_pcm_lib_ioctl(substream, cmd, arg);
......@@ -1381,13 +1491,14 @@ static int snd_korg1212_hw_params(snd_pcm_substream_t *substream,
spin_unlock_irqrestore(&korg1212->lock, flags);
return err;
}
/*
if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) {
spin_unlock_irqrestore(&korg1212->lock, flags);
return -EINVAL;
}
korg1212->periodsize = K1212_BLOCK_SIZE;
*/
korg1212->channels = params_channels(params);
korg1212->periodsize = K1212_PERIOD_BYTES;
spin_unlock_irqrestore(&korg1212->lock, flags);
......@@ -1398,6 +1509,7 @@ static int snd_korg1212_prepare(snd_pcm_substream_t *substream)
{
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
unsigned long flags;
int rc;
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_prepare [%s]\n", stateName[korg1212->cardState]);
......@@ -1405,18 +1517,19 @@ static int snd_korg1212_prepare(snd_pcm_substream_t *substream)
spin_lock_irqsave(&korg1212->lock, flags);
snd_korg1212_SetupForPlay(korg1212);
korg1212->currentBuffer = -1;
rc = snd_korg1212_SetupForPlay(korg1212);
korg1212->currentBuffer = 0;
spin_unlock_irqrestore(&korg1212->lock, flags);
return 0;
return rc ? -EINVAL : 0;
}
static int snd_korg1212_trigger(snd_pcm_substream_t *substream,
int cmd)
{
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
int rc;
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger [%s] cmd=%d\n", stateName[korg1212->cardState], cmd);
......@@ -1424,72 +1537,82 @@ static int snd_korg1212_trigger(snd_pcm_substream_t *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
korg1212->running = 1;
snd_korg1212_TriggerPlay(korg1212);
/*
if (korg1212->running) {
#if K1212_DEBUG_LEVEL > 1
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger: Already running?\n");
#endif
break;
}
*/
korg1212->running++;
rc = snd_korg1212_TriggerPlay(korg1212);
break;
case SNDRV_PCM_TRIGGER_STOP:
korg1212->running = 0;
snd_korg1212_StopPlay(korg1212);
/*
if (!korg1212->running) {
#if K1212_DEBUG_LEVEL > 1
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger: Already stopped?\n");
#endif
break;
}
*/
korg1212->running--;
rc = snd_korg1212_StopPlay(korg1212);
break;
default:
return -EINVAL;
rc = 1;
break;
}
return 0;
return rc ? -EINVAL : 0;
}
static snd_pcm_uframes_t snd_korg1212_pointer(snd_pcm_substream_t *substream)
static snd_pcm_uframes_t snd_korg1212_playback_pointer(snd_pcm_substream_t *substream)
{
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
snd_pcm_uframes_t pos;
if (korg1212->currentBuffer < 0)
return 0;
pos = korg1212->currentBuffer * kPlayBufferFrames;
#if K1212_DEBUG_LEVEL > 1
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_pointer [%s] %ld\n", stateName[korg1212->cardState], pos);
#if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_pointer [%s] %ld\n",
stateName[korg1212->cardState], pos);
#endif
return pos;
}
static int snd_korg1212_playback_copy(snd_pcm_substream_t *substream,
int channel, /* not used (interleaved data) */
snd_pcm_uframes_t pos,
void *src,
snd_pcm_uframes_t count)
static snd_pcm_uframes_t snd_korg1212_capture_pointer(snd_pcm_substream_t *substream)
{
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos;
snd_pcm_uframes_t pos;
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
pos = korg1212->currentBuffer * kPlayBufferFrames;
#if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_pointer [%s] %ld\n",
stateName[korg1212->cardState], pos);
#endif
snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
return copy_from_user(dst, src, count * K1212_FRAME_SIZE) ? -EFAULT : 0;
return pos;
}
static int snd_korg1212_capture_copy(snd_pcm_substream_t *substream,
static int snd_korg1212_playback_copy(snd_pcm_substream_t *substream,
int channel, /* not used (interleaved data) */
snd_pcm_uframes_t pos,
void *dst,
void *src,
snd_pcm_uframes_t count)
{
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
KorgAudioFrame * src = korg1212->recordDataBufsPtr[0].bufferData + pos;
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
#if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
#endif
return snd_korg1212_copy_from(korg1212, src, pos, count, 0, korg1212->channels * 2);
snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
return copy_to_user(dst, src, count * K1212_FRAME_SIZE) ? -EFAULT : 0;
}
static int snd_korg1212_playback_silence(snd_pcm_substream_t *substream,
......@@ -1498,17 +1621,27 @@ static int snd_korg1212_playback_silence(snd_pcm_substream_t *substream,
snd_pcm_uframes_t count)
{
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos;
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_silence [%s]\n", stateName[korg1212->cardState]);
#endif
snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL);
return snd_korg1212_silence(korg1212, pos, count, 0, korg1212->channels * 2);
}
memset(dst, 0, count * K1212_FRAME_SIZE);
static int snd_korg1212_capture_copy(snd_pcm_substream_t *substream,
int channel, /* not used (interleaved data) */
snd_pcm_uframes_t pos,
void *dst,
snd_pcm_uframes_t count)
{
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
return 0;
#if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
#endif
return snd_korg1212_copy_to(korg1212, dst, pos, count, 0, korg1212->channels * 2);
}
static snd_pcm_ops_t snd_korg1212_playback_ops = {
......@@ -1518,7 +1651,7 @@ static snd_pcm_ops_t snd_korg1212_playback_ops = {
.hw_params = snd_korg1212_hw_params,
.prepare = snd_korg1212_prepare,
.trigger = snd_korg1212_trigger,
.pointer = snd_korg1212_pointer,
.pointer = snd_korg1212_playback_pointer,
.copy = snd_korg1212_playback_copy,
.silence = snd_korg1212_playback_silence,
};
......@@ -1530,7 +1663,7 @@ static snd_pcm_ops_t snd_korg1212_capture_ops = {
.hw_params = snd_korg1212_hw_params,
.prepare = snd_korg1212_prepare,
.trigger = snd_korg1212_trigger,
.pointer = snd_korg1212_pointer,
.pointer = snd_korg1212_capture_pointer,
.copy = snd_korg1212_capture_copy,
};
......@@ -1555,7 +1688,7 @@ static int snd_korg1212_control_phase_get(snd_kcontrol_t *kcontrol, snd_ctl_elem
u->value.integer.value[0] = korg1212->volumePhase[i];
if (i >= 8)
if (i >= 8)
u->value.integer.value[1] = korg1212->volumePhase[i+1];
spin_unlock_irqrestore(&korg1212->lock, flags);
......@@ -1703,13 +1836,13 @@ static int snd_korg1212_control_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem
i = kcontrol->private_value;
if (u->value.enumerated.item[0] != (unsigned int)korg1212->sharedBufferPtr->volumeData[i]) {
if (u->value.enumerated.item[0] != (unsigned) korg1212->sharedBufferPtr->volumeData[i]) {
korg1212->sharedBufferPtr->routeData[i] = u->value.enumerated.item[0];
change = 1;
}
if (i >= 8) {
if (u->value.enumerated.item[1] != (unsigned int)korg1212->sharedBufferPtr->volumeData[i+1]) {
if (u->value.enumerated.item[1] != (unsigned) korg1212->sharedBufferPtr->volumeData[i+1]) {
korg1212->sharedBufferPtr->routeData[i+1] = u->value.enumerated.item[1];
change = 1;
}
......@@ -1720,7 +1853,7 @@ static int snd_korg1212_control_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem
return change;
}
static int snd_korg1212_control_analog_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
static int snd_korg1212_control_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
......@@ -1729,7 +1862,7 @@ static int snd_korg1212_control_analog_info(snd_kcontrol_t *kcontrol, snd_ctl_el
return 0;
}
static int snd_korg1212_control_analog_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u)
static int snd_korg1212_control_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u)
{
korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol);
unsigned long flags;
......@@ -1744,7 +1877,7 @@ static int snd_korg1212_control_analog_get(snd_kcontrol_t *kcontrol, snd_ctl_ele
return 0;
}
static int snd_korg1212_control_analog_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u)
static int snd_korg1212_control_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u)
{
korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol);
unsigned long flags;
......@@ -1855,9 +1988,9 @@ static snd_kcontrol_new_t snd_korg1212_controls[] = {
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "ADC Attenuation",
.info = snd_korg1212_control_analog_info,
.get = snd_korg1212_control_analog_get,
.put = snd_korg1212_control_analog_put,
.info = snd_korg1212_control_info,
.get = snd_korg1212_control_get,
.put = snd_korg1212_control_put,
}
};
......@@ -1875,7 +2008,7 @@ static void snd_korg1212_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *b
snd_iprintf(buffer, korg1212->card->longname);
snd_iprintf(buffer, " (index #%d)\n", korg1212->card->number + 1);
snd_iprintf(buffer, "\nGeneral settings\n");
snd_iprintf(buffer, " period size: %d bytes\n", K1212_BLOCK_SIZE);
snd_iprintf(buffer, " period size: %d bytes\n", K1212_PERIOD_BYTES);
snd_iprintf(buffer, " clock mode: %s\n", clockSourceName[korg1212->clkSrcRate] );
snd_iprintf(buffer, " left ADC Sens: %d\n", korg1212->leftADCInSens );
snd_iprintf(buffer, " right ADC Sens: %d\n", korg1212->rightADCInSens );
......@@ -1901,19 +2034,132 @@ static void __devinit snd_korg1212_proc_init(korg1212_t *korg1212)
snd_info_set_text_ops(entry, korg1212, snd_korg1212_proc_read);
}
static int __devinit snd_korg1212_create(korg1212_t *korg1212)
static int
snd_korg1212_free(korg1212_t *korg1212)
{
snd_korg1212_TurnOffIdleMonitor(korg1212);
if (korg1212->irq >= 0) {
synchronize_irq(korg1212->irq);
snd_korg1212_DisableCardInterrupts(korg1212);
free_irq(korg1212->irq, (void *)korg1212);
korg1212->irq = -1;
}
if (korg1212->iobase != 0) {
iounmap((void *)korg1212->iobase);
korg1212->iobase = 0;
}
if (korg1212->res_iomem != NULL) {
release_resource(korg1212->res_iomem);
kfree_nocheck(korg1212->res_iomem);
korg1212->res_iomem = NULL;
}
if (korg1212->res_ioport != NULL) {
release_resource(korg1212->res_ioport);
kfree_nocheck(korg1212->res_ioport);
korg1212->res_ioport = NULL;
}
if (korg1212->res_iomem2 != NULL) {
release_resource(korg1212->res_iomem2);
kfree_nocheck(korg1212->res_iomem2);
korg1212->res_iomem2 = NULL;
}
// ----------------------------------------------------
// free up memory resources used for the DSP download.
// ----------------------------------------------------
if (korg1212->dspMemPtr) {
snd_free_pci_pages(korg1212->pci, korg1212->dspCodeSize,
korg1212->dspMemPtr, (dma_addr_t)korg1212->dspMemPhy);
korg1212->dspMemPhy = 0;
korg1212->dspMemPtr = 0;
korg1212->dspCodeSize = 0;
}
#ifndef K1212_LARGEALLOC
// ------------------------------------------------------
// free up memory resources used for the Play/Rec Buffers
// ------------------------------------------------------
if (korg1212->playDataBufsPtr) {
snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
korg1212->playDataBufsPtr, (dma_addr_t)korg1212->PlayDataPhy);
korg1212->PlayDataPhy = 0;
korg1212->playDataBufsPtr = NULL;
}
if (korg1212->recordDataBufsPtr) {
snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
korg1212->recordDataBufsPtr, (dma_addr_t)korg1212->RecDataPhy);
korg1212->RecDataPhy = 0;
korg1212->recordDataBufsPtr = NULL;
}
#endif
// ----------------------------------------------------
// free up memory resources used for the Shared Buffers
// ----------------------------------------------------
if (korg1212->sharedBufferPtr) {
snd_free_pci_pages(korg1212->pci, (u32) sizeof(KorgSharedBuffer),
korg1212->sharedBufferPtr, (dma_addr_t)korg1212->sharedBufferPhy);
korg1212->sharedBufferPhy = 0;
korg1212->sharedBufferPtr = NULL;
}
snd_magic_kfree(korg1212);
return 0;
}
static int snd_korg1212_dev_free(snd_device_t *device)
{
korg1212_t *korg1212 = snd_magic_cast(korg1212_t, device->device_data, return -ENXIO);
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: Freeing device\n");
#endif
return snd_korg1212_free(korg1212);
}
static int __devinit snd_korg1212_create(snd_card_t * card, struct pci_dev *pci,
korg1212_t ** rchip)
{
struct pci_dev *pci = korg1212->pci;
int err;
unsigned int i;
unsigned ioport_size, iomem_size, iomem2_size;
dma_addr_t phys_addr;
korg1212_t * korg1212;
static snd_device_ops_t ops = {
.dev_free = snd_korg1212_dev_free,
};
* rchip = NULL;
if ((err = pci_enable_device(pci)) < 0)
return err;
korg1212 = snd_magic_kcalloc(korg1212_t, 0, GFP_KERNEL);
if (korg1212 == NULL)
return -ENOMEM;
korg1212->card = card;
korg1212->pci = pci;
init_waitqueue_head(&korg1212->wait);
spin_lock_init(&korg1212->lock);
korg1212->irq = -1;
korg1212->clkSource = K1212_CLKIDX_Local;
korg1212->clkRate = 44100;
korg1212->inIRQ = 0;
korg1212->running = 0;
korg1212->opencnt = 0;
korg1212->playcnt = 0;
korg1212->setcnt = 0;
snd_korg1212_setCardState(korg1212, K1212_STATE_UNINITIALIZED);
korg1212->idleMonitorOn = 0;
korg1212->clkSrcRate = K1212_CLKIDX_LocalAt44_1K;
......@@ -1923,9 +2169,6 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
for (i=0; i<kAudioChannels; i++)
korg1212->volumePhase[i] = 0;
if ((err = pci_enable_device(pci)) < 0)
return err;
korg1212->iomem = pci_resource_start(korg1212->pci, 0);
korg1212->ioport = pci_resource_start(korg1212->pci, 1);
korg1212->iomem2 = pci_resource_start(korg1212->pci, 2);
......@@ -1948,27 +2191,27 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->res_iomem = request_mem_region(korg1212->iomem, iomem_size, "korg1212");
if (korg1212->res_iomem == NULL) {
snd_printk("unable to grab region 0x%lx-0x%lx\n",
snd_printk(KERN_ERR "unable to grab region 0x%lx-0x%lx\n",
korg1212->iomem, korg1212->iomem + iomem_size - 1);
return -EBUSY;
}
korg1212->res_ioport = request_region(korg1212->ioport, ioport_size, "korg1212");
if (korg1212->res_ioport == NULL) {
snd_printk("unable to grab region 0x%lx-0x%lx\n",
snd_printk(KERN_ERR "unable to grab region 0x%lx-0x%lx\n",
korg1212->ioport, korg1212->ioport + ioport_size - 1);
return -EBUSY;
}
korg1212->res_iomem2 = request_mem_region(korg1212->iomem2, iomem2_size, "korg1212");
if (korg1212->res_iomem2 == NULL) {
snd_printk("unable to grab region 0x%lx-0x%lx\n",
snd_printk(KERN_ERR "unable to grab region 0x%lx-0x%lx\n",
korg1212->iomem2, korg1212->iomem2 + iomem2_size - 1);
return -EBUSY;
}
if ((korg1212->iobase = (unsigned long) ioremap(korg1212->iomem, iomem_size)) == 0) {
snd_printk("unable to remap memory region 0x%lx-0x%lx\n", korg1212->iobase,
snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", korg1212->iobase,
korg1212->iobase + iomem_size - 1);
return -EBUSY;
}
......@@ -1978,14 +2221,12 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
"korg1212", (void *) korg1212);
if (err) {
snd_printk("unable to grab IRQ %d\n", pci->irq);
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
return -EBUSY;
}
korg1212->irq = pci->irq;
init_waitqueue_head(&korg1212->wait);
spin_lock_init(&korg1212->lock);
pci_set_master(korg1212->pci);
korg1212->statusRegPtr = (u32 *) (korg1212->iobase + STATUS_REG_OFFSET);
......@@ -2029,7 +2270,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->sharedBufferPhy = (unsigned long)phys_addr;
if (korg1212->sharedBufferPtr == NULL) {
snd_printk("can not allocate shared buffer memory (%d bytes)\n", sizeof(KorgSharedBuffer));
snd_printk(KERN_ERR "can not allocate shared buffer memory (%d bytes)\n", sizeof(KorgSharedBuffer));
return -ENOMEM;
}
......@@ -2045,7 +2286,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->PlayDataPhy = (u32)phys_addr;
if (korg1212->playDataBufsPtr == NULL) {
snd_printk("can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
snd_printk(KERN_ERR "can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
return -ENOMEM;
}
......@@ -2058,7 +2299,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->RecDataPhy = (u32)phys_addr;
if (korg1212->recordDataBufsPtr == NULL) {
snd_printk("can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
snd_printk(KERN_ERR "can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize);
return -ENOMEM;
}
......@@ -2086,7 +2327,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->dspMemPhy = (u32)phys_addr;
if (korg1212->dspMemPtr == NULL) {
snd_printk("can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
snd_printk(KERN_ERR "can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize);
return -ENOMEM;
}
......@@ -2106,7 +2347,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
mdelay(CARD_BOOT_DELAY_IN_MS);
if (snd_korg1212_downloadDSPCode(korg1212))
if (snd_korg1212_downloadDSPCode(korg1212))
return -EBUSY;
printk(KERN_INFO "dspMemPhy = %08x U[%08x]\n"
......@@ -2122,17 +2363,21 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->RoutingTablePhy, LowerWordSwap(korg1212->RoutingTablePhy),
korg1212->AdatTimeCodePhy, LowerWordSwap(korg1212->AdatTimeCodePhy));
if ((err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm16)) < 0)
if ((err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm)) < 0)
return err;
korg1212->pcm16->private_data = korg1212;
korg1212->pcm16->private_free = snd_korg1212_free_pcm;
strcpy(korg1212->pcm16->name, "korg1212");
korg1212->pcm->private_data = korg1212;
korg1212->pcm->private_free = snd_korg1212_free_pcm;
strcpy(korg1212->pcm->name, "korg1212");
snd_pcm_set_ops(korg1212->pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_korg1212_playback_ops);
snd_pcm_set_ops(korg1212->pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_korg1212_capture_ops);
snd_pcm_set_ops(korg1212->pcm16, SNDRV_PCM_STREAM_PLAYBACK, &snd_korg1212_playback_ops);
snd_pcm_set_ops(korg1212->pcm16, SNDRV_PCM_STREAM_CAPTURE, &snd_korg1212_capture_ops);
korg1212->pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
korg1212->pcm16->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
//snd_pcm_lib_preallocate_pages_for_all(korg1212->pcm,
// K1212_MAX_BUF_SIZE, K1212_MAX_BUF_SIZE, GFP_KERNEL);
for (i = 0; i < K1212_CONTROL_ELEMENTS; i++) {
err = snd_ctl_add(korg1212->card, snd_ctl_new1(&snd_korg1212_controls[i], korg1212));
......@@ -2141,103 +2386,21 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
}
snd_korg1212_proc_init(korg1212);
return 0;
}
static void
snd_korg1212_free(void *private_data)
{
korg1212_t *korg1212 = (korg1212_t *)private_data;
if (korg1212 == NULL) {
return;
}
snd_korg1212_TurnOffIdleMonitor(korg1212);
snd_korg1212_DisableCardInterrupts(korg1212);
if (korg1212->irq >= 0) {
free_irq(korg1212->irq, (void *)korg1212);
korg1212->irq = -1;
}
if (korg1212->iobase != 0) {
iounmap((void *)korg1212->iobase);
korg1212->iobase = 0;
}
if (korg1212->res_iomem != NULL) {
release_resource(korg1212->res_iomem);
kfree_nocheck(korg1212->res_iomem);
korg1212->res_iomem = NULL;
}
if (korg1212->res_ioport != NULL) {
release_resource(korg1212->res_ioport);
kfree_nocheck(korg1212->res_ioport);
korg1212->res_ioport = NULL;
}
if (korg1212->res_iomem2 != NULL) {
release_resource(korg1212->res_iomem2);
kfree_nocheck(korg1212->res_iomem2);
korg1212->res_iomem2 = NULL;
}
// ----------------------------------------------------
// free up memory resources used for the DSP download.
// ----------------------------------------------------
if (korg1212->dspMemPtr) {
snd_free_pci_pages(korg1212->pci, korg1212->dspCodeSize,
korg1212->dspMemPtr, (dma_addr_t)korg1212->dspMemPhy);
korg1212->dspMemPhy = 0;
korg1212->dspMemPtr = 0;
korg1212->dspCodeSize = 0;
}
#ifndef K1212_LARGEALLOC
// ------------------------------------------------------
// free up memory resources used for the Play/Rec Buffers
// ------------------------------------------------------
if (korg1212->playDataBufsPtr) {
snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
korg1212->playDataBufsPtr, (dma_addr_t)korg1212->PlayDataPhy);
korg1212->PlayDataPhy = 0;
korg1212->playDataBufsPtr = NULL;
}
if (korg1212->recordDataBufsPtr) {
snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize,
korg1212->recordDataBufsPtr, (dma_addr_t)korg1212->RecDataPhy);
korg1212->RecDataPhy = 0;
korg1212->recordDataBufsPtr = NULL;
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, korg1212, &ops)) < 0) {
snd_korg1212_free(korg1212);
return err;
}
* rchip = korg1212;
return 0;
#endif
// ----------------------------------------------------
// free up memory resources used for the Shared Buffers
// ----------------------------------------------------
if (korg1212->sharedBufferPtr) {
snd_free_pci_pages(korg1212->pci, (u32) sizeof(KorgSharedBuffer),
korg1212->sharedBufferPtr, (dma_addr_t)korg1212->sharedBufferPhy);
korg1212->sharedBufferPhy = 0;
korg1212->sharedBufferPtr = NULL;
}
}
/*
* Card initialisation
*/
static void snd_korg1212_card_free(snd_card_t *card)
{
#if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: Freeing card\n");
#endif
snd_korg1212_free(card->private_data);
}
static int __devinit
snd_korg1212_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
......@@ -2254,16 +2417,11 @@ snd_korg1212_probe(struct pci_dev *pci,
dev++;
return -ENOENT;
}
if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
sizeof(korg1212_t))) == NULL)
card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
card->private_free = snd_korg1212_card_free;
korg1212 = (korg1212_t *)card->private_data;
korg1212->card = card;
korg1212->pci = pci;
if ((err = snd_korg1212_create(korg1212)) < 0) {
if ((err = snd_korg1212_create(card, pci, &korg1212)) < 0) {
snd_card_free(card);
return err;
}
......@@ -2281,22 +2439,23 @@ snd_korg1212_probe(struct pci_dev *pci,
snd_card_free(card);
return err;
}
pci_set_drvdata(pci, card);
pci_set_drvdata(pci, korg1212);
dev++;
return 0;
}
static void __devexit snd_korg1212_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
korg1212_t *korg1212 = pci_get_drvdata(pci);
snd_card_free(korg1212->card);
pci_set_drvdata(pci, NULL);
}
static struct pci_driver driver = {
.name = "korg1212",
.name = "korg1212",
.id_table = snd_korg1212_ids,
.probe = snd_korg1212_probe,
.remove = __devexit_p(snd_korg1212_remove),
.probe = snd_korg1212_probe,
.remove = __devexit_p(snd_korg1212_remove),
};
static int __init alsa_card_korg1212_init(void)
......
......@@ -820,6 +820,7 @@ static int snd_via686_playback_prepare(snd_pcm_substream_t *substream)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
via686_setup_format(chip, viadev, runtime);
return 0;
}
......@@ -909,18 +910,37 @@ static int snd_via8233_multi_prepare(snd_pcm_substream_t *substream)
snd_via82xx_channel_reset(chip, viadev);
snd_via82xx_set_table_ptr(chip, viadev);
/* FIXME: a more generic solutions would be better */
if (chip->chip_type == TYPE_VIA8233A) {
/* VIA8233A cannot change the slot mapping, so we need
* to swap the RL/RR with C/L.
*/
#define AC97_ID_ALC650 0x414c4720
if (chip->ac97->id == AC97_ID_ALC650) {
unsigned short val;
if (runtime->channels > 4)
/* slot mapping: 3,4,7,8 */
val = 0;
else
/* slot mapping: 3,4,6,9,7,8 */
val = 0x4000;
snd_ac97_update_bits(chip->ac97, AC97_ALC650_MULTICH, 0xc000, val);
}
}
fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
fmt |= runtime->channels << 4;
outb(fmt, VIADEV_REG(viadev, OFS_MULTPLAY_FORMAT));
/* set sample number to slot 3, 4, 7, 8, 6, 9 */
/* set sample number to slot 3, 4, 7, 8, 6, 9 (for VIA8233/C,8235) */
/* corresponding to FL, FR, RL, RR, C, LFE ?? */
switch (runtime->channels) {
case 1: slots = (1<<0) | (1<<4); break;
case 2: slots = (1<<0) | (2<<4); break;
case 3: slots = (1<<0) | (2<<4) | (5<<8); break;
case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break;
case 5: slots = (1<<0) | (2<<4) | (5<<8) | (3<<12) | (4<<16); break;
case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break;
case 5: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12) | (5<<16); break;
case 6: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12) | (5<<16) | (6<<20); break;
default: slots = 0; break;
}
/* STOP index is never reached */
......@@ -1438,7 +1458,7 @@ static void snd_via82xx_mixer_free_ac97(ac97_t *ac97)
}
static struct ac97_quirk ac97_quirks[] = {
{ 0x1106, 0x4161, AC97_TUNE_HP_ONLY }, /* ASRock K7VT2 */
{ 0x1106, 0x4161, "ASRock K7VT2", AC97_TUNE_HP_ONLY },
{ } /* terminator */
};
......@@ -1457,7 +1477,7 @@ static int __devinit snd_via82xx_mixer_new(via82xx_t *chip)
if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
return err;
snd_ac97_tune_hardware(&chip->ac97, chip->pci, ac97_quirks);
snd_ac97_tune_hardware(chip->ac97, chip->pci, ac97_quirks);
if (chip->chip_type != TYPE_VIA686) {
/* use slot 10/11 */
......
......@@ -1051,7 +1051,7 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
}
/* create a data pipe */
ep = get_endpoint(alts, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK;
if (is_playback)
subs->datapipe = usb_sndisocpipe(dev, ep);
else
......@@ -1062,9 +1062,16 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
subs->fill_max = 0;
/* we need a sync pipe in async OUT or adaptive IN mode */
attr = get_endpoint(alts, 0)->bmAttributes & EP_ATTR_MASK;
attr = fmt->ep_attr & EP_ATTR_MASK;
if ((is_playback && attr == EP_ATTR_ASYNC) ||
(! is_playback && attr == EP_ATTR_ADAPTIVE)) {
/*
* QUIRK: plantronics headset has adaptive-in
* although it's really not...
*/
if (dev->descriptor.idVendor == 0x047f &&
dev->descriptor.idProduct == 0x0ca1)
goto _ok;
/* check endpoint */
if (altsd->bNumEndpoints < 2 ||
get_endpoint(alts, 1)->bmAttributes != 0x01 ||
......@@ -1088,6 +1095,7 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
}
_ok:
if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0 ||
(err = init_usb_sample_rate(dev, subs->interface, alts, fmt,
runtime->rate)) < 0)
......@@ -1651,7 +1659,7 @@ static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buff
fp->endpoint & USB_DIR_IN ? "IN" : "OUT",
sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]);
if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) {
snd_iprintf(buffer, " Rates: %d - %d (continous)\n",
snd_iprintf(buffer, " Rates: %d - %d (continuous)\n",
fp->rate_min, fp->rate_max);
} else {
unsigned int i;
......
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