Commit c3c8a7e8 authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA update

  - AC97 codec
    - better modem codec detection
    - better AD1980 codec support
  - HWDEP - added generic DSP firmware loading
  - PCM - added FORWARD ioctl
        - fixed CS46xx and emufx PCM drivers (appl_ptr update)
  - sa11xx-uda1341 driver
    - full duplex mode
    - DMA stuff updated
    - minor (but sometimes important) fixes
  - via82xx driver
    - fixed routing of multi-channels
    - added a quirk for ALC650
  - USB audio
    - added quirk for plantronics headset
parent eaa535e7
...@@ -207,7 +207,7 @@ MIDI CONTROLLER ...@@ -207,7 +207,7 @@ MIDI CONTROLLER
--------------- ---------------
The MPU401-UART interface is enabled as default only for the first 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. for the 2nd (CMIPCI) card.
There is _no_ hardware wavetable function on this chip (except for There is _no_ hardware wavetable function on this chip (except for
...@@ -221,7 +221,7 @@ FM OPL/3 Synth ...@@ -221,7 +221,7 @@ FM OPL/3 Synth
-------------- --------------
The FM OPL/3 is also enabled as default only for the first card. 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. The output quality of FM OPL/3 is, however, very weird.
I don't know why.. I don't know why..
......
...@@ -1377,6 +1377,8 @@ ...@@ -1377,6 +1377,8 @@
module_init(alsa_card_mychip_init) module_init(alsa_card_mychip_init)
module_exit(alsa_card_mychip_exit) module_exit(alsa_card_mychip_exit)
EXPORT_NO_SYMBOLS; /* for old kernels only */
]]> ]]>
</programlisting> </programlisting>
</example> </example>
...@@ -2758,6 +2760,17 @@ ...@@ -2758,6 +2760,17 @@
</para> </para>
</section> </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"> <section id="pcm-interface-operators-page-callback">
<title>page callback</title> <title>page callback</title>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Serial UART 16450/16550 MIDI driver 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) 0 - Roland Soundcanvas support (default)
1 - Midiator MS-124T support (1) 1 - Midiator MS-124T support (1)
...@@ -24,37 +24,35 @@ send the F5 NN command sequence at all; perhaps it ought to. ...@@ -24,37 +24,35 @@ send the F5 NN command sequence at all; perhaps it ought to.
Usage example for simple serial converter: Usage example for simple serial converter:
/sbin/setserial /dev/ttyS0 none /sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \ /sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 speed=115200
snd_speed=115200
Usage example for Roland SoundCanvas with 4 MIDI ports: Usage example for Roland SoundCanvas with 4 MIDI ports:
/sbin/setserial /dev/ttyS0 none /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 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). parameter to match (A=19200, B=9600).
Usage example for MS-124T, with A-B switch in A position: Usage example for MS-124T, with A-B switch in A position:
/sbin/setserial /dev/ttyS0 none /sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \ /sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=1 \
snd_adaptor=1 snd_speed=19200 speed=19200
In MS-124W S/A mode, one raw MIDI substream is supported (midiCnD0); 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. the same data to all four MIDI Out connectors at full MIDI speed.
Usage example for S/A mode: Usage example for S/A mode:
/sbin/setserial /dev/ttyS0 none /sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \ /sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=2
snd_adaptor=2
In MS-124W M/B mode, the driver supports 16 ALSA raw MIDI substreams; 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 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 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. 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. ...@@ -67,8 +65,7 @@ one byte every 320 us per port.
Usage example for M/B mode: Usage example for M/B mode:
/sbin/setserial /dev/ttyS0 none /sbin/setserial /dev/ttyS0 none
/sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \ /sbin/modprobe snd-serial-u16550 port=0x3f8 irq=4 adaptor=3
snd_adaptor=3
The MS-124W hardware's M/A mode is currently not supported. This mode allows 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, 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 ...@@ -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 serial port. Similar to Roland Soundcanvas mode, F5 NN is used to select the
appropriate input or output stream (depending on the data direction). appropriate input or output stream (depending on the data direction).
Additionally, the CTS signal is used to regulate the data flow. The number of 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 { ...@@ -268,6 +268,14 @@ struct _snd_ac97 {
}; };
/* conditions */ /* 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) static inline int ac97_is_rev22(ac97_t * ac97)
{ {
return (ac97->ext_id & AC97_EI_REV_MASK) == AC97_EI_REV_22; 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) ...@@ -278,7 +286,8 @@ static inline int ac97_can_amap(ac97_t * ac97)
} }
/* functions */ /* 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); void snd_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short value);
unsigned short snd_ac97_read(ac97_t *ac97, unsigned short reg); unsigned short snd_ac97_read(ac97_t *ac97, unsigned short reg);
...@@ -296,6 +305,7 @@ enum { AC97_TUNE_HP_ONLY, AC97_TUNE_SWAP_HP }; ...@@ -296,6 +305,7 @@ enum { AC97_TUNE_HP_ONLY, AC97_TUNE_SWAP_HP };
struct ac97_quirk { struct ac97_quirk {
unsigned short vendor; unsigned short vendor;
unsigned short device; unsigned short device;
const char *name;
int type; int type;
}; };
......
...@@ -93,7 +93,7 @@ struct sndrv_aes_iec958 { ...@@ -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 { enum sndrv_hwdep_iface {
SNDRV_HWDEP_IFACE_OPL2 = 0, SNDRV_HWDEP_IFACE_OPL2 = 0,
...@@ -104,9 +104,10 @@ enum sndrv_hwdep_iface { ...@@ -104,9 +104,10 @@ enum sndrv_hwdep_iface {
SNDRV_HWDEP_IFACE_YSS225, /* Yamaha FX processor */ SNDRV_HWDEP_IFACE_YSS225, /* Yamaha FX processor */
SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */ SNDRV_HWDEP_IFACE_ICS2115, /* Wavetable synth */
SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */ SNDRV_HWDEP_IFACE_SSCAPE, /* Ensoniq SoundScape ISA card (MC68EC000) */
SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */
/* Don't forget to change the following: */ /* 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 { struct sndrv_hwdep_info {
...@@ -118,9 +119,29 @@ struct sndrv_hwdep_info { ...@@ -118,9 +119,29 @@ struct sndrv_hwdep_info {
unsigned char reserved[64]; /* reserved for future */ 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 { enum {
SNDRV_HWDEP_IOCTL_PVERSION = _IOR ('H', 0x00, int), SNDRV_HWDEP_IOCTL_PVERSION = _IOR ('H', 0x00, int),
SNDRV_HWDEP_IOCTL_INFO = _IOR ('H', 0x01, struct sndrv_hwdep_info), 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 { ...@@ -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 unsigned long sndrv_pcm_uframes_t;
typedef long sndrv_pcm_sframes_t; typedef long sndrv_pcm_sframes_t;
...@@ -434,6 +455,7 @@ enum { ...@@ -434,6 +455,7 @@ enum {
SNDRV_PCM_IOCTL_REWIND = _IOW('A', 0x46, sndrv_pcm_uframes_t), SNDRV_PCM_IOCTL_REWIND = _IOW('A', 0x46, sndrv_pcm_uframes_t),
SNDRV_PCM_IOCTL_RESUME = _IO('A', 0x47), SNDRV_PCM_IOCTL_RESUME = _IO('A', 0x47),
SNDRV_PCM_IOCTL_XRUN = _IO('A', 0x48), 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_WRITEI_FRAMES = _IOW('A', 0x50, struct sndrv_xferi),
SNDRV_PCM_IOCTL_READI_FRAMES = _IOR('A', 0x51, 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), SNDRV_PCM_IOCTL_WRITEN_FRAMES = _IOW('A', 0x52, struct sndrv_xfern),
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
typedef enum sndrv_hwdep_iface snd_hwdep_iface_t; typedef enum sndrv_hwdep_iface snd_hwdep_iface_t;
typedef struct sndrv_hwdep_info snd_hwdep_info_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 { typedef struct _snd_hwdep_ops {
long long (*llseek) (snd_hwdep_t *hw, struct file * file, long long offset, int orig); long long (*llseek) (snd_hwdep_t *hw, struct file * file, long long offset, int orig);
...@@ -37,6 +39,8 @@ typedef struct _snd_hwdep_ops { ...@@ -37,6 +39,8 @@ typedef struct _snd_hwdep_ops {
unsigned int (*poll) (snd_hwdep_t * hw, struct file * file, poll_table * wait); 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 (*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 (*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; } snd_hwdep_ops_t;
struct _snd_hwdep { struct _snd_hwdep {
...@@ -56,6 +60,11 @@ struct _snd_hwdep { ...@@ -56,6 +60,11 @@ struct _snd_hwdep {
wait_queue_head_t open_wait; wait_queue_head_t open_wait;
void *private_data; void *private_data;
void (*private_free) (snd_hwdep_t *hwdep); 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); 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 [] \ ...@@ -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_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_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_INDEX_DESC SNDRV_ENABLED ",allows:{{0,7}},unique,skill:required,dialog:list"
#define SNDRV_ID_DESC SNDRV_ENABLED ",unique" #define SNDRV_ID_DESC SNDRV_ENABLED ",unique"
......
...@@ -97,6 +97,7 @@ typedef struct _snd_pcm_ops { ...@@ -97,6 +97,7 @@ typedef struct _snd_pcm_ops {
int (*silence)(snd_pcm_substream_t *substream, int channel, int (*silence)(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count); snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset); struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
int (*ack)(snd_pcm_substream_t *substream);
} snd_pcm_ops_t; } snd_pcm_ops_t;
/* /*
......
...@@ -15,10 +15,15 @@ ...@@ -15,10 +15,15 @@
* features support * 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" #define UDA1341_ALSA_NAME "snd-uda1341"
/*
* Default rate set after inicialization
*/
#define AUDIO_RATE_DEFAULT 44100
/* /*
* UDA1341 L3 address and command types * UDA1341 L3 address and command types
*/ */
......
/* include/version.h. Generated by configure. */ /* include/version.h. Generated by configure. */
#define CONFIG_SND_VERSION "0.9.0rc7" #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 @@ ...@@ -13,9 +13,48 @@
* 2002-03-29 Tomas Kasparek basic capture is working (native ALSA) * 2002-03-29 Tomas Kasparek basic capture is working (native ALSA)
* 2002-03-29 Tomas Kasparek capture is working (OSS emulation) * 2002-03-29 Tomas Kasparek capture is working (OSS emulation)
* 2002-04-04 Tomas Kasparek better rates handling (allow non-standard rates) * 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 <sound/driver.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -53,8 +92,6 @@ MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard."); ...@@ -53,8 +92,6 @@ MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");
#define chip_t sa11xx_uda1341_t #define chip_t sa11xx_uda1341_t
#define SHIFT_16_STEREO 2
typedef enum stream_id_t{ typedef enum stream_id_t{
PLAYBACK=0, PLAYBACK=0,
CAPTURE, CAPTURE,
...@@ -63,6 +100,7 @@ typedef enum stream_id_t{ ...@@ -63,6 +100,7 @@ typedef enum stream_id_t{
typedef struct audio_stream { 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_device_t dma_dev; /* device identifier for DMA */
dma_regs_t *dma_regs; /* points to our DMA registers */ dma_regs_t *dma_regs; /* points to our DMA registers */
...@@ -72,22 +110,18 @@ typedef struct audio_stream { ...@@ -72,22 +110,18 @@ typedef struct audio_stream {
int sent_total; /* # of sent periods total (just for info & debug) */ int sent_total; /* # of sent periods total (just for info & debug) */
int sync; /* are we recoding - flag used to do DMA trans. for sync */ 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; snd_pcm_substream_t *stream;
}audio_stream_t; }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 { typedef struct snd_card_sa11xx_uda1341 {
struct pm_dev *pm_dev; struct pm_dev *pm_dev;
snd_card_t *card; snd_card_t *card;
struct l3_client *uda1341; struct l3_client *uda1341;
long samplerate; long samplerate;
audio_stream_t *s[MAX_STREAMS]; audio_stream_t *s[MAX_STREAMS];
snd_info_entry_t *proc_entry;
}sa11xx_uda1341_t; }sa11xx_uda1341_t;
static struct snd_card_sa11xx_uda1341 *sa11xx_uda1341 = NULL; 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 ...@@ -217,7 +251,9 @@ static void sa11xx_uda1341_set_samplerate(sa11xx_uda1341_t *sa11xx_uda1341, long
break; 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_FORMAT, (void *)LSB16);
l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk); l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk);
Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE; Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
DEBUG(KERN_DEBUG "set_samplerate done (new rate: %ld)\n", rate); 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) ...@@ -237,11 +273,13 @@ static void sa11xx_uda1341_audio_init(sa11xx_uda1341_t *sa11xx_uda1341)
/* Setup DMA stuff */ /* Setup DMA stuff */
if (sa11xx_uda1341->s[PLAYBACK]) { if (sa11xx_uda1341->s[PLAYBACK]) {
sa11xx_uda1341->s[PLAYBACK]->id = "UDA1341 out"; sa11xx_uda1341->s[PLAYBACK]->id = "UDA1341 out";
sa11xx_uda1341->s[PLAYBACK]->stream_id = PLAYBACK;
sa11xx_uda1341->s[PLAYBACK]->dma_dev = DMA_Ser4SSPWr; sa11xx_uda1341->s[PLAYBACK]->dma_dev = DMA_Ser4SSPWr;
} }
if (sa11xx_uda1341->s[CAPTURE]) { if (sa11xx_uda1341->s[CAPTURE]) {
sa11xx_uda1341->s[CAPTURE]->id = "UDA1341 in"; sa11xx_uda1341->s[CAPTURE]->id = "UDA1341 in";
sa11xx_uda1341->s[CAPTURE]->stream_id = CAPTURE;
sa11xx_uda1341->s[CAPTURE]->dma_dev = DMA_Ser4SSPRd; sa11xx_uda1341->s[CAPTURE]->dma_dev = DMA_Ser4SSPRd;
} }
...@@ -255,23 +293,25 @@ static void sa11xx_uda1341_audio_init(sa11xx_uda1341_t *sa11xx_uda1341) ...@@ -255,23 +293,25 @@ static void sa11xx_uda1341_audio_init(sa11xx_uda1341_t *sa11xx_uda1341)
Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8); Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8);
Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk; Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
Ser4SSCR0 |= SSCR0_SSE; Ser4SSCR0 |= SSCR0_SSE;
local_irq_restore(flags);
/* Enable the audio power */ /* Enable the audio power */
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET); clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON); set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
local_irq_restore(flags);
/* Initialize the UDA1341 internal state */ /* Initialize the UDA1341 internal state */
l3_open(sa11xx_uda1341->uda1341); l3_open(sa11xx_uda1341->uda1341);
/* external clock configuration */ /* external clock configuration (after l3_open - regs must be
sa11xx_uda1341_set_samplerate(sa11xx_uda1341, 44100); /* default sample rate */ * initialized */
sa11xx_uda1341_set_samplerate(sa11xx_uda1341, AUDIO_RATE_DEFAULT);
/* Wait for the UDA1341 to wake up */ /* Wait for the UDA1341 to wake up */
set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET); set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
mdelay(1); mdelay(1);
/* make the left and right channels unswapped (flip the WS latch ) */ /* make the left and right channels unswapped (flip the WS latch ) */
Ser4SSDR = 0; Ser4SSDR = 0;
...@@ -280,11 +320,16 @@ static void sa11xx_uda1341_audio_init(sa11xx_uda1341_t *sa11xx_uda1341) ...@@ -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) 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 */ /* disable the audio power and all signals leading to the audio chip */
l3_close(sa11xx_uda1341->uda1341); l3_close(sa11xx_uda1341->uda1341);
Ser4SSCR0 = 0; Ser4SSCR0 = 0;
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET); clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
/* power off */
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON); clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
/* mute off */
clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
} }
...@@ -292,26 +337,29 @@ static void sa11xx_uda1341_audio_shutdown(sa11xx_uda1341_t *sa11xx_uda1341) ...@@ -292,26 +337,29 @@ static void sa11xx_uda1341_audio_shutdown(sa11xx_uda1341_t *sa11xx_uda1341)
/* {{{ DMA staff */ /* {{{ DMA staff */
#define SYNC_ADDR (dma_addr_t)FLUSH_BASE_PHYS /*
#define SYNC_SIZE 4096 // was 2048 * these are the address and sizes used to fill the xmit buffer
* so we can get a clock in record only mode
#define DMA_REQUEST(s, cb) sa1100_request_dma((s)->dma_dev, (s)->id, cb, s, \ */
&((s)->dma_regs)) #define FORCE_CLOCK_ADDR (dma_addr_t)FLUSH_BASE_PHYS
#define DMA_FREE(s) {sa1100_free_dma((s)->dma_regs); (s)->dma_regs = 0;} #define FORCE_CLOCK_SIZE 4096 // was 2048
#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)
static void audio_dma_request(audio_stream_t *s, void (*callback)(void *)) 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) 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) 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) ...@@ -319,12 +367,17 @@ static u_int audio_get_dma_pos(audio_stream_t *s)
snd_pcm_substream_t * substream = s->stream; snd_pcm_substream_t * substream = s->stream;
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
unsigned int offset; unsigned int offset;
unsigned long flags;
DEBUG_NAME(KERN_DEBUG "get_dma_pos"); 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); DEBUG(" %d ->", offset);
offset >>= SHIFT_16_STEREO; offset = bytes_to_frames(runtime,offset);
DEBUG(" %d [fr]\n", offset); DEBUG(" %d [fr]\n", offset);
if (offset >= runtime->buffer_size){ if (offset >= runtime->buffer_size){
...@@ -339,27 +392,33 @@ static u_int audio_get_dma_pos(audio_stream_t *s) ...@@ -339,27 +392,33 @@ static u_int audio_get_dma_pos(audio_stream_t *s)
return offset; return offset;
} }
/*
* this stops the dma and clears the dma ptrs
*/
static void audio_stop_dma(audio_stream_t *s) static void audio_stop_dma(audio_stream_t *s)
{ {
long flags; long flags;
DEBUG_NAME(KERN_DEBUG "stop_dma\n"); 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; return;
local_irq_save(flags); spin_lock_irqsave(&(s->dma_lock), flags);
s->active = 0; s->active = 0;
s->sent_periods = 0; s->sent_periods = 0;
s->sent_total = 0; s->sent_total = 0;
s->sync = 0;
DMA_STOP(s); /* this stops the dma channel and clears the buffer ptrs */
DMA_CLEAR(s); sa1100_clear_dma((s)->dma_regs);
local_irq_restore(flags); spin_unlock_irqrestore(&(s->dma_lock), flags);
} }
static void audio_reset(audio_stream_t *s) static void audio_reset(audio_stream_t *s)
{ {
DEBUG_NAME(KERN_DEBUG "dma_reset\n"); DEBUG_NAME(KERN_DEBUG "dma_reset\n");
...@@ -375,40 +434,58 @@ static void audio_process_dma(audio_stream_t *s) ...@@ -375,40 +434,58 @@ static void audio_process_dma(audio_stream_t *s)
{ {
snd_pcm_substream_t * substream = s->stream; snd_pcm_substream_t * substream = s->stream;
snd_pcm_runtime_t *runtime; snd_pcm_runtime_t *runtime;
int ret,i; int ret;
DEBUG_NAME(KERN_DEBUG "process_dma\n"); 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 */ /* 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) { while (1) {
DEBUG(KERN_DEBUG "sent sync period (dma_size[B]: %d)\n", SYNC_SIZE); DEBUG(KERN_DEBUG "sent zero dma period (dma_size[B]: %d)\n", FORCE_CLOCK_SIZE);
ret = DMA_START(s, SYNC_ADDR, SYNC_SIZE); ret = sa1100_start_dma((s)->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
if (ret) if (ret)
return; 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; runtime = substream->runtime;
while(1) { DEBUG("audio_process_dma hw_ptr_base = 0x%x w_ptr_interrupt = 0x%x "
unsigned int dma_size = runtime->period_size << SHIFT_16_STEREO; "period_size = %d periods = %d buffer_size = %d sync=0x%x dma_area = 0x%x\n",
unsigned int offset = dma_size * s->sent_periods; 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){ if (dma_size > MAX_DMA_SIZE){
/* this should not happen! */ /* 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; 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) if (ret)
return; return;
...@@ -429,7 +506,6 @@ static void audio_process_dma(audio_stream_t *s) ...@@ -429,7 +506,6 @@ static void audio_process_dma(audio_stream_t *s)
} }
} }
static void audio_dma_callback(void *data) static void audio_dma_callback(void *data)
{ {
audio_stream_t *s = data; audio_stream_t *s = data;
...@@ -438,23 +514,25 @@ static void audio_dma_callback(void *data) ...@@ -438,23 +514,25 @@ static void audio_dma_callback(void *data)
DEBUG_NAME(KERN_DEBUG "dma_callback\n"); 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 #ifdef DEBUG_MODE
printk(KERN_DEBUG " dma_area:"); printk(KERN_DEBUG " dma_area:");
buf = (char *)s->stream->runtime->dma_addr + buf = (char *)s->stream->runtime->dma_addr + ((s->sent_periods - 1 ) *
((s->sent_periods - 1 ) * frames_to_bytes( s->stream->runtime, s->stream->runtime->period_size));
(s->stream->runtime->period_size << SHIFT_16_STEREO));
for (i=0; i < 32; i++) { for (i=0; i < 32; i++) {
printk(" %02x", *(char *)(buf + i)); printk(" %02x", *(char *)(buf + i));
} }
printk("\n"); printk("\n");
#endif #endif
}
/*
* 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) if (s->active)
snd_pcm_period_elapsed(s->stream);
audio_process_dma(s); audio_process_dma(s);
} }
...@@ -491,18 +569,21 @@ static int snd_card_sa11xx_uda1341_pcm_trigger(stream_id_t stream_id, ...@@ -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_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 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) { if (stream_id == CAPTURE && !chip->s[PLAYBACK]->active) {
/* we need synchronization DMA transfer (zeros) */ /* we need to force fill the xmit DMA with zeros */
DEBUG(KERN_DEBUG "starting synchronization DMA transfer\n"); DEBUG(KERN_DEBUG "starting zero fill DMA transfer\n");
chip->s[PLAYBACK]->sync = 1; 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]); audio_process_dma(chip->s[PLAYBACK]);
} }
/* want to playback and have capture - stop syncing */ /* this case is when you were recording then you turn on a
if(stream_id == PLAYBACK && chip->s[PLAYBACK]->sync) { * 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; chip->s[PLAYBACK]->sync = 0;
audio_stop_dma(chip->s[PLAYBACK]);
} }
/* requested stream startup */ /* requested stream startup */
...@@ -512,27 +593,30 @@ static int snd_card_sa11xx_uda1341_pcm_trigger(stream_id_t stream_id, ...@@ -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_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/* want to stop capture and use syncing - stop DMA syncing */ /* requested stream shutdown */
if (stream_id == CAPTURE && chip->s[PLAYBACK]->sync) { chip->s[stream_id]->active = 0;
/* we do not need synchronization DMA transfer now */ audio_stop_dma(chip->s[stream_id]);
DEBUG(KERN_DEBUG "stopping synchronization DMA transfer\n");
chip->s[PLAYBACK]->sync = 0; /*
chip->s[PLAYBACK]->active = 0; * now we need to make sure a record only stream has a clock
audio_stop_dma(chip->s[PLAYBACK]); * so if we're stopping a playback with an active capture
} * we need to turn the 0 fill dma on for the xmit side
/* want to stop playback and have capture - run DMA syncing */ */
if(stream_id == PLAYBACK && chip->s[CAPTURE]->active) { if (stream_id == PLAYBACK && chip->s[CAPTURE]->active) {
/* we need synchronization DMA transfer (zeros) */ /* we need to force fill the xmit DMA with zeros */
DEBUG(KERN_DEBUG "starting synchronization DMA transfer\n"); DEBUG(KERN_DEBUG "starting zero fill DMA transfer\n");
chip->s[PLAYBACK]->sync = 1; chip->s[PLAYBACK]->sync = 1;
chip->s[PLAYBACK]->active = 1; chip->s[PLAYBACK]->active = 0;
chip->s[PLAYBACK]->stream = SYNC_SUBSTREAM; /* not really used! */
audio_process_dma(chip->s[PLAYBACK]); 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]);
}
/* requested stream shutdown */
chip->s[stream_id]->active = 0;
audio_stop_dma(chip->s[stream_id]);
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -601,7 +685,11 @@ static int snd_card_sa11xx_uda1341_playback_open(snd_pcm_substream_t * substream ...@@ -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_periods = 0;
chip->s[PLAYBACK]->sent_total = 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; runtime->hw = snd_sa11xx_uda1341_playback;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) 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 ...@@ -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) 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); sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream);
DEBUG_NAME(KERN_DEBUG "playback_pointer\n"); 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) ...@@ -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_periods = 0;
chip->s[CAPTURE]->sent_total = 0; chip->s[CAPTURE]->sent_total = 0;
audio_reset(chip->s[PLAYBACK]); audio_reset(chip->s[CAPTURE]);
runtime->hw = snd_sa11xx_uda1341_capture; runtime->hw = snd_sa11xx_uda1341_capture;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) 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 ...@@ -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) 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); sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream);
DEBUG_NAME(KERN_DEBUG "record_pointer\n"); 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, ...@@ -784,6 +877,13 @@ static int __init snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341_t *sa11xx_uda1341,
substreams, substreams, &pcm)) < 0) substreams, substreams, &pcm)) < 0)
return err; 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_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);
pcm->private_data = sa11xx_uda1341; 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 ...@@ -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"); 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]; is = sa11xx_uda1341->s[PLAYBACK];
os = sa11xx_uda1341->s[CAPTURE]; os = sa11xx_uda1341->s[CAPTURE];
......
...@@ -107,7 +107,12 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) ...@@ -107,7 +107,12 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
#endif #endif
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
add_wait_queue(&hw->open_wait, &wait); add_wait_queue(&hw->open_wait, &wait);
down(&hw->open_mutex);
while (1) { while (1) {
if (hw->exclusive && hw->used > 0) {
err = -EBUSY;
break;
}
err = hw->ops.open(hw, file); err = hw->ops.open(hw, file);
if (err >= 0) if (err >= 0)
break; break;
...@@ -127,20 +132,26 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) ...@@ -127,20 +132,26 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&hw->open_wait, &wait); remove_wait_queue(&hw->open_wait, &wait);
if (err >= 0) if (err >= 0) {
file->private_data = hw; file->private_data = hw;
hw->used++;
}
up(&hw->open_mutex);
return err; return err;
} }
static int snd_hwdep_release(struct inode *inode, struct file * file) 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); snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO);
down(&hw->open_mutex);
if (hw->ops.release) { if (hw->ops.release) {
err = hw->ops.release(hw, file); err = hw->ops.release(hw, file);
wake_up(&hw->open_wait); wake_up(&hw->open_wait);
return err;
} }
if (hw->used > 0)
hw->used--;
up(&hw->open_mutex);
return -ENXIO; return -ENXIO;
} }
...@@ -166,14 +177,58 @@ static int snd_hwdep_info(snd_hwdep_t *hw, snd_hwdep_info_t *_info) ...@@ -166,14 +177,58 @@ static int snd_hwdep_info(snd_hwdep_t *hw, snd_hwdep_info_t *_info)
return 0; 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, static int snd_hwdep_ioctl(struct inode *inode, struct file * file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
snd_hwdep_t *hw = snd_magic_cast(snd_hwdep_t, file->private_data, return -ENXIO); 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); 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); 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) if (hw->ops.ioctl)
return hw->ops.ioctl(hw, file, cmd, arg); return hw->ops.ioctl(hw, file, cmd, arg);
return -ENOTTY; return -ENOTTY;
...@@ -298,6 +353,7 @@ int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep ...@@ -298,6 +353,7 @@ int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep
return err; return err;
} }
init_waitqueue_head(&hwdep->open_wait); init_waitqueue_head(&hwdep->open_wait);
init_MUTEX(&hwdep->open_mutex);
*rhwdep = hwdep; *rhwdep = hwdep;
return 0; return 0;
} }
......
...@@ -20,13 +20,52 @@ ...@@ -20,13 +20,52 @@
#include <sound/driver.h> #include <sound/driver.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/fs.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/timer.h> #include <sound/hwdep.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "ioctl32.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[] = { struct ioctl32_mapper hwdep_mappers[] = {
{ SNDRV_HWDEP_IOCTL_PVERSION, NULL }, MAP_COMPAT(SNDRV_HWDEP_IOCTL_PVERSION),
{ SNDRV_HWDEP_IOCTL_INFO, NULL }, MAP_COMPAT(SNDRV_HWDEP_IOCTL_INFO),
MAP_COMPAT(SNDRV_HWDEP_IOCTL_DSP_STATUS),
{ SNDRV_HWDEP_IOCTL_DSP_LOAD32, AP(hwdep_dsp_image) },
{ 0 }, { 0 },
}; };
...@@ -77,27 +77,6 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) ...@@ -77,27 +77,6 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
va_end(args); va_end(args);
tmpbuf[sizeof(tmpbuf)-1] = '\0'; tmpbuf[sizeof(tmpbuf)-1] = '\0';
printk(tmpbuf); 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 #endif
...@@ -2186,6 +2186,8 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream, ...@@ -2186,6 +2186,8 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
} else { } else {
runtime->control->appl_ptr = appl_ptr; runtime->control->appl_ptr = appl_ptr;
} }
if (substream->ops->ack)
substream->ops->ack(substream);
offset += frames; offset += frames;
size -= frames; size -= frames;
...@@ -2478,6 +2480,8 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream, void ...@@ -2478,6 +2480,8 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream, void
} else { } else {
runtime->control->appl_ptr = appl_ptr; runtime->control->appl_ptr = appl_ptr;
} }
if (substream->ops->ack)
substream->ops->ack(substream);
offset += frames; offset += frames;
size -= frames; size -= frames;
......
...@@ -527,7 +527,7 @@ u_int8_t snd_pcm_format_silence(snd_pcm_format_t format) ...@@ -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. * 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) 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 ...@@ -1982,6 +1982,106 @@ snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream, snd_pcm
return ret; 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) static int snd_pcm_hwsync(snd_pcm_substream_t *substream)
{ {
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
...@@ -2169,6 +2269,18 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, ...@@ -2169,6 +2269,18 @@ static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
__put_user(result, _frames); __put_user(result, _frames);
return result < 0 ? result : 0; 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: case SNDRV_PCM_IOCTL_PAUSE:
{ {
int res; int res;
...@@ -2244,6 +2356,18 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream, ...@@ -2244,6 +2356,18 @@ static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
__put_user(result, _frames); __put_user(result, _frames);
return result < 0 ? result : 0; 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: case SNDRV_PCM_IOCTL_DRAIN:
return snd_pcm_capture_drain(substream); return snd_pcm_capture_drain(substream);
case SNDRV_PCM_IOCTL_DROP: case SNDRV_PCM_IOCTL_DROP:
......
...@@ -358,11 +358,19 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev) ...@@ -358,11 +358,19 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev)
if (snd_rawmidi_info_select(card, &info) >= 0) if (snd_rawmidi_info_select(card, &info) >= 0)
strcpy(port.name, info.subname); strcpy(port.name, info.subname);
if (! port.name[0]) { if (! port.name[0]) {
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) if (ports > 1)
sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p); sprintf(port.name, "MIDI %d-%d-%d", card->number, device, p);
else else
sprintf(port.name, "MIDI %d-%d", card->number, device); sprintf(port.name, "MIDI %d-%d", card->number, device);
} }
}
if ((info.flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count) 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; port.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
if ((info.flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count) if ((info.flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count)
......
...@@ -521,9 +521,6 @@ EXPORT_SYMBOL(snd_verbose_printk); ...@@ -521,9 +521,6 @@ EXPORT_SYMBOL(snd_verbose_printk);
#endif #endif
#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
EXPORT_SYMBOL(snd_verbose_printd); EXPORT_SYMBOL(snd_verbose_printd);
#endif
#if defined(CONFIG_SND_DEBUG) && !defined(CONFIG_SND_VERBOSE_PRINTK)
EXPORT_SYMBOL(snd_printd);
#endif #endif
/* wrappers */ /* wrappers */
#ifdef CONFIG_SND_DEBUG_MEMORY #ifdef CONFIG_SND_DEBUG_MEMORY
......
...@@ -474,7 +474,7 @@ int snd_mpu401_uart_new(snd_card_t * card, int device, ...@@ -474,7 +474,7 @@ int snd_mpu401_uart_new(snd_card_t * card, int device,
} }
mpu->irq = irq; mpu->irq = irq;
mpu->irq_flags = irq_flags; 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_OUTPUT, &snd_mpu401_uart_output);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input);
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
......
...@@ -802,7 +802,7 @@ module_exit(alsa_card_mtpav_exit) ...@@ -802,7 +802,7 @@ module_exit(alsa_card_mtpav_exit)
#ifndef MODULE #ifndef MODULE
/* format is: snd-mtpav=snd_enable,index,id, /* format is: snd-mtpav=enable,index,id,
port,irq,hwports */ port,irq,hwports */
static int __init alsa_card_mtpav_setup(char *str) static int __init alsa_card_mtpav_setup(char *str)
......
...@@ -379,7 +379,7 @@ module_exit(alsa_card_dt019x_exit) ...@@ -379,7 +379,7 @@ module_exit(alsa_card_dt019x_exit)
#ifndef MODULE #ifndef MODULE
/* format is: snd-dt019x=enable,index,id,snd_isapnp, /* format is: snd-dt019x=enable,index,id,
port,mpu_port,fm_port, port,mpu_port,fm_port,
irq,mpu_irq,dma8,dma8_size */ irq,mpu_irq,dma8,dma8_size */
......
...@@ -277,7 +277,7 @@ module_exit(alsa_card_es968_exit) ...@@ -277,7 +277,7 @@ module_exit(alsa_card_es968_exit)
#ifndef MODULE #ifndef MODULE
/* format is: snd-es968=enable,index,id, /* format is: snd-es968=enable,index,id,
port,irq,snd_dma1 */ port,irq,dma1 */
static int __init alsa_card_es968_setup(char *str) 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 ...@@ -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.run_width = p->run_width;
info.version = p->version; info.version = p->version;
info.state = p->running; 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; break;
/* load CSP microcode */ /* load CSP microcode */
......
...@@ -44,7 +44,7 @@ MODULE_DEVICES("{{Aztech Systems,Sound Galaxy}}"); ...@@ -44,7 +44,7 @@ MODULE_DEVICES("{{Aztech Systems,Sound Galaxy}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 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 sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */
static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */ static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */ static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */
...@@ -300,7 +300,7 @@ static int __init alsa_card_sgalaxy_init(void) ...@@ -300,7 +300,7 @@ static int __init alsa_card_sgalaxy_init(void)
{ {
int dev, cards; 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) if (snd_sgalaxy_probe(dev) >= 0)
cards++; cards++;
} }
...@@ -327,7 +327,7 @@ module_exit(alsa_card_sgalaxy_exit) ...@@ -327,7 +327,7 @@ module_exit(alsa_card_sgalaxy_exit)
#ifndef MODULE #ifndef MODULE
/* format is: snd-sgalaxy=snd_enable,index,id, /* format is: snd-sgalaxy=enable,index,id,
sbport,wssport, sbport,wssport,
irq,dma1 */ irq,dma1 */
...@@ -337,7 +337,7 @@ static int __init alsa_card_sgalaxy_setup(char *str) ...@@ -337,7 +337,7 @@ static int __init alsa_card_sgalaxy_setup(char *str)
if (nr_dev >= SNDRV_CARDS) if (nr_dev >= SNDRV_CARDS)
return 0; 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_option(&str,&index[nr_dev]) == 2 &&
get_id(&str,&id[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 &&
get_option(&str,(int *)&sbport[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); ...@@ -56,110 +56,111 @@ static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97);
typedef struct { typedef struct {
unsigned int id; unsigned int id;
unsigned int mask; unsigned int mask;
char *name; const char *name;
int (*patch)(ac97_t *ac97); int (*patch)(ac97_t *ac97);
int (*mpatch)(ac97_t *ac97);
} ac97_codec_id_t; } ac97_codec_id_t;
static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = { static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = {
{ 0x414b4d00, 0xffffff00, "Asahi Kasei", NULL }, { 0x414b4d00, 0xffffff00, "Asahi Kasei", NULL, NULL },
{ 0x41445300, 0xffffff00, "Analog Devices", NULL }, { 0x41445300, 0xffffff00, "Analog Devices", NULL, NULL },
{ 0x414c4300, 0xffffff00, "Realtek", NULL }, { 0x414c4300, 0xffffff00, "Realtek", NULL, NULL },
{ 0x414c4700, 0xffffff00, "Avance Logic", NULL }, { 0x414c4700, 0xffffff00, "Avance Logic", NULL, NULL },
{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL }, { 0x434d4900, 0xffffff00, "C-Media Electronics", NULL, NULL },
{ 0x43525900, 0xffffff00, "Cirrus Logic", NULL }, { 0x43525900, 0xffffff00, "Cirrus Logic", NULL, NULL },
{ 0x43585400, 0xffffff00, "Conexant", NULL }, { 0x43585400, 0xffffff00, "Conexant", NULL, NULL },
{ 0x44543000, 0xffffff00, "Diamond Technology", NULL }, { 0x44543000, 0xffffff00, "Diamond Technology", NULL, NULL },
{ 0x454d4300, 0xffffff00, "eMicro", NULL }, { 0x454d4300, 0xffffff00, "eMicro", NULL, NULL },
{ 0x45838300, 0xffffff00, "ESS Technology", NULL }, { 0x45838300, 0xffffff00, "ESS Technology", NULL, NULL },
{ 0x48525300, 0xffffff00, "Intersil", NULL }, { 0x48525300, 0xffffff00, "Intersil", NULL, NULL },
{ 0x49434500, 0xffffff00, "ICEnsemble", NULL }, { 0x49434500, 0xffffff00, "ICEnsemble", NULL, NULL },
{ 0x49544500, 0xffffff00, "ITE Tech.Inc", NULL }, { 0x49544500, 0xffffff00, "ITE Tech.Inc", NULL, NULL },
{ 0x4e534300, 0xffffff00, "National Semiconductor", NULL }, { 0x4e534300, 0xffffff00, "National Semiconductor", NULL, NULL },
{ 0x50534300, 0xffffff00, "Philips", NULL }, { 0x50534300, 0xffffff00, "Philips", NULL, NULL },
{ 0x53494c00, 0xffffff00, "Silicon Laboratory", NULL }, { 0x53494c00, 0xffffff00, "Silicon Laboratory", NULL, NULL },
{ 0x54524100, 0xffffff00, "TriTech", NULL }, { 0x54524100, 0xffffff00, "TriTech", NULL, NULL },
{ 0x54584e00, 0xffffff00, "Texas Instruments", NULL }, { 0x54584e00, 0xffffff00, "Texas Instruments", NULL, NULL },
{ 0x56494100, 0xffffff00, "VIA Technologies", NULL }, { 0x56494100, 0xffffff00, "VIA Technologies", NULL, NULL },
{ 0x57454300, 0xffffff00, "Winbond", NULL }, { 0x57454300, 0xffffff00, "Winbond", NULL, NULL },
{ 0x574d4c00, 0xffffff00, "Wolfson", NULL }, { 0x574d4c00, 0xffffff00, "Wolfson", NULL, NULL },
{ 0x594d4800, 0xffffff00, "Yamaha", NULL }, { 0x594d4800, 0xffffff00, "Yamaha", NULL, NULL },
{ 0x83847600, 0xffffff00, "SigmaTel", NULL }, { 0x83847600, 0xffffff00, "SigmaTel", NULL, NULL },
{ 0, 0, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
static const ac97_codec_id_t snd_ac97_codec_ids[] = { static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x014b0502, 0xffffffff, "NM256AV", NULL }, // FIXME: which real one? { 0x014b0502, 0xffffffff, "NM256AV", NULL, NULL }, // FIXME: which real one?
{ 0x414b4d00, 0xffffffff, "AK4540", NULL }, { 0x414b4d00, 0xffffffff, "AK4540", NULL, NULL },
{ 0x414b4d01, 0xffffffff, "AK4542", NULL }, { 0x414b4d01, 0xffffffff, "AK4542", NULL, NULL },
{ 0x414b4d02, 0xffffffff, "AK4543", NULL }, { 0x414b4d02, 0xffffffff, "AK4543", NULL, NULL },
{ 0x414b4d06, 0xffffffff, "AK4544A", NULL }, { 0x414b4d06, 0xffffffff, "AK4544A", NULL, NULL },
{ 0x414b4d07, 0xffffffff, "AK4545", NULL }, { 0x414b4d07, 0xffffffff, "AK4545", NULL, NULL },
{ 0x41445303, 0xffffffff, "AD1819", patch_ad1819 }, { 0x41445303, 0xffffffff, "AD1819", patch_ad1819, NULL },
{ 0x41445340, 0xffffffff, "AD1881", patch_ad1881 }, { 0x41445340, 0xffffffff, "AD1881", patch_ad1881, NULL },
{ 0x41445348, 0xffffffff, "AD1881A", patch_ad1881 }, { 0x41445348, 0xffffffff, "AD1881A", patch_ad1881, NULL },
{ 0x41445360, 0xffffffff, "AD1885", patch_ad1885 }, { 0x41445360, 0xffffffff, "AD1885", patch_ad1885, NULL },
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886 }, { 0x41445361, 0xffffffff, "AD1886", patch_ad1886, NULL },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881 }, { 0x41445362, 0xffffffff, "AD1887", patch_ad1881, NULL },
{ 0x41445363, 0xffffffff, "AD1886A", patch_ad1881 }, { 0x41445363, 0xffffffff, "AD1886A", patch_ad1881, NULL },
{ 0x41445370, 0xffffffff, "AD1980", patch_ad1980 }, { 0x41445370, 0xffffffff, "AD1980", patch_ad1980, NULL },
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1881 }, { 0x41445372, 0xffffffff, "AD1981A", patch_ad1881, NULL },
{ 0x414c4300, 0xfffffff0, "RL5306", NULL }, { 0x414c4300, 0xfffffff0, "RL5306", NULL, NULL },
{ 0x414c4310, 0xfffffff0, "RL5382", NULL }, { 0x414c4310, 0xfffffff0, "RL5382", NULL, NULL },
{ 0x414c4320, 0xfffffff0, "RL5383", NULL }, { 0x414c4320, 0xfffffff0, "RL5383", NULL, NULL },
{ 0x414c4710, 0xfffffff0, "ALC200/200P", NULL }, { 0x414c4710, 0xfffffff0, "ALC200/200P", NULL, NULL },
{ 0x414c4720, 0xfffffff0, "ALC650", patch_alc650 }, { 0x414c4720, 0xfffffff0, "ALC650", patch_alc650, NULL },
{ 0x414c4730, 0xffffffff, "ALC101", NULL }, { 0x414c4730, 0xffffffff, "ALC101", NULL, NULL },
{ 0x414c4740, 0xfffffff0, "ALC202", NULL }, { 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL },
{ 0x414c4750, 0xfffffff0, "ALC250", NULL }, { 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL },
{ 0x434d4941, 0xffffffff, "CMI9738", NULL }, { 0x434d4941, 0xffffffff, "CMI9738", NULL, NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", NULL }, { 0x434d4961, 0xffffffff, "CMI9739", NULL, NULL },
{ 0x43525900, 0xfffffff8, "CS4297", NULL }, { 0x43525900, 0xfffffff8, "CS4297", NULL, NULL },
{ 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif }, { 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif, NULL },
{ 0x43525920, 0xfffffff8, "CS4294/4298", NULL }, { 0x43525920, 0xfffffff8, "CS4294/4298", NULL, NULL },
{ 0x43525928, 0xfffffff8, "CS4294", NULL }, { 0x43525928, 0xfffffff8, "CS4294", NULL, NULL },
{ 0x43525930, 0xfffffff8, "CS4299", patch_cirrus_cs4299 }, { 0x43525930, 0xfffffff8, "CS4299", patch_cirrus_cs4299, NULL },
{ 0x43525948, 0xfffffff8, "CS4201", NULL }, { 0x43525948, 0xfffffff8, "CS4201", NULL, NULL },
{ 0x43525958, 0xfffffff8, "CS4205", patch_cirrus_spdif }, { 0x43525958, 0xfffffff8, "CS4205", patch_cirrus_spdif, NULL },
{ 0x43525960, 0xfffffff8, "CS4291", NULL }, { 0x43525960, 0xfffffff8, "CS4291", NULL, NULL },
{ 0x43585421, 0xffffffff, "HSD11246", NULL }, // SmartMC II { 0x43585421, 0xffffffff, "HSD11246", NULL, NULL }, // SmartMC II
{ 0x43585428, 0xfffffff8, "Cx20468", patch_conexant }, // SmartAMC fixme: the mask might be different { 0x43585428, 0xfffffff8, "Cx20468", patch_conexant, NULL }, // SmartAMC fixme: the mask might be different
{ 0x44543031, 0xfffffff0, "DT0398", NULL }, { 0x44543031, 0xfffffff0, "DT0398", NULL, NULL },
{ 0x454d4328, 0xffffffff, "28028", NULL }, // same as TR28028? { 0x454d4328, 0xffffffff, "28028", NULL, NULL }, // same as TR28028?
{ 0x45838308, 0xffffffff, "ESS1988", NULL }, { 0x45838308, 0xffffffff, "ESS1988", NULL, NULL },
{ 0x48525300, 0xffffff00, "HMP9701", NULL }, { 0x48525300, 0xffffff00, "HMP9701", NULL, NULL },
{ 0x49434501, 0xffffffff, "ICE1230", NULL }, { 0x49434501, 0xffffffff, "ICE1230", NULL, NULL },
{ 0x49434511, 0xffffffff, "ICE1232", NULL }, // alias VIA VT1611A? { 0x49434511, 0xffffffff, "ICE1232", NULL, NULL }, // alias VIA VT1611A?
{ 0x49434551, 0xffffffff, "VT1616", NULL }, { 0x49434551, 0xffffffff, "VT1616", NULL, NULL },
{ 0x49544520, 0xffffffff, "IT2226E", NULL }, { 0x49544520, 0xffffffff, "IT2226E", NULL, NULL },
{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL }, // only guess --jk { 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk
{ 0x4e534331, 0xffffffff, "LM4549", NULL }, { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL },
{ 0x50534304, 0xffffffff, "UCB1400", NULL }, { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL },
{ 0x53494c22, 0xffffffff, "Si3036", NULL }, { 0x53494c22, 0xffffffff, "Si3036", NULL, NULL },
{ 0x53494c23, 0xffffffff, "Si3038", NULL }, { 0x53494c23, 0xffffffff, "Si3038", NULL, NULL },
{ 0x54524102, 0xffffffff, "TR28022", NULL }, { 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
{ 0x54524106, 0xffffffff, "TR28026", NULL }, { 0x54524106, 0xffffffff, "TR28026", NULL, NULL },
{ 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028 }, // added by xin jin [07/09/99] { 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99]
{ 0x54524123, 0xffffffff, "TR28602", NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)] { 0x54524123, 0xffffffff, "TR28602", NULL, NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
{ 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL }, { 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL },
{ 0x56494161, 0xffffffff, "VIA1612A", NULL }, // modified ICE1232 with S/PDIF { 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF
{ 0x57454301, 0xffffffff, "W83971D", NULL }, { 0x57454301, 0xffffffff, "W83971D", NULL, NULL },
{ 0x574d4c00, 0xffffffff, "WM9701A", patch_wolfson00 }, { 0x574d4c00, 0xffffffff, "WM9701A", patch_wolfson00,NULL },
{ 0x574d4c03, 0xffffffff, "WM9703/9707", patch_wolfson03 }, { 0x574d4c03, 0xffffffff, "WM9703/9707", patch_wolfson03,NULL },
{ 0x574d4c04, 0xffffffff, "WM9704/quad", patch_wolfson04 }, { 0x574d4c04, 0xffffffff, "WM9704/quad", patch_wolfson04,NULL },
{ 0x574d4c05, 0xffffffff, "WM9705", NULL }, // patch? { 0x574d4c05, 0xffffffff, "WM9705", NULL, NULL }, // patch?
{ 0x594d4800, 0xffffffff, "YMF743", NULL }, { 0x594d4800, 0xffffffff, "YMF743", NULL, NULL },
{ 0x594d4802, 0xffffffff, "YMF752", NULL }, { 0x594d4802, 0xffffffff, "YMF752", NULL, NULL },
{ 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753 }, { 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL },
{ 0x83847600, 0xffffffff, "STAC9700/83/84", NULL }, { 0x83847600, 0xffffffff, "STAC9700/83/84", NULL, NULL },
{ 0x83847604, 0xffffffff, "STAC9701/3/4/5", NULL }, { 0x83847604, 0xffffffff, "STAC9701/3/4/5", NULL, NULL },
{ 0x83847605, 0xffffffff, "STAC9704", NULL }, { 0x83847605, 0xffffffff, "STAC9704", NULL, NULL },
{ 0x83847608, 0xffffffff, "STAC9708/11", patch_sigmatel_stac9708 }, { 0x83847608, 0xffffffff, "STAC9708/11", patch_sigmatel_stac9708, NULL },
{ 0x83847609, 0xffffffff, "STAC9721/23", patch_sigmatel_stac9721 }, { 0x83847609, 0xffffffff, "STAC9721/23", patch_sigmatel_stac9721, NULL },
{ 0x83847644, 0xffffffff, "STAC9744", patch_sigmatel_stac9744 }, { 0x83847644, 0xffffffff, "STAC9744", patch_sigmatel_stac9744, NULL },
{ 0x83847650, 0xffffffff, "STAC9750/51", NULL }, // patch? { 0x83847650, 0xffffffff, "STAC9750/51", NULL, NULL }, // patch?
{ 0x83847656, 0xffffffff, "STAC9756/57", patch_sigmatel_stac9756 }, { 0x83847656, 0xffffffff, "STAC9756/57", patch_sigmatel_stac9756, NULL },
{ 0x83847666, 0xffffffff, "STAC9766/67", NULL }, // patch? { 0x83847666, 0xffffffff, "STAC9766/67", NULL, NULL }, // patch?
{ 0, 0, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
static const char *snd_ac97_stereo_enhancements[] = 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 ...@@ -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 * Compares the value with the register cache and updates the value
* only when the value is changed. * 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. * code on failure.
*/ */
int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value) 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) ...@@ -352,7 +353,7 @@ int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value)
* @mask: the bit-mask to change * @mask: the bit-mask to change
* @value: the value to set * @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. * is changed.
* *
* Returns 1 if the bits are changed, 0 if no change, or a negative * 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] = { ...@@ -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) 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 * ALC650
*/ */
...@@ -1032,8 +1077,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_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), AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0),
/* 4: Analog Input To Surround */ /* 4: Analog Input To Surround */
/* 5: Analog Input To Center/LFE */ /* 5: Analog Input To Center/LFE */
/* 6: Indepedent Master Volume Right */ /* 6: Independent Master Volume Right */
/* 7: Indepedent Master Volume Left */ /* 7: Independent Master Volume Left */
/* 8: reserved */ /* 8: reserved */
AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 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 ...@@ -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 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. 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. */ 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) 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) ...@@ -1680,6 +1725,9 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
for (idx = 0; idx < 3; idx++) for (idx = 0; idx < 3; idx++)
if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_spdif[idx], ac97))) < 0) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_ymf753_controls_spdif[idx], ac97))) < 0)
return err; 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 */ /* set default PCM S/PDIF params */
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ /* 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) ...@@ -1735,6 +1783,12 @@ static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97)
return 0; 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) static int snd_ac97_test_rate(ac97_t *ac97, int reg, int rate)
{ {
unsigned short val; unsigned short val;
...@@ -1771,7 +1825,7 @@ static void snd_ac97_determine_rates(ac97_t *ac97, int reg, unsigned int *r_resu ...@@ -1771,7 +1825,7 @@ static void snd_ac97_determine_rates(ac97_t *ac97, int reg, unsigned int *r_resu
*r_result = result; *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; const ac97_codec_id_t *pid;
...@@ -1782,8 +1836,12 @@ static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name) ...@@ -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++) for (pid = snd_ac97_codec_id_vendors; pid->id; pid++)
if (pid->id == (id & pid->mask)) { if (pid->id == (id & pid->mask)) {
strcpy(name, pid->name); strcpy(name, pid->name);
if (ac97 && pid->patch) if (ac97) {
if (!modem && pid->patch)
pid->patch(ac97); pid->patch(ac97);
else if (modem && pid->mpatch)
pid->mpatch(ac97);
}
goto __vendor_ok; goto __vendor_ok;
} }
return; return;
...@@ -1795,8 +1853,12 @@ static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name) ...@@ -1795,8 +1853,12 @@ static void snd_ac97_get_name(ac97_t *ac97, unsigned int id, char *name)
strcat(name, pid->name); strcat(name, pid->name);
if (pid->mask != 0xffffffff) if (pid->mask != 0xffffffff)
sprintf(name + strlen(name), " rev %d", id & ~pid->mask); sprintf(name + strlen(name), " rev %d", id & ~pid->mask);
if (ac97 && pid->patch) if (ac97) {
if (!modem && pid->patch)
pid->patch(ac97); pid->patch(ac97);
else if (modem && pid->mpatch)
pid->mpatch(ac97);
}
return; return;
} }
sprintf(name + strlen(name), " id %x", id & 0xff); 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) ...@@ -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 * The template must include the valid callbacks (at least read and
* write), the codec number (num) and address (addr), and the private * write), the codec number (num) and address (addr), and the private
* data (private_data). The other callbacks, wait and reset, are not * 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 * The clock is set to 48000. If another clock is needed, reset
* ac97->clock manually afterwards. * ac97->clock manually afterwards.
...@@ -1858,9 +1920,11 @@ static int ac97_reset_wait(ac97_t *ac97, int timeout, int with_modem) ...@@ -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 * The ac97 instance is registered as a low-level device, so you don't
* have to release it manually. * 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 snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
{ {
int err; int err;
...@@ -1929,8 +1993,8 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97) ...@@ -1929,8 +1993,8 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
goto __ready_ok; goto __ready_ok;
/* FIXME: add powerdown control */ /* FIXME: add powerdown control */
if (ac97_is_audio(ac97)) {
/* nothing should be in powerdown mode */ /* nothing should be in powerdown mode */
if (ac97->scaps & AC97_SCAP_AUDIO) {
snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0); snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
snd_ac97_write_cache_test(ac97, AC97_RESET, 0); /* reset to defaults */ snd_ac97_write_cache_test(ac97, AC97_RESET, 0); /* reset to defaults */
udelay(100); udelay(100);
...@@ -1950,7 +2014,7 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97) ...@@ -1950,7 +2014,7 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
__ready_ok: __ready_ok:
if (ac97->clock == 0) if (ac97->clock == 0)
ac97->clock = 48000; /* standard value */ 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; ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT;
else else
ac97->addr = (ac97->ext_mid & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT; 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) ...@@ -1985,8 +2049,8 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
/* additional initializations */ /* additional initializations */
if (ac97->init) if (ac97->init)
ac97->init(ac97); ac97->init(ac97);
snd_ac97_get_name(ac97, ac97->id, name); snd_ac97_get_name(ac97, ac97->id, name, 0);
snd_ac97_get_name(NULL, ac97->id, name); // ac97->id might be changed in the special setup code snd_ac97_get_name(NULL, ac97->id, name, 0); // ac97->id might be changed in the special setup code
if (card->mixername[0] == '\0') { if (card->mixername[0] == '\0') {
strcpy(card->mixername, name); strcpy(card->mixername, name);
} else { } else {
...@@ -1995,19 +2059,188 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97) ...@@ -1995,19 +2059,188 @@ int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97)
strcat(card->mixername, name); strcat(card->mixername, name);
} }
} }
if (ac97->scaps & AC97_SCAP_AUDIO) { if (ac97_is_audio(ac97)) {
if ((err = snd_component_add(card, "AC97a")) < 0) { if ((err = snd_component_add(card, "AC97a")) < 0) {
snd_ac97_free(ac97); snd_ac97_free(ac97);
return err; 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 (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) { if ((err = snd_component_add(card, "AC97m")) < 0) {
snd_ac97_free(ac97); snd_ac97_free(ac97);
return err; 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); snd_ac97_free(ac97);
return -ENOMEM; return -ENOMEM;
} }
...@@ -2035,7 +2268,7 @@ static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, in ...@@ -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_ID1) << 16;
id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); 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); snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name);
if ((ac97->scaps & AC97_SCAP_AUDIO) == 0) if ((ac97->scaps & AC97_SCAP_AUDIO) == 0)
goto __modem; goto __modem;
...@@ -2430,6 +2663,7 @@ static int remove_ctl(ac97_t *ac97, const char *name) ...@@ -2430,6 +2663,7 @@ static int remove_ctl(ac97_t *ac97, const char *name)
snd_ctl_elem_id_t id; snd_ctl_elem_id_t id;
memset(&id, 0, sizeof(id)); memset(&id, 0, sizeof(id));
strcpy(id.name, name); strcpy(id.name, name);
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_remove_id(ac97->card, &id); 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) ...@@ -2438,8 +2672,10 @@ static int rename_ctl(ac97_t *ac97, const char *src, const char *dst)
snd_ctl_elem_id_t sid, did; snd_ctl_elem_id_t sid, did;
memset(&sid, 0, sizeof(sid)); memset(&sid, 0, sizeof(sid));
strcpy(sid.name, src); strcpy(sid.name, src);
sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
memset(&did, 0, sizeof(did)); memset(&did, 0, sizeof(did));
strcpy(did.name, dst); strcpy(did.name, dst);
did.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
return snd_ctl_rename_id(ac97->card, &sid, &did); 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 ...@@ -2476,19 +2712,21 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct pci_dev *pci, struct ac97_quirk
{ {
unsigned short vendor, device; 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_VENDOR_ID, &vendor);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &device); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &device);
for (; quirk->vendor; quirk++) { for (; quirk->vendor; quirk++) {
if (quirk->vendor == vendor && quirk->device == device) { 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) { switch (quirk->type) {
case AC97_TUNE_HP_ONLY: case AC97_TUNE_HP_ONLY:
return swap_headphone(ac97, 1); return swap_headphone(ac97, 1);
case AC97_TUNE_SWAP_HP: case AC97_TUNE_SWAP_HP:
return swap_headphone(ac97, 0); 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; return -EINVAL;
} }
} }
...@@ -2506,6 +2744,7 @@ EXPORT_SYMBOL(snd_ac97_write_cache); ...@@ -2506,6 +2744,7 @@ EXPORT_SYMBOL(snd_ac97_write_cache);
EXPORT_SYMBOL(snd_ac97_update); EXPORT_SYMBOL(snd_ac97_update);
EXPORT_SYMBOL(snd_ac97_update_bits); EXPORT_SYMBOL(snd_ac97_update_bits);
EXPORT_SYMBOL(snd_ac97_mixer); EXPORT_SYMBOL(snd_ac97_mixer);
EXPORT_SYMBOL(snd_ac97_modem);
EXPORT_SYMBOL(snd_ac97_set_rate); EXPORT_SYMBOL(snd_ac97_set_rate);
EXPORT_SYMBOL(snd_ac97_tune_hardware); EXPORT_SYMBOL(snd_ac97_tune_hardware);
#ifdef CONFIG_PM #ifdef CONFIG_PM
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define AC97_ID_AD1886 0x41445361 #define AC97_ID_AD1886 0x41445361
#define AC97_ID_AD1887 0x41445362 #define AC97_ID_AD1887 0x41445362
#define AC97_ID_AD1886A 0x41445363 #define AC97_ID_AD1886A 0x41445363
#define AC97_ID_AD1980 0x41445370
#define AC97_ID_TR28028 0x54524108 #define AC97_ID_TR28028 0x54524108
#define AC97_ID_STAC9700 0x83847600 #define AC97_ID_STAC9700 0x83847600
#define AC97_ID_STAC9704 0x83847604 #define AC97_ID_STAC9704 0x83847604
......
...@@ -672,28 +672,21 @@ static void snd_cs46xx_set_capture_sample_rate(cs46xx_t *chip, unsigned int rate ...@@ -672,28 +672,21 @@ static void snd_cs46xx_set_capture_sample_rate(cs46xx_t *chip, unsigned int rate
* PCM part * PCM part
*/ */
static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream, static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream)
snd_pcm_uframes_t frames)
{ {
/* cs46xx_t *chip = snd_pcm_substream_chip(substream); */ /* cs46xx_t *chip = snd_pcm_substream_chip(substream); */
snd_pcm_runtime_t *runtime = substream->runtime; 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_uframes_t appl_ptr = runtime->control->appl_ptr;
snd_pcm_sframes_t diff; snd_pcm_sframes_t diff = appl_ptr - cpcm->appl_ptr;
cs46xx_pcm_t * cpcm; int buffer_size = runtime->period_size * CS46XX_FRAGS << cpcm->shift;
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;
diff = appl_ptr - cpcm->appl_ptr;
if (diff) { if (diff) {
if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
diff += runtime->boundary; 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 && while (cpcm->hw_ready < buffer_size &&
cpcm->sw_ready > 0) { cpcm->sw_ready > 0) {
size_t hw_to_end = buffer_size - cpcm->hw_data; 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, ...@@ -720,21 +713,20 @@ static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream,
return 0; return 0;
} }
static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream, static int snd_cs46xx_capture_transfer(snd_pcm_substream_t *substream)
snd_pcm_uframes_t frames)
{ {
cs46xx_t *chip = snd_pcm_substream_chip(substream); cs46xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr; snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
snd_pcm_sframes_t diff = appl_ptr - chip->capt.appl_ptr; snd_pcm_sframes_t diff = appl_ptr - chip->capt.appl_ptr;
int buffer_size = runtime->period_size * CS46XX_FRAGS << chip->capt.shift; int buffer_size = runtime->period_size * CS46XX_FRAGS << chip->capt.shift;
if (diff) { if (diff) {
if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
diff += runtime->boundary; 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 && while (chip->capt.hw_ready > 0 &&
chip->capt.sw_ready < (int)chip->capt.sw_bufsize) { chip->capt.sw_ready < (int)chip->capt.sw_bufsize) {
size_t hw_to_end = buffer_size - chip->capt.hw_data; 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_ ...@@ -802,7 +794,7 @@ static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(snd_pcm_substream_
cpcm->sw_io += bytes; cpcm->sw_io += bytes;
if (cpcm->sw_io >= cpcm->sw_bufsize) if (cpcm->sw_io >= cpcm->sw_bufsize)
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; return cpcm->sw_io >> cpcm->shift;
} }
...@@ -827,57 +819,10 @@ static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t ...@@ -827,57 +819,10 @@ static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t
chip->capt.sw_io += bytes; chip->capt.sw_io += bytes;
if (chip->capt.sw_io >= chip->capt.sw_bufsize) if (chip->capt.sw_io >= chip->capt.sw_bufsize)
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; 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, static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
int cmd) int cmd)
{ {
...@@ -909,10 +854,10 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream, ...@@ -909,10 +854,10 @@ static int snd_cs46xx_playback_trigger(snd_pcm_substream_t * substream,
cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel); cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);
if (substream->runtime->periods != CS46XX_FRAGS) if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream, 0); snd_cs46xx_playback_transfer(substream);
#else #else
if (substream->runtime->periods != CS46XX_FRAGS) if (substream->runtime->periods != CS46XX_FRAGS)
snd_cs46xx_playback_transfer(substream, 0); snd_cs46xx_playback_transfer(substream);
{ unsigned int tmp; { unsigned int tmp;
tmp = snd_cs46xx_peek(chip, BA1_PCTL); tmp = snd_cs46xx_peek(chip, BA1_PCTL);
tmp &= 0x0000ffff; tmp &= 0x0000ffff;
...@@ -1587,8 +1532,8 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops = { ...@@ -1587,8 +1532,8 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops = {
.hw_free = snd_cs46xx_playback_hw_free, .hw_free = snd_cs46xx_playback_hw_free,
.prepare = snd_cs46xx_playback_prepare, .prepare = snd_cs46xx_playback_prepare,
.trigger = snd_cs46xx_playback_trigger, .trigger = snd_cs46xx_playback_trigger,
.copy = snd_cs46xx_playback_copy,
.pointer = snd_cs46xx_playback_indirect_pointer, .pointer = snd_cs46xx_playback_indirect_pointer,
.ack = snd_cs46xx_playback_transfer,
}; };
snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = { snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = {
...@@ -1610,8 +1555,8 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops = { ...@@ -1610,8 +1555,8 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops = {
.hw_free = snd_cs46xx_playback_hw_free, .hw_free = snd_cs46xx_playback_hw_free,
.prepare = snd_cs46xx_playback_prepare, .prepare = snd_cs46xx_playback_prepare,
.trigger = snd_cs46xx_playback_trigger, .trigger = snd_cs46xx_playback_trigger,
.copy = snd_cs46xx_playback_copy,
.pointer = snd_cs46xx_playback_indirect_pointer, .pointer = snd_cs46xx_playback_indirect_pointer,
.ack = snd_cs46xx_playback_transfer,
}; };
#endif #endif
...@@ -1635,8 +1580,8 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_ops = { ...@@ -1635,8 +1580,8 @@ snd_pcm_ops_t snd_cs46xx_playback_indirect_ops = {
.hw_free = snd_cs46xx_playback_hw_free, .hw_free = snd_cs46xx_playback_hw_free,
.prepare = snd_cs46xx_playback_prepare, .prepare = snd_cs46xx_playback_prepare,
.trigger = snd_cs46xx_playback_trigger, .trigger = snd_cs46xx_playback_trigger,
.copy = snd_cs46xx_playback_copy,
.pointer = snd_cs46xx_playback_indirect_pointer, .pointer = snd_cs46xx_playback_indirect_pointer,
.ack = snd_cs46xx_playback_transfer,
}; };
snd_pcm_ops_t snd_cs46xx_capture_ops = { snd_pcm_ops_t snd_cs46xx_capture_ops = {
...@@ -1658,8 +1603,8 @@ snd_pcm_ops_t snd_cs46xx_capture_indirect_ops = { ...@@ -1658,8 +1603,8 @@ snd_pcm_ops_t snd_cs46xx_capture_indirect_ops = {
.hw_free = snd_cs46xx_capture_hw_free, .hw_free = snd_cs46xx_capture_hw_free,
.prepare = snd_cs46xx_capture_prepare, .prepare = snd_cs46xx_capture_prepare,
.trigger = snd_cs46xx_capture_trigger, .trigger = snd_cs46xx_capture_trigger,
.copy = snd_cs46xx_capture_copy,
.pointer = snd_cs46xx_capture_indirect_pointer, .pointer = snd_cs46xx_capture_indirect_pointer,
.ack = snd_cs46xx_capture_transfer,
}; };
static void snd_cs46xx_pcm_free(snd_pcm_t *pcm) static void snd_cs46xx_pcm_free(snd_pcm_t *pcm)
...@@ -2505,9 +2450,6 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip) ...@@ -2505,9 +2450,6 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
strcpy(id.name, "External Amplifier Power Down"); strcpy(id.name, "External Amplifier Power Down");
chip->eapd_switch = snd_ctl_find_id(chip->card, &id); chip->eapd_switch = snd_ctl_find_id(chip->card, &id);
/* turn on amplifier */
chip->amplifier_ctrl(chip, 1);
#ifdef CONFIG_SND_CS46XX_NEW_DSP #ifdef CONFIG_SND_CS46XX_NEW_DSP
/* do soundcard specific mixer setup */ /* do soundcard specific mixer setup */
if (chip->mixer_init) { if (chip->mixer_init) {
...@@ -2516,6 +2458,9 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip) ...@@ -2516,6 +2458,9 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
} }
#endif #endif
/* turn on amplifier */
chip->amplifier_ctrl(chip, 1);
return 0; return 0;
} }
......
...@@ -520,8 +520,7 @@ static void snd_emu10k1_fx8010_playback_tram_poke(emu10k1_t *emu, ...@@ -520,8 +520,7 @@ static void snd_emu10k1_fx8010_playback_tram_poke(emu10k1_t *emu,
*tram_pos -= frames; *tram_pos -= frames;
} }
static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream, static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream)
snd_pcm_uframes_t frames)
{ {
emu10k1_t *emu = snd_pcm_substream_chip(substream); emu10k1_t *emu = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
...@@ -529,13 +528,13 @@ static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream, ...@@ -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_uframes_t appl_ptr = runtime->control->appl_ptr;
snd_pcm_sframes_t diff = appl_ptr - pcm->appl_ptr; snd_pcm_sframes_t diff = appl_ptr - pcm->appl_ptr;
snd_pcm_uframes_t buffer_size = pcm->buffer_size / 2; snd_pcm_uframes_t buffer_size = pcm->buffer_size / 2;
if (diff) { if (diff) {
if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2)) if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
diff += runtime->boundary; 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 && while (pcm->hw_ready < buffer_size &&
pcm->sw_ready > 0) { pcm->sw_ready > 0) {
size_t hw_to_end = buffer_size - pcm->hw_data; 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, ...@@ -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); result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq);
if (result < 0) if (result < 0)
goto __err; 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); snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
...@@ -670,28 +669,10 @@ static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(snd_pcm_substream_t ...@@ -670,28 +669,10 @@ static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(snd_pcm_substream_t
pcm->sw_io += frames; pcm->sw_io += frames;
if (pcm->sw_io > runtime->buffer_size) if (pcm->sw_io > runtime->buffer_size)
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; 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 = static snd_pcm_hardware_t snd_emu10k1_fx8010_playback =
{ {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
...@@ -748,8 +729,8 @@ static snd_pcm_ops_t snd_emu10k1_fx8010_playback_ops = { ...@@ -748,8 +729,8 @@ static snd_pcm_ops_t snd_emu10k1_fx8010_playback_ops = {
.hw_free = snd_emu10k1_fx8010_playback_hw_free, .hw_free = snd_emu10k1_fx8010_playback_hw_free,
.prepare = snd_emu10k1_fx8010_playback_prepare, .prepare = snd_emu10k1_fx8010_playback_prepare,
.trigger = snd_emu10k1_fx8010_playback_trigger, .trigger = snd_emu10k1_fx8010_playback_trigger,
.copy = snd_emu10k1_fx8010_playback_copy,
.pointer = snd_emu10k1_fx8010_playback_pointer, .pointer = snd_emu10k1_fx8010_playback_pointer,
.ack = snd_emu10k1_fx8010_playback_transfer,
}; };
static void snd_emu10k1_fx8010_pcm_free(snd_pcm_t *pcm) static void snd_emu10k1_fx8010_pcm_free(snd_pcm_t *pcm)
...@@ -1252,12 +1233,14 @@ static void __devinit snd_emu10k1_init_stereo_onoff_control(emu10k1_fx8010_contr ...@@ -1252,12 +1233,14 @@ static void __devinit snd_emu10k1_init_stereo_onoff_control(emu10k1_fx8010_contr
* initial DSP configuration for Audigy * initial DSP configuration for Audigy
*/ */
#define A_GPR_ACCU 0xd6
static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) 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; u32 ptr;
emu10k1_fx8010_code_t *icode; emu10k1_fx8010_code_t *icode;
emu10k1_fx8010_control_gpr_t *controls; emu10k1_fx8010_control_gpr_t *controls, *ctl;
mm_segment_t seg; mm_segment_t seg;
spin_lock_init(&emu->fx8010.irq_lock); spin_lock_init(&emu->fx8010.irq_lock);
...@@ -1278,9 +1261,9 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) ...@@ -1278,9 +1261,9 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu)
ptr = 0; ptr = 0;
nctl = 0; nctl = 0;
playback = 10; playback = 10;
capture = playback + 10; /* we reserve 10 voices */ capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
gpr = capture + 10; gpr = capture + 10;
tmp = 0x80; tmp = 0x88;
/* stop FX processor */ /* stop FX processor */
snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); 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)) ...@@ -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) \ #define A_PUT_STEREO_OUTPUT(out1,out2,src) \
{A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);} {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 */ /* digital outputs */
A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback); 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); 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); A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5); A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
/* analog speakers */ /* analog speakers */
//A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback); //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); 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); 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); A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5); A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
/* headphone */ /* 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 */ /* ADC buffer */
A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture); A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
......
...@@ -1508,12 +1508,16 @@ static struct _ac97_ali_rate_regs { ...@@ -1508,12 +1508,16 @@ static struct _ac97_ali_rate_regs {
{ ALID_SPDIFIN, { 0, 0, 0 }, -1 }, { 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) static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
{ {
ac97_t ac97, *x97; ac97_t ac97, *x97;
ichdev_t *ichdev; ichdev_t *ichdev;
int err, i, channels = 2, codecs; int err, i, num, channels = 2, codecs, _codecs;
unsigned int glob_sta = 0; unsigned int glob_sta = 0;
for (i = 0; i <= ICHD_LAST; i++) { for (i = 0; i <= ICHD_LAST; i++) {
...@@ -1589,6 +1593,7 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) ...@@ -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) if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0)
return err; return err;
chip->ac97[0] = x97; chip->ac97[0] = x97;
snd_ac97_tune_hardware(chip->ac97[0], chip->pci, ac97_quirks);
chip->ichd[ICHD_PCMOUT].ac97 = x97; chip->ichd[ICHD_PCMOUT].ac97 = x97;
chip->ichd[ICHD_PCMIN].ac97 = x97; chip->ichd[ICHD_PCMIN].ac97 = x97;
if (x97->ext_id & AC97_EI_VRM) if (x97->ext_id & AC97_EI_VRM)
...@@ -1604,20 +1609,20 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) ...@@ -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); snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 0);
/* AnalogDevices CNR boards uses special codec chaining */ /* AnalogDevices CNR boards uses special codec chaining */
/* skip standard test method for secondary codecs in this case */ /* skip standard test method for secondary codecs in this case */
if (x97->flags & AC97_AD_MULTI) { if (x97->flags & AC97_AD_MULTI)
codecs = 1; codecs = 1;
goto __skip_secondary;
}
if (codecs < 2) if (codecs < 2)
goto __skip_secondary; goto __skip_secondary;
for (i = 1; i < codecs; i++) { for (i = 1, num = 1, _codecs = codecs; num < _codecs; num++) {
ac97.num = i; ac97.num = num;
if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0) { 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); snd_printk("Unable to initialize codec #%i [device = %i, GLOB_STA = 0x%x]\n", i, chip->device_type, glob_sta);
codecs = i; codecs--;
break; continue;
} }
chip->ac97[i] = x97; chip->ac97[i++] = x97;
if (!ac97_is_audio(x97))
continue;
switch (chip->device_type) { switch (chip->device_type) {
case DEVICE_INTEL_ICH4: case DEVICE_INTEL_ICH4:
if (chip->ichd[ICHD_PCM2IN].ac97 == NULL) if (chip->ichd[ICHD_PCM2IN].ac97 == NULL)
...@@ -1656,14 +1661,16 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) ...@@ -1656,14 +1661,16 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
} }
iputbyte(chip, ICHREG(SDM), tmp); iputbyte(chip, ICHREG(SDM), tmp);
} }
for (i = 0; i < 3; i++) { for (i = 0; i < codecs; i++) {
if ((x97 = chip->ac97[i]) == NULL) x97 = chip->ac97[i];
if (!ac97_is_audio(x97))
continue; continue;
if (x97->scaps & AC97_SCAP_SURROUND_DAC) if (x97->scaps & AC97_SCAP_SURROUND_DAC)
chip->multi4 = 1; chip->multi4 = 1;
} }
for (i = 0; i < 3 && chip->multi4; i++) { for (i = 0; i < codecs && chip->multi4; i++) {
if ((x97 = chip->ac97[i]) == NULL) x97 = chip->ac97[i];
if (!ac97_is_audio(x97))
continue; continue;
if (x97->scaps & AC97_SCAP_CENTER_LFE_DAC) if (x97->scaps & AC97_SCAP_CENTER_LFE_DAC)
chip->multi6 = 1; chip->multi6 = 1;
...@@ -1674,7 +1681,10 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) ...@@ -1674,7 +1681,10 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
if (chip->multi4) if (chip->multi4)
goto __6ch; goto __6ch;
for ( ; i < codecs; i++) { 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); snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 1);
chip->multi4 = 1; chip->multi4 = 1;
break; break;
...@@ -1682,7 +1692,10 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) ...@@ -1682,7 +1692,10 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
} }
__6ch: __6ch:
for ( ; i < codecs && chip->multi4; i++) { 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); snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 2);
chip->multi6 = 1; chip->multi6 = 1;
break; break;
...@@ -1691,7 +1704,10 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) ...@@ -1691,7 +1704,10 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
/* ok, some older codecs might support only AMAP */ /* ok, some older codecs might support only AMAP */
if (!chip->multi4) { if (!chip->multi4) {
for (i = 1; i < codecs; i++) { 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) { if (x97->addr == 1) {
chip->multi4 = 1; chip->multi4 = 1;
break; break;
...@@ -1699,7 +1715,9 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) ...@@ -1699,7 +1715,9 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
} }
} }
for ( ; i < codecs && chip->multi4; i++) { 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) { if (x97->addr == 2) {
chip->multi6 = 1; chip->multi6 = 1;
break; break;
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#define K1212_DEBUG_LEVEL 0 #define K1212_DEBUG_LEVEL 0
#define K1212_DEBUG_PRINTK printk #define K1212_DEBUG_PRINTK printk
//#define K1212_DEBUG_PRINTK(x...) printk("<0>" x)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Record/Play Buffer Allocation Method. If K1212_LARGEALLOC is defined all // Record/Play Buffer Allocation Method. If K1212_LARGEALLOC is defined all
...@@ -178,13 +179,21 @@ typedef enum { ...@@ -178,13 +179,21 @@ typedef enum {
#define kAudioChannels (k16BitChannels + k32BitChannels) #define kAudioChannels (k16BitChannels + k32BitChannels)
#define kPlayBufferFrames 1024 #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_FRAME_SIZE (sizeof(KorgAudioFrame))
#define K1212_MAX_SAMPLES (kPlayBufferFrames*kNumBuffers) #define K1212_MAX_SAMPLES (kPlayBufferFrames*kNumBuffers)
#define K1212_PERIODS (K1212_BUF_SIZE/K1212_BLOCK_SIZE) #define K1212_PERIODS (kNumBuffers)
#define K1212_PERIOD_BYTES (K1212_BLOCK_SIZE) #define K1212_PERIOD_BYTES (K1212_FRAME_SIZE*kPlayBufferFrames)
#define K1212_BLOCK_SIZE (K1212_FRAME_SIZE*kPlayBufferFrames) #define K1212_BUF_SIZE (K1212_PERIOD_BYTES*kNumBuffers)
#define K1212_BUF_SIZE (K1212_BLOCK_SIZE*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 k1212MinADCSens 0x7f
#define k1212MaxADCSens 0x00 #define k1212MaxADCSens 0x00
...@@ -314,9 +323,9 @@ typedef struct SensBits { ...@@ -314,9 +323,9 @@ typedef struct SensBits {
} SensBits; } SensBits;
struct _snd_korg1212 { struct _snd_korg1212 {
struct pci_dev *pci;
snd_card_t *card; snd_card_t *card;
snd_pcm_t *pcm16; struct pci_dev *pci;
snd_pcm_t *pcm;
int irq; int irq;
spinlock_t lock; spinlock_t lock;
...@@ -362,9 +371,9 @@ struct _snd_korg1212 { ...@@ -362,9 +371,9 @@ struct _snd_korg1212 {
u16 * sensRegPtr; // address of the sensitivity setting register u16 * sensRegPtr; // address of the sensitivity setting register
u32 * idRegPtr; // address of the device and vendor ID registers u32 * idRegPtr; // address of the device and vendor ID registers
size_t periodsize; size_t periodsize;
size_t currentBuffer; int channels;
int currentBuffer;
snd_pcm_substream_t *playback_substream; snd_pcm_substream_t *playback_substream;
snd_pcm_substream_t *capture_substream; snd_pcm_substream_t *capture_substream;
...@@ -383,6 +392,11 @@ struct _snd_korg1212 { ...@@ -383,6 +392,11 @@ struct _snd_korg1212 {
u16 leftADCInSens; // ADC left channel input sensitivity u16 leftADCInSens; // ADC left channel input sensitivity
u16 rightADCInSens; // ADC right 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"); MODULE_DESCRIPTION("korg1212");
...@@ -465,7 +479,6 @@ u16 ClockSourceSelector[] = {0x8000, // selects source as ADAT at 44.1 kHz ...@@ -465,7 +479,6 @@ u16 ClockSourceSelector[] = {0x8000, // selects source as ADAT at 44.1 kHz
static snd_korg1212rc rc; static snd_korg1212rc rc;
MODULE_DEVICE_TABLE(pci, snd_korg1212_ids); MODULE_DEVICE_TABLE(pci, snd_korg1212_ids);
typedef union swap_u32 { unsigned char c[4]; u32 i; } swap_u32; typedef union swap_u32 { unsigned char c[4]; u32 i; } swap_u32;
...@@ -521,11 +534,6 @@ static u32 EndianSwap(u32 swappee) ...@@ -521,11 +534,6 @@ static u32 EndianSwap(u32 swappee)
#endif /* not used */ #endif /* not used */
void TickDelay(int time)
{
udelay(time);
}
#define SetBitInWord(theWord,bitPosition) (*theWord) |= (0x0001 << bitPosition) #define SetBitInWord(theWord,bitPosition) (*theWord) |= (0x0001 << bitPosition)
#define SetBitInDWord(theWord,bitPosition) (*theWord) |= (0x00000001 << bitPosition) #define SetBitInDWord(theWord,bitPosition) (*theWord) |= (0x00000001 << bitPosition)
#define ClearBitInWord(theWord,bitPosition) (*theWord) &= ~(0x0001 << bitPosition) #define ClearBitInWord(theWord,bitPosition) (*theWord) &= ~(0x0001 << bitPosition)
...@@ -536,13 +544,19 @@ static snd_korg1212rc snd_korg1212_Send1212Command(korg1212_t *korg1212, korg121 ...@@ -536,13 +544,19 @@ static snd_korg1212rc snd_korg1212_Send1212Command(korg1212_t *korg1212, korg121
{ {
u32 retryCount; u32 retryCount;
u16 mailBox3Lo; 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 #if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- 0x%08x 0x%08x [%s]\n", doorbellVal, mailBox0Val, stateName[korg1212->cardState]); K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- 0x%08x 0x%08x [%s]\n", doorbellVal, mailBox0Val, stateName[korg1212->cardState]);
#endif #endif
for (retryCount = 0; retryCount < MAX_COMMAND_RETRIES; retryCount++) { for (retryCount = 0; retryCount < MAX_COMMAND_RETRIES; retryCount++) {
writel(mailBox3Val, korg1212->mailbox3Ptr); writel(mailBox3Val, korg1212->mailbox3Ptr);
writel(mailBox2Val, korg1212->mailbox2Ptr); writel(mailBox2Val, korg1212->mailbox2Ptr);
writel(mailBox1Val, korg1212->mailbox1Ptr); writel(mailBox1Val, korg1212->mailbox1Ptr);
...@@ -552,12 +566,10 @@ static snd_korg1212rc snd_korg1212_Send1212Command(korg1212_t *korg1212, korg121 ...@@ -552,12 +566,10 @@ static snd_korg1212rc snd_korg1212_Send1212Command(korg1212_t *korg1212, korg121
// -------------------------------------------------------------- // --------------------------------------------------------------
// the reboot command will not give an acknowledgement. // the reboot command will not give an acknowledgement.
// -------------------------------------------------------------- // --------------------------------------------------------------
switch (doorbellVal) { if ( doorbellVal == K1212_DB_RebootCard ||
case K1212_DB_RebootCard: doorbellVal == K1212_DB_BootFromDSPPage4 ||
case K1212_DB_BootFromDSPPage4: doorbellVal == K1212_DB_StartDSPDownload ) {
case K1212_DB_StartDSPDownload: rc = K1212_CMDRET_Success;
return K1212_CMDRET_Success;
default:
break; break;
} }
...@@ -566,46 +578,61 @@ static snd_korg1212rc snd_korg1212_Send1212Command(korg1212_t *korg1212, korg121 ...@@ -566,46 +578,61 @@ static snd_korg1212rc snd_korg1212_Send1212Command(korg1212_t *korg1212, korg121
// read in the low word of mailbox3. If the MSB is set and the // 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. // low byte is equal to the doorbell value, then it ack'd.
// -------------------------------------------------------------- // --------------------------------------------------------------
TickDelay(COMMAND_ACK_DELAY); udelay(COMMAND_ACK_DELAY);
mailBox3Lo = readl(korg1212->mailbox3Ptr); mailBox3Lo = readl(korg1212->mailbox3Ptr);
if (mailBox3Lo & COMMAND_ACK_MASK) { if (mailBox3Lo & COMMAND_ACK_MASK) {
if ((mailBox3Lo & DOORBELL_VAL_MASK) == (doorbellVal & DOORBELL_VAL_MASK)) { if ((mailBox3Lo & DOORBELL_VAL_MASK) == (doorbellVal & DOORBELL_VAL_MASK)) {
korg1212->cmdRetryCount += retryCount; #if K1212_DEBUG_LEVEL > 1
return K1212_CMDRET_Success; K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- Success\n");
#endif
rc = K1212_CMDRET_Success;
break;
} }
} }
} }
korg1212->cmdRetryCount += retryCount; korg1212->cmdRetryCount += retryCount;
return K1212_CMDRET_NoAckFromCard;
} else { if (retryCount >= MAX_COMMAND_RETRIES) {
return K1212_CMDRET_CardUninitialized; #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) static void snd_korg1212_WaitForCardStopAck(korg1212_t *korg1212)
{ {
unsigned long endtime = jiffies + 20 * HZ; u32 endtime = jiffies + 2 * HZ;
#if K1212_DEBUG_LEVEL > 0 #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 #endif
if (korg1212->inIRQ) if (korg1212->inIRQ)
return; return;
do { 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; return;
}
if (!korg1212->inIRQ) if (!korg1212->inIRQ)
schedule(); schedule();
} while (time_before(jiffies, endtime)); } 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); writel(0, &korg1212->sharedBufferPtr->cardCommand);
} }
static void snd_korg1212_TurnOnIdleMonitor(korg1212_t *korg1212) static void snd_korg1212_TurnOnIdleMonitor(korg1212_t *korg1212)
{ {
TickDelay(INTERCOMMAND_DELAY); udelay(INTERCOMMAND_DELAY);
korg1212->idleMonitorOn = 1; korg1212->idleMonitorOn = 1;
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode, rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
K1212_MODE_MonitorOn, 0, 0, 0); K1212_MODE_MonitorOn, 0, 0, 0);
...@@ -641,8 +668,9 @@ static void snd_korg1212_setCardState(korg1212_t * korg1212, CardState csState) ...@@ -641,8 +668,9 @@ static void snd_korg1212_setCardState(korg1212_t * korg1212, CardState csState)
static int snd_korg1212_OpenCard(korg1212_t * korg1212) static int snd_korg1212_OpenCard(korg1212_t * korg1212)
{ {
#if K1212_DEBUG_LEVEL > 0 #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 #endif
if (korg1212->opencnt++ == 0)
snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN); snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
return 1; return 1;
} }
...@@ -650,9 +678,12 @@ static int snd_korg1212_OpenCard(korg1212_t * korg1212) ...@@ -650,9 +678,12 @@ static int snd_korg1212_OpenCard(korg1212_t * korg1212)
static int snd_korg1212_CloseCard(korg1212_t * korg1212) static int snd_korg1212_CloseCard(korg1212_t * korg1212)
{ {
#if K1212_DEBUG_LEVEL > 0 #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 #endif
if (--(korg1212->opencnt))
return 0;
if (korg1212->cardState == K1212_STATE_SETUP) { if (korg1212->cardState == K1212_STATE_SETUP) {
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode, rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
K1212_MODE_StopPlay, 0, 0, 0); K1212_MODE_StopPlay, 0, 0, 0);
...@@ -676,9 +707,12 @@ static int snd_korg1212_CloseCard(korg1212_t * korg1212) ...@@ -676,9 +707,12 @@ static int snd_korg1212_CloseCard(korg1212_t * korg1212)
static int snd_korg1212_SetupForPlay(korg1212_t * korg1212) static int snd_korg1212_SetupForPlay(korg1212_t * korg1212)
{ {
#if K1212_DEBUG_LEVEL > 0 #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 #endif
if (korg1212->setcnt++)
return 0;
snd_korg1212_setCardState(korg1212, K1212_STATE_SETUP); snd_korg1212_setCardState(korg1212, K1212_STATE_SETUP);
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode, rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
K1212_MODE_SetupPlay, 0, 0, 0); K1212_MODE_SetupPlay, 0, 0, 0);
...@@ -687,17 +721,20 @@ static int snd_korg1212_SetupForPlay(korg1212_t * korg1212) ...@@ -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]); if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: SetupForPlay - RC = %d [%s]\n", rc, stateName[korg1212->cardState]);
#endif #endif
if (rc != K1212_CMDRET_Success) { if (rc != K1212_CMDRET_Success) {
return 0;
}
return 1; return 1;
}
return 0;
} }
static int snd_korg1212_TriggerPlay(korg1212_t * korg1212) static int snd_korg1212_TriggerPlay(korg1212_t * korg1212)
{ {
#if K1212_DEBUG_LEVEL > 0 #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 #endif
if (korg1212->playcnt++)
return 0;
snd_korg1212_setCardState(korg1212, K1212_STATE_PLAYING); snd_korg1212_setCardState(korg1212, K1212_STATE_PLAYING);
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_TriggerPlay, 0, 0, 0, 0); rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_TriggerPlay, 0, 0, 0, 0);
...@@ -706,23 +743,28 @@ static int snd_korg1212_TriggerPlay(korg1212_t * korg1212) ...@@ -706,23 +743,28 @@ static int snd_korg1212_TriggerPlay(korg1212_t * korg1212)
#endif #endif
if (rc != K1212_CMDRET_Success) { if (rc != K1212_CMDRET_Success) {
return 0;
}
return 1; return 1;
}
return 0;
} }
static int snd_korg1212_StopPlay(korg1212_t * korg1212) static int snd_korg1212_StopPlay(korg1212_t * korg1212)
{ {
#if K1212_DEBUG_LEVEL > 0 #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 #endif
if (--(korg1212->playcnt))
return 0;
korg1212->setcnt = 0;
if (korg1212->cardState != K1212_STATE_ERRORSTOP) { if (korg1212->cardState != K1212_STATE_ERRORSTOP) {
writel(0xffffffff, &korg1212->sharedBufferPtr->cardCommand); writel(0xffffffff, &korg1212->sharedBufferPtr->cardCommand);
snd_korg1212_WaitForCardStopAck(korg1212); snd_korg1212_WaitForCardStopAck(korg1212);
} }
snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN); snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
return 1; return 0;
} }
static void snd_korg1212_EnableCardInterrupts(korg1212_t * korg1212) static void snd_korg1212_EnableCardInterrupts(korg1212_t * korg1212)
...@@ -802,7 +844,7 @@ static int snd_korg1212_SetRate(korg1212_t *korg1212, int rate) ...@@ -802,7 +844,7 @@ static int snd_korg1212_SetRate(korg1212_t *korg1212, int rate)
korg1212->clkSrcRate = parm; korg1212->clkSrcRate = parm;
korg1212->clkRate = rate; korg1212->clkRate = rate;
TickDelay(INTERCOMMAND_DELAY); udelay(INTERCOMMAND_DELAY);
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SetClockSourceRate, rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SetClockSourceRate,
ClockSourceSelector[korg1212->clkSrcRate], ClockSourceSelector[korg1212->clkSrcRate],
0, 0, 0); 0, 0, 0);
...@@ -869,7 +911,7 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212) ...@@ -869,7 +911,7 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
// flag. Also, clear out mailbox 3, so we don't lockup. // flag. Also, clear out mailbox 3, so we don't lockup.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
writel(0, korg1212->mailbox3Ptr); 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 // 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) ...@@ -910,7 +952,7 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
ClearBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS); ClearBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS);
ClearBitInWord(&controlValue, SET_SENS_DATA_BITPOS); ClearBitInWord(&controlValue, SET_SENS_DATA_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // load/shift goes low writew(controlValue, korg1212->sensRegPtr); // load/shift goes low
TickDelay(LOADSHIFT_DELAY); udelay(LOADSHIFT_DELAY);
for (bitPosition = 15; bitPosition >= 0; bitPosition--) { // for all the bits for (bitPosition = 15; bitPosition >= 0; bitPosition--) { // for all the bits
if (channel == 0) { if (channel == 0) {
...@@ -929,10 +971,10 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212) ...@@ -929,10 +971,10 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS); ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes low writew(controlValue, korg1212->sensRegPtr); // clock goes low
TickDelay(SENSCLKPULSE_WIDTH); udelay(SENSCLKPULSE_WIDTH);
SetBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS); SetBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes high 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) ...@@ -943,19 +985,19 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS); ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
SetBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS); SetBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // load shift goes high - clk low writew(controlValue, korg1212->sensRegPtr); // load shift goes high - clk low
TickDelay(SENSCLKPULSE_WIDTH); udelay(SENSCLKPULSE_WIDTH);
if (clkIs48K) if (clkIs48K)
SetBitInWord(&controlValue, SET_SENS_DATA_BITPOS); SetBitInWord(&controlValue, SET_SENS_DATA_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // set/clear data bit writew(controlValue, korg1212->sensRegPtr); // set/clear data bit
TickDelay(ONE_RTC_TICK); udelay(ONE_RTC_TICK);
SetBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS); SetBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes high writew(controlValue, korg1212->sensRegPtr); // clock goes high
TickDelay(SENSCLKPULSE_WIDTH); udelay(SENSCLKPULSE_WIDTH);
ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS); ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes low 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) ...@@ -963,7 +1005,7 @@ static int snd_korg1212_WriteADCSensitivity(korg1212_t *korg1212)
// Also, if the card was in monitor mode, restore it. // Also, if the card was in monitor mode, restore it.
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
for (count = 0; count < 10; count++) for (count = 0; count < 10; count++)
TickDelay(SENSCLKPULSE_WIDTH); udelay(SENSCLKPULSE_WIDTH);
if (monModeSet) { if (monModeSet) {
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode, rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
...@@ -1011,7 +1053,7 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212) ...@@ -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]); if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: Configure Buffer Memory - RC = %d [%s]\n", rc, stateName[korg1212->cardState]);
#endif #endif
TickDelay(INTERCOMMAND_DELAY); udelay(INTERCOMMAND_DELAY);
rc = snd_korg1212_Send1212Command(korg1212, rc = snd_korg1212_Send1212Command(korg1212,
K1212_DB_ConfigureMiscMemory, K1212_DB_ConfigureMiscMemory,
...@@ -1029,7 +1071,7 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212) ...@@ -1029,7 +1071,7 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212)
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
// Initialize the routing and volume tables, then update the card's state. // Initialize the routing and volume tables, then update the card's state.
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
TickDelay(INTERCOMMAND_DELAY); udelay(INTERCOMMAND_DELAY);
for (channel = 0; channel < kAudioChannels; channel++) { for (channel = 0; channel < kAudioChannels; channel++) {
korg1212->sharedBufferPtr->volumeData[channel] = k1212MaxVolume; korg1212->sharedBufferPtr->volumeData[channel] = k1212MaxVolume;
...@@ -1039,7 +1081,7 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212) ...@@ -1039,7 +1081,7 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212)
snd_korg1212_WriteADCSensitivity(korg1212); snd_korg1212_WriteADCSensitivity(korg1212);
TickDelay(INTERCOMMAND_DELAY); udelay(INTERCOMMAND_DELAY);
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SetClockSourceRate, rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SetClockSourceRate,
ClockSourceSelector[korg1212->clkSrcRate], ClockSourceSelector[korg1212->clkSrcRate],
0, 0, 0); 0, 0, 0);
...@@ -1056,7 +1098,6 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212) ...@@ -1056,7 +1098,6 @@ static void snd_korg1212_OnDSPDownloadComplete(korg1212_t *korg1212)
wake_up_interruptible(&korg1212->wait); wake_up_interruptible(&korg1212->wait);
} }
static void snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
u32 doorbellValue; u32 doorbellValue;
...@@ -1092,10 +1133,11 @@ static void snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1092,10 +1133,11 @@ static void snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs)
// an error occurred - stop the card // an error occurred - stop the card
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
case K1212_ISRCODE_DMAERROR: 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]); K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DMAE count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]);
#endif #endif
writel(0, &korg1212->sharedBufferPtr->cardCommand); writel(0, &korg1212->sharedBufferPtr->cardCommand);
snd_korg1212_setCardState(korg1212, K1212_STATE_ERRORSTOP);
break; break;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
...@@ -1103,14 +1145,14 @@ static void snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -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. // the semaphore in case someone is waiting for this.
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
case K1212_ISRCODE_CARDSTOPPED: 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]); K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ CSTP count - %ld, %x, [%s].\n", korg1212->irqcount, doorbellValue, stateName[korg1212->cardState]);
#endif #endif
writel(0, &korg1212->sharedBufferPtr->cardCommand); writel(0, &korg1212->sharedBufferPtr->cardCommand);
break; break;
default: 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, K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DFLT count - %ld, %x, cpos=%d [%s].\n", korg1212->irqcount, doorbellValue,
korg1212->currentBuffer, stateName[korg1212->cardState]); korg1212->currentBuffer, stateName[korg1212->cardState]);
#endif #endif
...@@ -1178,11 +1220,11 @@ static snd_pcm_hardware_t snd_korg1212_playback_info = ...@@ -1178,11 +1220,11 @@ static snd_pcm_hardware_t snd_korg1212_playback_info =
SNDRV_PCM_RATE_48000), SNDRV_PCM_RATE_48000),
.rate_min = 44100, .rate_min = 44100,
.rate_max = 48000, .rate_max = 48000,
.channels_min = K1212_CHANNELS, .channels_min = K1212_MIN_CHANNELS,
.channels_max = K1212_CHANNELS, .channels_max = K1212_MAX_CHANNELS,
.buffer_bytes_max = K1212_BUF_SIZE, .buffer_bytes_max = K1212_MAX_BUF_SIZE,
.period_bytes_min = K1212_PERIOD_BYTES, .period_bytes_min = K1212_MIN_CHANNELS * 2 * kPlayBufferFrames,
.period_bytes_max = K1212_PERIOD_BYTES, .period_bytes_max = K1212_MAX_CHANNELS * 2 * kPlayBufferFrames,
.periods_min = K1212_PERIODS, .periods_min = K1212_PERIODS,
.periods_max = K1212_PERIODS, .periods_max = K1212_PERIODS,
.fifo_size = 0, .fifo_size = 0,
...@@ -1198,36 +1240,116 @@ static snd_pcm_hardware_t snd_korg1212_capture_info = ...@@ -1198,36 +1240,116 @@ static snd_pcm_hardware_t snd_korg1212_capture_info =
SNDRV_PCM_RATE_48000), SNDRV_PCM_RATE_48000),
.rate_min = 44100, .rate_min = 44100,
.rate_max = 48000, .rate_max = 48000,
.channels_min = K1212_CHANNELS, .channels_min = K1212_MIN_CHANNELS,
.channels_max = K1212_CHANNELS, .channels_max = K1212_MAX_CHANNELS,
.buffer_bytes_max = K1212_BUF_SIZE, .buffer_bytes_max = K1212_MAX_BUF_SIZE,
.period_bytes_min = K1212_PERIOD_BYTES, .period_bytes_min = K1212_MIN_CHANNELS * 2 * kPlayBufferFrames,
.period_bytes_max = K1212_PERIOD_BYTES, .period_bytes_max = K1212_MAX_CHANNELS * 2 * kPlayBufferFrames,
.periods_min = K1212_PERIODS, .periods_min = K1212_PERIODS,
.periods_max = K1212_PERIODS, .periods_max = K1212_PERIODS,
.fifo_size = 0, .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 #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 #endif
memset((void*) dst + offset, 0, size);
dst++;
}
korg1212->pcm16 = NULL; return 0;
} }
static unsigned int period_bytes[] = { K1212_PERIOD_BYTES }; 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;
#define PERIOD_BYTES sizeof(period_bytes) / sizeof(period_bytes[0]) #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);
static snd_pcm_hw_constraint_list_t hw_constraints_period_bytes = { for (i=0; i < count; i++) {
.count = PERIOD_BYTES, #if K1212_DEBUG_LEVEL > 0
.list = period_bytes, if ( (void *) src < (void *) korg1212->recordDataBufsPtr ||
.mask = 0 (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 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;
#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
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) static int snd_korg1212_playback_open(snd_pcm_substream_t *substream)
{ {
...@@ -1239,26 +1361,27 @@ static int snd_korg1212_playback_open(snd_pcm_substream_t *substream) ...@@ -1239,26 +1361,27 @@ 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]); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_open [%s]\n", stateName[korg1212->cardState]);
#endif #endif
snd_pcm_set_sync(substream); // ???
spin_lock_irqsave(&korg1212->lock, flags); spin_lock_irqsave(&korg1212->lock, flags);
snd_korg1212_OpenCard(korg1212); snd_korg1212_OpenCard(korg1212);
snd_pcm_set_sync(substream); // ???
runtime->hw = snd_korg1212_playback_info; runtime->hw = snd_korg1212_playback_info;
runtime->dma_area = (char *) korg1212->playDataBufsPtr; runtime->dma_area = (char *) korg1212->playDataBufsPtr;
runtime->dma_bytes = K1212_BUF_SIZE; runtime->dma_bytes = K1212_BUF_SIZE;
korg1212->playback_substream = substream; korg1212->playback_substream = substream;
korg1212->periodsize = K1212_PERIODS; korg1212->periodsize = K1212_PERIODS;
korg1212->channels = K1212_CHANNELS;
spin_unlock_irqrestore(&korg1212->lock, flags); 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_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, kPlayBufferFrames, kPlayBufferFrames);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
return 0; return 0;
} }
static int snd_korg1212_capture_open(snd_pcm_substream_t *substream) static int snd_korg1212_capture_open(snd_pcm_substream_t *substream)
{ {
unsigned long flags; unsigned long flags;
...@@ -1269,23 +1392,23 @@ static int snd_korg1212_capture_open(snd_pcm_substream_t *substream) ...@@ -1269,23 +1392,23 @@ 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]); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_open [%s]\n", stateName[korg1212->cardState]);
#endif #endif
snd_pcm_set_sync(substream); // ???
spin_lock_irqsave(&korg1212->lock, flags); spin_lock_irqsave(&korg1212->lock, flags);
snd_korg1212_OpenCard(korg1212); snd_korg1212_OpenCard(korg1212);
snd_pcm_set_sync(substream); // ???
runtime->hw = snd_korg1212_capture_info; runtime->hw = snd_korg1212_capture_info;
runtime->dma_area = (char *) korg1212->recordDataBufsPtr; runtime->dma_area = (char *) korg1212->recordDataBufsPtr;
runtime->dma_bytes = K1212_BUF_SIZE; runtime->dma_bytes = K1212_BUF_SIZE;
korg1212->capture_substream = substream; korg1212->capture_substream = substream;
korg1212->periodsize = K1212_PERIODS; korg1212->periodsize = K1212_PERIODS;
korg1212->channels = K1212_CHANNELS;
spin_unlock_irqrestore(&korg1212->lock, flags); 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_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, kPlayBufferFrames, kPlayBufferFrames);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes);
return 0; return 0;
} }
...@@ -1298,6 +1421,8 @@ static int snd_korg1212_playback_close(snd_pcm_substream_t *substream) ...@@ -1298,6 +1421,8 @@ 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]); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_close [%s]\n", stateName[korg1212->cardState]);
#endif #endif
snd_korg1212_silence(korg1212, 0, K1212_MAX_SAMPLES, 0, korg1212->channels * 2);
spin_lock_irqsave(&korg1212->lock, flags); spin_lock_irqsave(&korg1212->lock, flags);
korg1212->playback_substream = NULL; korg1212->playback_substream = NULL;
...@@ -1329,37 +1454,22 @@ static int snd_korg1212_capture_close(snd_pcm_substream_t *substream) ...@@ -1329,37 +1454,22 @@ static int snd_korg1212_capture_close(snd_pcm_substream_t *substream)
return 0; 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, static int snd_korg1212_ioctl(snd_pcm_substream_t *substream,
unsigned int cmd, void *arg) unsigned int cmd, void *arg)
{ {
#if K1212_DEBUG_LEVEL > 0 #if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_ioctl: cmd=%d\n", cmd); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_ioctl: cmd=%d\n", cmd);
#endif #endif
if (cmd == SNDRV_PCM_IOCTL1_CHANNEL_INFO ) { if (cmd == SNDRV_PCM_IOCTL1_CHANNEL_INFO ) {
snd_pcm_channel_info_t *info = arg; 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); return snd_pcm_lib_ioctl(substream, cmd, arg);
...@@ -1381,13 +1491,14 @@ static int snd_korg1212_hw_params(snd_pcm_substream_t *substream, ...@@ -1381,13 +1491,14 @@ static int snd_korg1212_hw_params(snd_pcm_substream_t *substream,
spin_unlock_irqrestore(&korg1212->lock, flags); spin_unlock_irqrestore(&korg1212->lock, flags);
return err; return err;
} }
/*
if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) { if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) {
spin_unlock_irqrestore(&korg1212->lock, flags); spin_unlock_irqrestore(&korg1212->lock, flags);
return -EINVAL; return -EINVAL;
} }
*/
korg1212->periodsize = K1212_BLOCK_SIZE; korg1212->channels = params_channels(params);
korg1212->periodsize = K1212_PERIOD_BYTES;
spin_unlock_irqrestore(&korg1212->lock, flags); spin_unlock_irqrestore(&korg1212->lock, flags);
...@@ -1398,6 +1509,7 @@ static int snd_korg1212_prepare(snd_pcm_substream_t *substream) ...@@ -1398,6 +1509,7 @@ static int snd_korg1212_prepare(snd_pcm_substream_t *substream)
{ {
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
unsigned long flags; unsigned long flags;
int rc;
#if K1212_DEBUG_LEVEL > 0 #if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_prepare [%s]\n", stateName[korg1212->cardState]); 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) ...@@ -1405,18 +1517,19 @@ static int snd_korg1212_prepare(snd_pcm_substream_t *substream)
spin_lock_irqsave(&korg1212->lock, flags); spin_lock_irqsave(&korg1212->lock, flags);
snd_korg1212_SetupForPlay(korg1212); rc = snd_korg1212_SetupForPlay(korg1212);
korg1212->currentBuffer = 0;
korg1212->currentBuffer = -1;
spin_unlock_irqrestore(&korg1212->lock, flags); spin_unlock_irqrestore(&korg1212->lock, flags);
return 0;
return rc ? -EINVAL : 0;
} }
static int snd_korg1212_trigger(snd_pcm_substream_t *substream, static int snd_korg1212_trigger(snd_pcm_substream_t *substream,
int cmd) int cmd)
{ {
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
int rc;
#if K1212_DEBUG_LEVEL > 0 #if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger [%s] cmd=%d\n", stateName[korg1212->cardState], cmd); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_trigger [%s] cmd=%d\n", stateName[korg1212->cardState], cmd);
...@@ -1424,33 +1537,63 @@ static int snd_korg1212_trigger(snd_pcm_substream_t *substream, ...@@ -1424,33 +1537,63 @@ static int snd_korg1212_trigger(snd_pcm_substream_t *substream,
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: 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; break;
case SNDRV_PCM_TRIGGER_STOP: 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; break;
default: 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); korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
snd_pcm_uframes_t pos; snd_pcm_uframes_t pos;
if (korg1212->currentBuffer < 0) pos = korg1212->currentBuffer * kPlayBufferFrames;
return 0;
#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 snd_pcm_uframes_t snd_korg1212_capture_pointer(snd_pcm_substream_t *substream)
{
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
snd_pcm_uframes_t pos;
pos = korg1212->currentBuffer * kPlayBufferFrames; pos = korg1212->currentBuffer * kPlayBufferFrames;
#if K1212_DEBUG_LEVEL > 1 #if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_pointer [%s] %ld\n", stateName[korg1212->cardState], pos); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_pointer [%s] %ld\n",
stateName[korg1212->cardState], pos);
#endif #endif
return pos; return pos;
...@@ -1463,52 +1606,42 @@ static int snd_korg1212_playback_copy(snd_pcm_substream_t *substream, ...@@ -1463,52 +1606,42 @@ static int snd_korg1212_playback_copy(snd_pcm_substream_t *substream,
snd_pcm_uframes_t count) snd_pcm_uframes_t count)
{ {
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos;
#if K1212_DEBUG_LEVEL > 0 #if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
#endif #endif
snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL); return snd_korg1212_copy_from(korg1212, src, pos, count, 0, korg1212->channels * 2);
return copy_from_user(dst, src, count * K1212_FRAME_SIZE) ? -EFAULT : 0;
} }
static int snd_korg1212_capture_copy(snd_pcm_substream_t *substream, static int snd_korg1212_playback_silence(snd_pcm_substream_t *substream,
int channel, /* not used (interleaved data) */ int channel, /* not used (interleaved data) */
snd_pcm_uframes_t pos, snd_pcm_uframes_t pos,
void *dst,
snd_pcm_uframes_t count) snd_pcm_uframes_t count)
{ {
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
KorgAudioFrame * src = korg1212->recordDataBufsPtr[0].bufferData + pos;
#if K1212_DEBUG_LEVEL > 0 #if K1212_DEBUG_LEVEL > 0
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_silence [%s]\n", stateName[korg1212->cardState]);
#endif #endif
snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL); return snd_korg1212_silence(korg1212, pos, count, 0, korg1212->channels * 2);
return copy_to_user(dst, src, count * K1212_FRAME_SIZE) ? -EFAULT : 0;
} }
static int snd_korg1212_playback_silence(snd_pcm_substream_t *substream, static int snd_korg1212_capture_copy(snd_pcm_substream_t *substream,
int channel, /* not used (interleaved data) */ int channel, /* not used (interleaved data) */
snd_pcm_uframes_t pos, snd_pcm_uframes_t pos,
void *dst,
snd_pcm_uframes_t count) snd_pcm_uframes_t count)
{ {
korg1212_t *korg1212 = _snd_pcm_substream_chip(substream); korg1212_t *korg1212 = _snd_pcm_substream_chip(substream);
KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos;
#if K1212_DEBUG_LEVEL > 0 #if K1212_DEBUG_LEVEL > 2
K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_silence [%s]\n", stateName[korg1212->cardState]); K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_copy [%s] %ld %ld\n", stateName[korg1212->cardState], pos, count);
#endif #endif
snd_assert(pos + count <= K1212_MAX_SAMPLES, return -EINVAL); return snd_korg1212_copy_to(korg1212, dst, pos, count, 0, korg1212->channels * 2);
memset(dst, 0, count * K1212_FRAME_SIZE);
return 0;
} }
static snd_pcm_ops_t snd_korg1212_playback_ops = { static snd_pcm_ops_t snd_korg1212_playback_ops = {
...@@ -1518,7 +1651,7 @@ 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, .hw_params = snd_korg1212_hw_params,
.prepare = snd_korg1212_prepare, .prepare = snd_korg1212_prepare,
.trigger = snd_korg1212_trigger, .trigger = snd_korg1212_trigger,
.pointer = snd_korg1212_pointer, .pointer = snd_korg1212_playback_pointer,
.copy = snd_korg1212_playback_copy, .copy = snd_korg1212_playback_copy,
.silence = snd_korg1212_playback_silence, .silence = snd_korg1212_playback_silence,
}; };
...@@ -1530,7 +1663,7 @@ static snd_pcm_ops_t snd_korg1212_capture_ops = { ...@@ -1530,7 +1663,7 @@ static snd_pcm_ops_t snd_korg1212_capture_ops = {
.hw_params = snd_korg1212_hw_params, .hw_params = snd_korg1212_hw_params,
.prepare = snd_korg1212_prepare, .prepare = snd_korg1212_prepare,
.trigger = snd_korg1212_trigger, .trigger = snd_korg1212_trigger,
.pointer = snd_korg1212_pointer, .pointer = snd_korg1212_capture_pointer,
.copy = snd_korg1212_capture_copy, .copy = snd_korg1212_capture_copy,
}; };
...@@ -1703,13 +1836,13 @@ static int snd_korg1212_control_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem ...@@ -1703,13 +1836,13 @@ static int snd_korg1212_control_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem
i = kcontrol->private_value; 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]; korg1212->sharedBufferPtr->routeData[i] = u->value.enumerated.item[0];
change = 1; change = 1;
} }
if (i >= 8) { 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]; korg1212->sharedBufferPtr->routeData[i+1] = u->value.enumerated.item[1];
change = 1; change = 1;
} }
...@@ -1720,7 +1853,7 @@ static int snd_korg1212_control_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem ...@@ -1720,7 +1853,7 @@ static int snd_korg1212_control_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem
return change; 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->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2; uinfo->count = 2;
...@@ -1729,7 +1862,7 @@ static int snd_korg1212_control_analog_info(snd_kcontrol_t *kcontrol, snd_ctl_el ...@@ -1729,7 +1862,7 @@ static int snd_korg1212_control_analog_info(snd_kcontrol_t *kcontrol, snd_ctl_el
return 0; 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); korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol);
unsigned long flags; unsigned long flags;
...@@ -1744,7 +1877,7 @@ static int snd_korg1212_control_analog_get(snd_kcontrol_t *kcontrol, snd_ctl_ele ...@@ -1744,7 +1877,7 @@ static int snd_korg1212_control_analog_get(snd_kcontrol_t *kcontrol, snd_ctl_ele
return 0; 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); korg1212_t *korg1212 = _snd_kcontrol_chip(kcontrol);
unsigned long flags; unsigned long flags;
...@@ -1855,9 +1988,9 @@ static snd_kcontrol_new_t snd_korg1212_controls[] = { ...@@ -1855,9 +1988,9 @@ static snd_kcontrol_new_t snd_korg1212_controls[] = {
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "ADC Attenuation", .name = "ADC Attenuation",
.info = snd_korg1212_control_analog_info, .info = snd_korg1212_control_info,
.get = snd_korg1212_control_analog_get, .get = snd_korg1212_control_get,
.put = snd_korg1212_control_analog_put, .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 ...@@ -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, korg1212->card->longname);
snd_iprintf(buffer, " (index #%d)\n", korg1212->card->number + 1); snd_iprintf(buffer, " (index #%d)\n", korg1212->card->number + 1);
snd_iprintf(buffer, "\nGeneral settings\n"); 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, " clock mode: %s\n", clockSourceName[korg1212->clkSrcRate] );
snd_iprintf(buffer, " left ADC Sens: %d\n", korg1212->leftADCInSens ); snd_iprintf(buffer, " left ADC Sens: %d\n", korg1212->leftADCInSens );
snd_iprintf(buffer, " right ADC Sens: %d\n", korg1212->rightADCInSens ); snd_iprintf(buffer, " right ADC Sens: %d\n", korg1212->rightADCInSens );
...@@ -1901,19 +2034,132 @@ static void __devinit snd_korg1212_proc_init(korg1212_t *korg1212) ...@@ -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); 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; int err;
unsigned int i; unsigned int i;
unsigned ioport_size, iomem_size, iomem2_size; unsigned ioport_size, iomem_size, iomem2_size;
dma_addr_t phys_addr; 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->irq = -1;
korg1212->clkSource = K1212_CLKIDX_Local; korg1212->clkSource = K1212_CLKIDX_Local;
korg1212->clkRate = 44100; korg1212->clkRate = 44100;
korg1212->inIRQ = 0; korg1212->inIRQ = 0;
korg1212->running = 0; korg1212->running = 0;
korg1212->opencnt = 0;
korg1212->playcnt = 0;
korg1212->setcnt = 0;
snd_korg1212_setCardState(korg1212, K1212_STATE_UNINITIALIZED); snd_korg1212_setCardState(korg1212, K1212_STATE_UNINITIALIZED);
korg1212->idleMonitorOn = 0; korg1212->idleMonitorOn = 0;
korg1212->clkSrcRate = K1212_CLKIDX_LocalAt44_1K; korg1212->clkSrcRate = K1212_CLKIDX_LocalAt44_1K;
...@@ -1923,9 +2169,6 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212) ...@@ -1923,9 +2169,6 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
for (i=0; i<kAudioChannels; i++) for (i=0; i<kAudioChannels; i++)
korg1212->volumePhase[i] = 0; korg1212->volumePhase[i] = 0;
if ((err = pci_enable_device(pci)) < 0)
return err;
korg1212->iomem = pci_resource_start(korg1212->pci, 0); korg1212->iomem = pci_resource_start(korg1212->pci, 0);
korg1212->ioport = pci_resource_start(korg1212->pci, 1); korg1212->ioport = pci_resource_start(korg1212->pci, 1);
korg1212->iomem2 = pci_resource_start(korg1212->pci, 2); korg1212->iomem2 = pci_resource_start(korg1212->pci, 2);
...@@ -1948,27 +2191,27 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212) ...@@ -1948,27 +2191,27 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->res_iomem = request_mem_region(korg1212->iomem, iomem_size, "korg1212"); korg1212->res_iomem = request_mem_region(korg1212->iomem, iomem_size, "korg1212");
if (korg1212->res_iomem == NULL) { 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); korg1212->iomem, korg1212->iomem + iomem_size - 1);
return -EBUSY; return -EBUSY;
} }
korg1212->res_ioport = request_region(korg1212->ioport, ioport_size, "korg1212"); korg1212->res_ioport = request_region(korg1212->ioport, ioport_size, "korg1212");
if (korg1212->res_ioport == NULL) { 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); korg1212->ioport, korg1212->ioport + ioport_size - 1);
return -EBUSY; return -EBUSY;
} }
korg1212->res_iomem2 = request_mem_region(korg1212->iomem2, iomem2_size, "korg1212"); korg1212->res_iomem2 = request_mem_region(korg1212->iomem2, iomem2_size, "korg1212");
if (korg1212->res_iomem2 == NULL) { 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); korg1212->iomem2, korg1212->iomem2 + iomem2_size - 1);
return -EBUSY; return -EBUSY;
} }
if ((korg1212->iobase = (unsigned long) ioremap(korg1212->iomem, iomem_size)) == 0) { 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); korg1212->iobase + iomem_size - 1);
return -EBUSY; return -EBUSY;
} }
...@@ -1978,14 +2221,12 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212) ...@@ -1978,14 +2221,12 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
"korg1212", (void *) korg1212); "korg1212", (void *) korg1212);
if (err) { 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; return -EBUSY;
} }
korg1212->irq = pci->irq; korg1212->irq = pci->irq;
init_waitqueue_head(&korg1212->wait);
spin_lock_init(&korg1212->lock);
pci_set_master(korg1212->pci); pci_set_master(korg1212->pci);
korg1212->statusRegPtr = (u32 *) (korg1212->iobase + STATUS_REG_OFFSET); korg1212->statusRegPtr = (u32 *) (korg1212->iobase + STATUS_REG_OFFSET);
...@@ -2029,7 +2270,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212) ...@@ -2029,7 +2270,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->sharedBufferPhy = (unsigned long)phys_addr; korg1212->sharedBufferPhy = (unsigned long)phys_addr;
if (korg1212->sharedBufferPtr == NULL) { 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; return -ENOMEM;
} }
...@@ -2045,7 +2286,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212) ...@@ -2045,7 +2286,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->PlayDataPhy = (u32)phys_addr; korg1212->PlayDataPhy = (u32)phys_addr;
if (korg1212->playDataBufsPtr == NULL) { 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; return -ENOMEM;
} }
...@@ -2058,7 +2299,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212) ...@@ -2058,7 +2299,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->RecDataPhy = (u32)phys_addr; korg1212->RecDataPhy = (u32)phys_addr;
if (korg1212->recordDataBufsPtr == NULL) { 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; return -ENOMEM;
} }
...@@ -2086,7 +2327,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212) ...@@ -2086,7 +2327,7 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->dspMemPhy = (u32)phys_addr; korg1212->dspMemPhy = (u32)phys_addr;
if (korg1212->dspMemPtr == NULL) { 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; return -ENOMEM;
} }
...@@ -2122,17 +2363,21 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212) ...@@ -2122,17 +2363,21 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
korg1212->RoutingTablePhy, LowerWordSwap(korg1212->RoutingTablePhy), korg1212->RoutingTablePhy, LowerWordSwap(korg1212->RoutingTablePhy),
korg1212->AdatTimeCodePhy, LowerWordSwap(korg1212->AdatTimeCodePhy)); 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; return err;
korg1212->pcm16->private_data = korg1212; korg1212->pcm->private_data = korg1212;
korg1212->pcm16->private_free = snd_korg1212_free_pcm; korg1212->pcm->private_free = snd_korg1212_free_pcm;
strcpy(korg1212->pcm16->name, "korg1212"); 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); korg1212->pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
snd_pcm_set_ops(korg1212->pcm16, SNDRV_PCM_STREAM_CAPTURE, &snd_korg1212_capture_ops);
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++) { for (i = 0; i < K1212_CONTROL_ELEMENTS; i++) {
err = snd_ctl_add(korg1212->card, snd_ctl_new1(&snd_korg1212_controls[i], korg1212)); err = snd_ctl_add(korg1212->card, snd_ctl_new1(&snd_korg1212_controls[i], korg1212));
...@@ -2142,102 +2387,20 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212) ...@@ -2142,102 +2387,20 @@ static int __devinit snd_korg1212_create(korg1212_t *korg1212)
snd_korg1212_proc_init(korg1212); snd_korg1212_proc_init(korg1212);
return 0; if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, korg1212, &ops)) < 0) {
snd_korg1212_free(korg1212);
} return err;
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;
} }
#endif * rchip = korg1212;
return 0;
// ----------------------------------------------------
// 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 * 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 static int __devinit
snd_korg1212_probe(struct pci_dev *pci, snd_korg1212_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id) const struct pci_device_id *pci_id)
...@@ -2254,16 +2417,11 @@ snd_korg1212_probe(struct pci_dev *pci, ...@@ -2254,16 +2417,11 @@ snd_korg1212_probe(struct pci_dev *pci,
dev++; dev++;
return -ENOENT; return -ENOENT;
} }
if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE, card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
sizeof(korg1212_t))) == NULL) if (card == NULL)
return -ENOMEM; return -ENOMEM;
card->private_free = snd_korg1212_card_free; if ((err = snd_korg1212_create(card, pci, &korg1212)) < 0) {
korg1212 = (korg1212_t *)card->private_data;
korg1212->card = card;
korg1212->pci = pci;
if ((err = snd_korg1212_create(korg1212)) < 0) {
snd_card_free(card); snd_card_free(card);
return err; return err;
} }
...@@ -2281,14 +2439,15 @@ snd_korg1212_probe(struct pci_dev *pci, ...@@ -2281,14 +2439,15 @@ snd_korg1212_probe(struct pci_dev *pci,
snd_card_free(card); snd_card_free(card);
return err; return err;
} }
pci_set_drvdata(pci, card); pci_set_drvdata(pci, korg1212);
dev++; dev++;
return 0; return 0;
} }
static void __devexit snd_korg1212_remove(struct pci_dev *pci) 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); pci_set_drvdata(pci, NULL);
} }
......
...@@ -820,6 +820,7 @@ static int snd_via686_playback_prepare(snd_pcm_substream_t *substream) ...@@ -820,6 +820,7 @@ static int snd_via686_playback_prepare(snd_pcm_substream_t *substream)
snd_pcm_runtime_t *runtime = substream->runtime; 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_PCM_FRONT_DAC_RATE, runtime->rate);
snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
via686_setup_format(chip, viadev, runtime); via686_setup_format(chip, viadev, runtime);
return 0; return 0;
} }
...@@ -909,18 +910,37 @@ static int snd_via8233_multi_prepare(snd_pcm_substream_t *substream) ...@@ -909,18 +910,37 @@ static int snd_via8233_multi_prepare(snd_pcm_substream_t *substream)
snd_via82xx_channel_reset(chip, viadev); snd_via82xx_channel_reset(chip, viadev);
snd_via82xx_set_table_ptr(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->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
fmt |= runtime->channels << 4; fmt |= runtime->channels << 4;
outb(fmt, VIADEV_REG(viadev, OFS_MULTPLAY_FORMAT)); 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 ?? */ /* corresponding to FL, FR, RL, RR, C, LFE ?? */
switch (runtime->channels) { switch (runtime->channels) {
case 1: slots = (1<<0) | (1<<4); break; case 1: slots = (1<<0) | (1<<4); break;
case 2: slots = (1<<0) | (2<<4); break; case 2: slots = (1<<0) | (2<<4); break;
case 3: slots = (1<<0) | (2<<4) | (5<<8); break; case 3: slots = (1<<0) | (2<<4) | (5<<8); break;
case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); 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 5: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12) | (5<<16); break;
case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break; case 6: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12) | (5<<16) | (6<<20); break;
default: slots = 0; break; default: slots = 0; break;
} }
/* STOP index is never reached */ /* STOP index is never reached */
...@@ -1438,7 +1458,7 @@ static void snd_via82xx_mixer_free_ac97(ac97_t *ac97) ...@@ -1438,7 +1458,7 @@ static void snd_via82xx_mixer_free_ac97(ac97_t *ac97)
} }
static struct ac97_quirk ac97_quirks[] = { static struct ac97_quirk ac97_quirks[] = {
{ 0x1106, 0x4161, AC97_TUNE_HP_ONLY }, /* ASRock K7VT2 */ { 0x1106, 0x4161, "ASRock K7VT2", AC97_TUNE_HP_ONLY },
{ } /* terminator */ { } /* terminator */
}; };
...@@ -1457,7 +1477,7 @@ static int __devinit snd_via82xx_mixer_new(via82xx_t *chip) ...@@ -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) if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
return err; 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) { if (chip->chip_type != TYPE_VIA686) {
/* use slot 10/11 */ /* use slot 10/11 */
......
...@@ -1051,7 +1051,7 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) ...@@ -1051,7 +1051,7 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
} }
/* create a data pipe */ /* create a data pipe */
ep = get_endpoint(alts, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK;
if (is_playback) if (is_playback)
subs->datapipe = usb_sndisocpipe(dev, ep); subs->datapipe = usb_sndisocpipe(dev, ep);
else else
...@@ -1062,9 +1062,16 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) ...@@ -1062,9 +1062,16 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
subs->fill_max = 0; subs->fill_max = 0;
/* we need a sync pipe in async OUT or adaptive IN mode */ /* 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) || if ((is_playback && attr == EP_ATTR_ASYNC) ||
(! is_playback && attr == EP_ATTR_ADAPTIVE)) { (! 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 */ /* check endpoint */
if (altsd->bNumEndpoints < 2 || if (altsd->bNumEndpoints < 2 ||
get_endpoint(alts, 1)->bmAttributes != 0x01 || get_endpoint(alts, 1)->bmAttributes != 0x01 ||
...@@ -1088,6 +1095,7 @@ static int set_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) ...@@ -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; subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
} }
_ok:
if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0 || if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0 ||
(err = init_usb_sample_rate(dev, subs->interface, alts, fmt, (err = init_usb_sample_rate(dev, subs->interface, alts, fmt,
runtime->rate)) < 0) runtime->rate)) < 0)
...@@ -1651,7 +1659,7 @@ static void proc_dump_substream_formats(snd_usb_substream_t *subs, snd_info_buff ...@@ -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", fp->endpoint & USB_DIR_IN ? "IN" : "OUT",
sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]); sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]);
if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { 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); fp->rate_min, fp->rate_max);
} else { } else {
unsigned int i; 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