diff options
Diffstat (limited to 'sound/pci')
34 files changed, 6870 insertions, 6241 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 9823d59d7ad..389cd793166 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -152,10 +152,16 @@ config SND_AZT3328 select SND_MPU401_UART select SND_PCM select SND_RAWMIDI + select SND_AC97_CODEC help Say Y here to include support for Aztech AZF3328 (PCI168) soundcards. + Supported features: AC97-"conformant" mixer, MPU401/OPL3, analog I/O + (16bit/8bit, many sample rates [<= 66.2kHz], NO hardware mixing), + Digital Enhanced Game Port, 1.024MHz multimedia sequencer timer, + ext. codec (I2S port), onboard amp (4W/4Ohms/ch), suspend/resume. + To compile this driver as a module, choose M here: the module will be called snd-azt3328. @@ -572,13 +578,13 @@ comment "Don't forget to add built-in firmwares for HDSP driver" depends on SND_HDSP=y config SND_HDSPM - tristate "RME Hammerfall DSP MADI" + tristate "RME Hammerfall DSP MADI/RayDAT/AIO" select SND_HWDEP select SND_RAWMIDI select SND_PCM help - Say Y here to include support for RME Hammerfall DSP MADI - soundcards. + Say Y here to include support for RME Hammerfall DSP MADI, + RayDAT and AIO soundcards. To compile this driver as a module, choose M here: the module will be called snd-hdspm. diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index cb62d178b3e..7f4d619f4dd 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -71,6 +71,12 @@ static const struct ac97_codec_id snd_ac97_codec_id_vendors[] = { { 0x414b4d00, 0xffffff00, "Asahi Kasei", NULL, NULL }, { 0x414c4300, 0xffffff00, "Realtek", NULL, NULL }, { 0x414c4700, 0xffffff00, "Realtek", NULL, NULL }, +/* + * This is an _inofficial_ Aztech Labs entry + * (value might differ from unknown official Aztech ID), + * currently used by the AC97 emulation of the almost-AC97 PCI168 card. + */ +{ 0x415a5400, 0xffffff00, "Aztech Labs (emulated)", NULL, NULL }, { 0x434d4900, 0xffffff00, "C-Media Electronics", NULL, NULL }, { 0x43525900, 0xffffff00, "Cirrus Logic", NULL, NULL }, { 0x43585400, 0xffffff00, "Conexant", NULL, NULL }, @@ -127,6 +133,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x414c4781, 0xffffffff, "ALC658D", NULL, NULL }, /* already patched */ { 0x414c4780, 0xfffffff0, "ALC658", patch_alc655, NULL }, { 0x414c4790, 0xfffffff0, "ALC850", patch_alc850, NULL }, +{ 0x415a5401, 0xffffffff, "AZF3328", patch_aztech_azf3328, NULL }, { 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL }, { 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, { 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL }, @@ -590,9 +597,9 @@ static int snd_ac97_put_volsw(struct snd_kcontrol *kcontrol, snd_ac97_page_restore(ac97, page_save); #ifdef CONFIG_SND_AC97_POWER_SAVE /* check analog mixer power-down */ - if ((val_mask & 0x8000) && + if ((val_mask & AC97_PD_EAPD) && (kcontrol->private_value & (1<<30))) { - if (val & 0x8000) + if (val & AC97_PD_EAPD) ac97->power_up &= ~(1 << (reg>>1)); else ac97->power_up |= 1 << (reg>>1); @@ -1035,20 +1042,20 @@ static int snd_ac97_dev_free(struct snd_device *device) static int snd_ac97_try_volume_mix(struct snd_ac97 * ac97, int reg) { - unsigned short val, mask = 0x8000; + unsigned short val, mask = AC97_MUTE_MASK_MONO; if (! snd_ac97_valid_reg(ac97, reg)) return 0; switch (reg) { case AC97_MASTER_TONE: - return ac97->caps & 0x04 ? 1 : 0; + return ac97->caps & AC97_BC_BASS_TREBLE ? 1 : 0; case AC97_HEADPHONE: - return ac97->caps & 0x10 ? 1 : 0; + return ac97->caps & AC97_BC_HEADPHONE ? 1 : 0; case AC97_REC_GAIN_MIC: - return ac97->caps & 0x01 ? 1 : 0; + return ac97->caps & AC97_BC_DEDICATED_MIC ? 1 : 0; case AC97_3D_CONTROL: - if (ac97->caps & 0x7c00) { + if (ac97->caps & AC97_BC_3D_TECH_ID_MASK) { val = snd_ac97_read(ac97, reg); /* if nonzero - fixed and we can't set it */ return val == 0; @@ -1104,7 +1111,10 @@ static void check_volume_resolution(struct snd_ac97 *ac97, int reg, unsigned cha *lo_max = *hi_max = 0; for (i = 0 ; i < ARRAY_SIZE(cbit); i++) { unsigned short val; - snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8)); + snd_ac97_write( + ac97, reg, + AC97_MUTE_MASK_STEREO | cbit[i] | (cbit[i] << 8) + ); /* Do the read twice due to buffers on some ac97 codecs. * e.g. The STAC9704 returns exactly what you wrote to the register * if you read it immediately. This causes the detect routine to fail. @@ -1139,14 +1149,14 @@ static void snd_ac97_change_volume_params2(struct snd_ac97 * ac97, int reg, int unsigned short val, val1; *max = 63; - val = 0x8080 | (0x20 << shift); + val = AC97_MUTE_MASK_STEREO | (0x20 << shift); snd_ac97_write(ac97, reg, val); val1 = snd_ac97_read(ac97, reg); if (val != val1) { *max = 31; } /* reset volume to zero */ - snd_ac97_write_cache(ac97, reg, 0x8080); + snd_ac97_write_cache(ac97, reg, AC97_MUTE_MASK_STEREO); } static inline int printable(unsigned int x) @@ -1183,16 +1193,16 @@ static int snd_ac97_cmute_new_stereo(struct snd_card *card, char *name, int reg, if (! snd_ac97_valid_reg(ac97, reg)) return 0; - mute_mask = 0x8000; + mute_mask = AC97_MUTE_MASK_MONO; val = snd_ac97_read(ac97, reg); if (check_stereo || (ac97->flags & AC97_STEREO_MUTES)) { /* check whether both mute bits work */ - val1 = val | 0x8080; + val1 = val | AC97_MUTE_MASK_STEREO; snd_ac97_write(ac97, reg, val1); if (val1 == snd_ac97_read(ac97, reg)) - mute_mask = 0x8080; + mute_mask = AC97_MUTE_MASK_STEREO; } - if (mute_mask == 0x8080) { + if (mute_mask == AC97_MUTE_MASK_STEREO) { struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); if (check_amix) tmp.private_value |= (1 << 30); @@ -1268,9 +1278,11 @@ static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigne err = snd_ctl_add(card, kctl); if (err < 0) return err; - snd_ac97_write_cache(ac97, reg, - (snd_ac97_read(ac97, reg) & 0x8080) | - lo_max | (hi_max << 8)); + snd_ac97_write_cache( + ac97, reg, + (snd_ac97_read(ac97, reg) & AC97_MUTE_MASK_STEREO) + | lo_max | (hi_max << 8) + ); return 0; } @@ -1332,7 +1344,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) return err; } - ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080; + ac97->regs[AC97_CENTER_LFE_MASTER] = AC97_MUTE_MASK_STEREO; /* build center controls */ if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) @@ -1410,8 +1422,12 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) return err; set_tlv_db_scale(kctl, db_scale_4bit); - snd_ac97_write_cache(ac97, AC97_PC_BEEP, - snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e); + snd_ac97_write_cache( + ac97, + AC97_PC_BEEP, + (snd_ac97_read(ac97, AC97_PC_BEEP) + | AC97_MUTE_MASK_MONO | 0x001e) + ); } /* build Phone controls */ @@ -1545,7 +1561,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) } /* build Simulated Stereo Enhancement control */ - if (ac97->caps & 0x0008) { + if (ac97->caps & AC97_BC_SIM_STEREO) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_STEREO_ENHANCEMENT], ac97))) < 0) return err; } @@ -1557,7 +1573,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) } /* build Loudness control */ - if (ac97->caps & 0x0020) { + if (ac97->caps & AC97_BC_LOUDNESS) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOUDNESS], ac97))) < 0) return err; } @@ -2542,8 +2558,8 @@ void snd_ac97_resume(struct snd_ac97 *ac97) schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); /* FIXME: extra delay */ - ac97->bus->ops->write(ac97, AC97_MASTER, 0x8000); - if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) + ac97->bus->ops->write(ac97, AC97_MASTER, AC97_MUTE_MASK_MONO); + if (snd_ac97_read(ac97, AC97_MASTER) != AC97_MUTE_MASK_MONO) msleep(250); } else { end_time = jiffies + msecs_to_jiffies(100); @@ -2747,12 +2763,12 @@ static int master_mute_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem int rshift = (kcontrol->private_value >> 12) & 0x0f; unsigned short mask; if (shift != rshift) - mask = 0x8080; + mask = AC97_MUTE_MASK_STEREO; else - mask = 0x8000; - snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, + mask = AC97_MUTE_MASK_MONO; + snd_ac97_update_bits(ac97, AC97_POWERDOWN, AC97_PD_EAPD, (ac97->regs[AC97_MASTER] & mask) == mask ? - 0x8000 : 0); + AC97_PD_EAPD : 0); } return err; } @@ -2765,7 +2781,10 @@ static int tune_mute_led(struct snd_ac97 *ac97) return -ENOENT; msw->put = master_mute_sw_put; snd_ac97_remove_ctl(ac97, "External Amplifier", NULL); - snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */ + snd_ac97_update_bits( + ac97, AC97_POWERDOWN, + AC97_PD_EAPD, AC97_PD_EAPD /* mute LED on */ + ); ac97->scaps |= AC97_SCAP_EAPD_LED; return 0; } @@ -2780,12 +2799,12 @@ static int hp_master_mute_sw_put(struct snd_kcontrol *kcontrol, int rshift = (kcontrol->private_value >> 12) & 0x0f; unsigned short mask; if (shift != rshift) - mask = 0x8080; + mask = AC97_MUTE_MASK_STEREO; else - mask = 0x8000; - snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, + mask = AC97_MUTE_MASK_MONO; + snd_ac97_update_bits(ac97, AC97_POWERDOWN, AC97_PD_EAPD, (ac97->regs[AC97_MASTER] & mask) == mask ? - 0x8000 : 0); + AC97_PD_EAPD : 0); } return err; } @@ -2801,7 +2820,10 @@ static int tune_hp_mute_led(struct snd_ac97 *ac97) snd_ac97_remove_ctl(ac97, "External Amplifier", NULL); snd_ac97_remove_ctl(ac97, "Headphone Playback", "Switch"); snd_ac97_remove_ctl(ac97, "Headphone Playback", "Volume"); - snd_ac97_update_bits(ac97, AC97_POWERDOWN, 0x8000, 0x8000); /* mute LED on */ + snd_ac97_update_bits( + ac97, AC97_POWERDOWN, + AC97_PD_EAPD, AC97_PD_EAPD /* mute LED on */ + ); return 0; } diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index bf47574ca1f..200c9a1d48b 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -27,6 +27,15 @@ #include "ac97_patch.h" /* + * Forward declarations + */ + +static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97, + const char *name); +static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, + const unsigned int *tlv, const char **slaves); + +/* * Chip specific initialization */ @@ -2940,6 +2949,49 @@ static int patch_alc850(struct snd_ac97 *ac97) return 0; } +static int patch_aztech_azf3328_specific(struct snd_ac97 *ac97) +{ + struct snd_kcontrol *kctl_3d_center = + snd_ac97_find_mixer_ctl(ac97, "3D Control - Center"); + struct snd_kcontrol *kctl_3d_depth = + snd_ac97_find_mixer_ctl(ac97, "3D Control - Depth"); + + /* + * 3D register is different from AC97 standard layout + * (also do some renaming, to resemble Windows driver naming) + */ + if (kctl_3d_center) { + kctl_3d_center->private_value = + AC97_SINGLE_VALUE(AC97_3D_CONTROL, 1, 0x07, 0); + snd_ac97_rename_vol_ctl(ac97, + "3D Control - Center", "3D Control - Width" + ); + } + if (kctl_3d_depth) + kctl_3d_depth->private_value = + AC97_SINGLE_VALUE(AC97_3D_CONTROL, 8, 0x03, 0); + + /* Aztech Windows driver calls the + equivalent control "Modem Playback", thus rename it: */ + snd_ac97_rename_vol_ctl(ac97, + "Master Mono Playback", "Modem Playback" + ); + snd_ac97_rename_vol_ctl(ac97, + "Headphone Playback", "FM Synth Playback" + ); + + return 0; +} + +static const struct snd_ac97_build_ops patch_aztech_azf3328_ops = { + .build_specific = patch_aztech_azf3328_specific +}; + +static int patch_aztech_azf3328(struct snd_ac97 *ac97) +{ + ac97->build_ops = &patch_aztech_azf3328_ops; + return 0; +} /* * C-Media CM97xx codecs diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index c80b0b863c5..0ac1f98d91a 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -21,6 +21,7 @@ * would appreciate it if you grant us the right to use those modifications * for any purpose including commercial applications. */ + /* >0: print Hw params, timer vars. >1: print stream write/copy sizes */ #define REALLY_VERBOSE_LOGGING 0 @@ -36,16 +37,12 @@ #define VPRINTK2(...) #endif -#ifndef ASI_STYLE_NAMES -/* not sure how ALSA style name should look */ -#define ASI_STYLE_NAMES 1 -#endif - #include "hpi_internal.h" #include "hpimsginit.h" #include "hpioctl.h" #include <linux/pci.h> +#include <linux/version.h> #include <linux/init.h> #include <linux/jiffies.h> #include <linux/slab.h> @@ -85,11 +82,11 @@ MODULE_PARM_DESC(enable_hpi_hwdep, /* identify driver */ #ifdef KERNEL_ALSA_BUILD -static char *build_info = "built using headers from kernel source"; +static char *build_info = "Built using headers from kernel source"; module_param(build_info, charp, S_IRUGO); MODULE_PARM_DESC(build_info, "built using headers from kernel source"); #else -static char *build_info = "built within ALSA source"; +static char *build_info = "Built within ALSA source"; module_param(build_info, charp, S_IRUGO); MODULE_PARM_DESC(build_info, "built within ALSA source"); #endif @@ -100,13 +97,14 @@ static const int mixer_dump; #define DEFAULT_SAMPLERATE 44100 static int adapter_fs = DEFAULT_SAMPLERATE; -static struct hpi_hsubsys *ss; /* handle to HPI audio subsystem */ - /* defaults */ #define PERIODS_MIN 2 -#define PERIOD_BYTES_MIN 2304 +#define PERIOD_BYTES_MIN 2048 #define BUFFER_BYTES_MAX (512 * 1024) +/* convert stream to character */ +#define SCHR(s) ((s == SNDRV_PCM_STREAM_PLAYBACK) ? 'P' : 'C') + /*#define TIMER_MILLISECONDS 20 #define FORCE_TIMER_JIFFIES ((TIMER_MILLISECONDS * HZ + 999)/1000) */ @@ -152,11 +150,12 @@ struct snd_card_asihpi_pcm { struct timer_list timer; unsigned int respawn_timer; unsigned int hpi_buffer_attached; - unsigned int pcm_size; - unsigned int pcm_count; + unsigned int buffer_bytes; + unsigned int period_bytes; unsigned int bytes_per_sec; - unsigned int pcm_irq_pos; /* IRQ position */ - unsigned int pcm_buf_pos; /* position in buffer */ + unsigned int pcm_buf_host_rw_ofs; /* Host R/W pos */ + unsigned int pcm_buf_dma_ofs; /* DMA R/W offset in buffer */ + unsigned int pcm_buf_elapsed_dma_ofs; /* DMA R/W offset in buffer */ struct snd_pcm_substream *substream; u32 h_stream; struct hpi_format format; @@ -167,7 +166,6 @@ struct snd_card_asihpi_pcm { /* Functions to allow driver to give a buffer to HPI for busmastering */ static u16 hpi_stream_host_buffer_attach( - struct hpi_hsubsys *hS, u32 h_stream, /* handle to outstream. */ u32 size_in_bytes, /* size in bytes of bus mastering buffer */ u32 pci_address @@ -194,10 +192,7 @@ static u16 hpi_stream_host_buffer_attach( return hr.error; } -static u16 hpi_stream_host_buffer_detach( - struct hpi_hsubsys *hS, - u32 h_stream -) +static u16 hpi_stream_host_buffer_detach(u32 h_stream) { struct hpi_message hm; struct hpi_response hr; @@ -218,24 +213,23 @@ static u16 hpi_stream_host_buffer_detach( return hr.error; } -static inline u16 hpi_stream_start(struct hpi_hsubsys *hS, u32 h_stream) +static inline u16 hpi_stream_start(u32 h_stream) { if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) - return hpi_outstream_start(hS, h_stream); + return hpi_outstream_start(h_stream); else - return hpi_instream_start(hS, h_stream); + return hpi_instream_start(h_stream); } -static inline u16 hpi_stream_stop(struct hpi_hsubsys *hS, u32 h_stream) +static inline u16 hpi_stream_stop(u32 h_stream) { if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) - return hpi_outstream_stop(hS, h_stream); + return hpi_outstream_stop(h_stream); else - return hpi_instream_stop(hS, h_stream); + return hpi_instream_stop(h_stream); } static inline u16 hpi_stream_get_info_ex( - struct hpi_hsubsys *hS, u32 h_stream, u16 *pw_state, u32 *pbuffer_size, @@ -244,42 +238,43 @@ static inline u16 hpi_stream_get_info_ex( u32 *pauxiliary_data ) { + u16 e; if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) - return hpi_outstream_get_info_ex(hS, h_stream, pw_state, + e = hpi_outstream_get_info_ex(h_stream, pw_state, pbuffer_size, pdata_in_buffer, psample_count, pauxiliary_data); else - return hpi_instream_get_info_ex(hS, h_stream, pw_state, + e = hpi_instream_get_info_ex(h_stream, pw_state, pbuffer_size, pdata_in_buffer, psample_count, pauxiliary_data); + return e; } -static inline u16 hpi_stream_group_add(struct hpi_hsubsys *hS, +static inline u16 hpi_stream_group_add( u32 h_master, u32 h_stream) { if (hpi_handle_object(h_master) == HPI_OBJ_OSTREAM) - return hpi_outstream_group_add(hS, h_master, h_stream); + return hpi_outstream_group_add(h_master, h_stream); else - return hpi_instream_group_add(hS, h_master, h_stream); + return hpi_instream_group_add(h_master, h_stream); } -static inline u16 hpi_stream_group_reset(struct hpi_hsubsys *hS, - u32 h_stream) +static inline u16 hpi_stream_group_reset(u32 h_stream) { if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) - return hpi_outstream_group_reset(hS, h_stream); + return hpi_outstream_group_reset(h_stream); else - return hpi_instream_group_reset(hS, h_stream); + return hpi_instream_group_reset(h_stream); } -static inline u16 hpi_stream_group_get_map(struct hpi_hsubsys *hS, +static inline u16 hpi_stream_group_get_map( u32 h_stream, u32 *mo, u32 *mi) { if (hpi_handle_object(h_stream) == HPI_OBJ_OSTREAM) - return hpi_outstream_group_get_map(hS, h_stream, mo, mi); + return hpi_outstream_group_get_map(h_stream, mo, mi); else - return hpi_instream_group_get_map(hS, h_stream, mo, mi); + return hpi_instream_group_get_map(h_stream, mo, mi); } static u16 handle_error(u16 err, int line, char *filename) @@ -299,11 +294,11 @@ static void print_hwparams(struct snd_pcm_hw_params *p) { snd_printd("HWPARAMS \n"); snd_printd("samplerate %d \n", params_rate(p)); - snd_printd("channels %d \n", params_channels(p)); - snd_printd("format %d \n", params_format(p)); + snd_printd("Channels %d \n", params_channels(p)); + snd_printd("Format %d \n", params_format(p)); snd_printd("subformat %d \n", params_subformat(p)); - snd_printd("buffer bytes %d \n", params_buffer_bytes(p)); - snd_printd("period bytes %d \n", params_period_bytes(p)); + snd_printd("Buffer bytes %d \n", params_buffer_bytes(p)); + snd_printd("Period bytes %d \n", params_period_bytes(p)); snd_printd("access %d \n", params_access(p)); snd_printd("period_size %d \n", params_period_size(p)); snd_printd("periods %d \n", params_periods(p)); @@ -335,7 +330,7 @@ static snd_pcm_format_t hpi_to_alsa_formats[] = { */ -1 #else - /* SNDRV_PCM_FORMAT_S24_3LE */ /* { HPI_FORMAT_PCM24_SIGNED 15 */ + /* SNDRV_PCM_FORMAT_S24_3LE */ /* HPI_FORMAT_PCM24_SIGNED 15 */ #endif }; @@ -378,20 +373,20 @@ static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi, } else { /* on cards without SRC, valid rates are determined by sampleclock */ - err = hpi_mixer_get_control(ss, asihpi->h_mixer, + err = hpi_mixer_get_control(asihpi->h_mixer, HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0, HPI_CONTROL_SAMPLECLOCK, &h_control); if (err) { snd_printk(KERN_ERR - "no local sampleclock, err %d\n", err); + "No local sampleclock, err %d\n", err); } for (idx = 0; idx < 100; idx++) { - if (hpi_sample_clock_query_local_rate(ss, + if (hpi_sample_clock_query_local_rate( h_control, idx, &sample_rate)) { if (!idx) snd_printk(KERN_ERR - "local rate query failed\n"); + "Local rate query failed\n"); break; } @@ -480,10 +475,10 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, format, params_rate(params), 0, 0)); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - if (hpi_instream_reset(ss, dpcm->h_stream) != 0) + if (hpi_instream_reset(dpcm->h_stream) != 0) return -EINVAL; - if (hpi_instream_set_format(ss, + if (hpi_instream_set_format( dpcm->h_stream, &dpcm->format) != 0) return -EINVAL; } @@ -491,10 +486,10 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, dpcm->hpi_buffer_attached = 0; if (card->support_mmap) { - err = hpi_stream_host_buffer_attach(ss, dpcm->h_stream, + err = hpi_stream_host_buffer_attach(dpcm->h_stream, params_buffer_bytes(params), runtime->dma_addr); if (err == 0) { - snd_printd(KERN_INFO + VPRINTK1(KERN_INFO "stream_host_buffer_attach succeeded %u %lu\n", params_buffer_bytes(params), (unsigned long)runtime->dma_addr); @@ -505,11 +500,11 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, return -ENOMEM; } - err = hpi_stream_get_info_ex(ss, dpcm->h_stream, NULL, + err = hpi_stream_get_info_ex(dpcm->h_stream, NULL, &dpcm->hpi_buffer_attached, NULL, NULL, NULL); - snd_printd(KERN_INFO "stream_host_buffer_attach status 0x%x\n", + VPRINTK1(KERN_INFO "stream_host_buffer_attach status 0x%x\n", dpcm->hpi_buffer_attached); } bytes_per_sec = params_rate(params) * params_channels(params); @@ -520,16 +515,32 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; dpcm->bytes_per_sec = bytes_per_sec; - dpcm->pcm_size = params_buffer_bytes(params); - dpcm->pcm_count = params_period_bytes(params); - snd_printd(KERN_INFO "pcm_size=%d, pcm_count=%d, bps=%d\n", - dpcm->pcm_size, dpcm->pcm_count, bytes_per_sec); + dpcm->buffer_bytes = params_buffer_bytes(params); + dpcm->period_bytes = params_period_bytes(params); + VPRINTK1(KERN_INFO "buffer_bytes=%d, period_bytes=%d, bps=%d\n", + dpcm->buffer_bytes, dpcm->period_bytes, bytes_per_sec); - dpcm->pcm_irq_pos = 0; - dpcm->pcm_buf_pos = 0; return 0; } +static int +snd_card_asihpi_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_card_asihpi_pcm *dpcm = runtime->private_data; + if (dpcm->hpi_buffer_attached) + hpi_stream_host_buffer_detach(dpcm->h_stream); + + snd_pcm_lib_free_pages(substream); + return 0; +} + +static void snd_card_asihpi_runtime_free(struct snd_pcm_runtime *runtime) +{ + struct snd_card_asihpi_pcm *dpcm = runtime->private_data; + kfree(dpcm); +} + static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream * substream) { @@ -537,9 +548,9 @@ static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream * struct snd_card_asihpi_pcm *dpcm = runtime->private_data; int expiry; - expiry = (dpcm->pcm_count * HZ / dpcm->bytes_per_sec); - /* wait longer the first time, for samples to propagate */ - expiry = max(expiry, 20); + expiry = HZ / 200; + /*? (dpcm->period_bytes * HZ / dpcm->bytes_per_sec); */ + expiry = max(expiry, 1); /* don't let it be zero! */ dpcm->timer.expires = jiffies + expiry; dpcm->respawn_timer = 1; add_timer(&dpcm->timer); @@ -562,37 +573,44 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, struct snd_pcm_substream *s; u16 e; - snd_printd("trigger %dstream %d\n", - substream->stream, substream->number); + VPRINTK1(KERN_INFO "%c%d trigger\n", + SCHR(substream->stream), substream->number); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_pcm_group_for_each_entry(s, substream) { - struct snd_card_asihpi_pcm *ds; - ds = s->runtime->private_data; + struct snd_pcm_runtime *runtime = s->runtime; + struct snd_card_asihpi_pcm *ds = runtime->private_data; if (snd_pcm_substream_chip(s) != card) continue; + /* don't link Cap and Play */ + if (substream->stream != s->stream) + continue; + if ((s->stream == SNDRV_PCM_STREAM_PLAYBACK) && (card->support_mmap)) { /* How do I know how much valid data is present - * in buffer? Just guessing 2 periods, but if + * in buffer? Must be at least one period! + * Guessing 2 periods, but if * buffer is bigger it may contain even more * data?? */ - unsigned int preload = ds->pcm_count * 2; - VPRINTK2("preload %d\n", preload); + unsigned int preload = ds->period_bytes * 1; + VPRINTK2(KERN_INFO "%d preload x%x\n", s->number, preload); hpi_handle_error(hpi_outstream_write_buf( - ss, ds->h_stream, - &s->runtime->dma_area[0], + ds->h_stream, + &runtime->dma_area[0], preload, &ds->format)); + ds->pcm_buf_host_rw_ofs = preload; } if (card->support_grouping) { - VPRINTK1("\t_group %dstream %d\n", s->stream, + VPRINTK1(KERN_INFO "\t%c%d group\n", + SCHR(s->stream), s->number); - e = hpi_stream_group_add(ss, + e = hpi_stream_group_add( dpcm->h_stream, ds->h_stream); if (!e) { @@ -604,10 +622,12 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, } else break; } - snd_printd("start\n"); + VPRINTK1(KERN_INFO "start\n"); /* start the master stream */ snd_card_asihpi_pcm_timer_start(substream); - hpi_handle_error(hpi_stream_start(ss, dpcm->h_stream)); + if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) || + !card->support_mmap) + hpi_handle_error(hpi_stream_start(dpcm->h_stream)); break; case SNDRV_PCM_TRIGGER_STOP: @@ -615,88 +635,73 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream, snd_pcm_group_for_each_entry(s, substream) { if (snd_pcm_substream_chip(s) != card) continue; + /* don't link Cap and Play */ + if (substream->stream != s->stream) + continue; /*? workaround linked streams don't transition to SETUP 20070706*/ s->runtime->status->state = SNDRV_PCM_STATE_SETUP; if (card->support_grouping) { - VPRINTK1("\t_group %dstream %d\n", s->stream, + VPRINTK1(KERN_INFO "\t%c%d group\n", + SCHR(s->stream), s->number); snd_pcm_trigger_done(s, substream); } else break; } - snd_printd("stop\n"); + VPRINTK1(KERN_INFO "stop\n"); /* _prepare and _hwparams reset the stream */ - hpi_handle_error(hpi_stream_stop(ss, dpcm->h_stream)); + hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) hpi_handle_error( - hpi_outstream_reset(ss, dpcm->h_stream)); + hpi_outstream_reset(dpcm->h_stream)); if (card->support_grouping) - hpi_handle_error(hpi_stream_group_reset(ss, - dpcm->h_stream)); + hpi_handle_error(hpi_stream_group_reset(dpcm->h_stream)); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_printd("pause release\n"); - hpi_handle_error(hpi_stream_start(ss, dpcm->h_stream)); + VPRINTK1(KERN_INFO "pause release\n"); + hpi_handle_error(hpi_stream_start(dpcm->h_stream)); snd_card_asihpi_pcm_timer_start(substream); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_printd("pause\n"); + VPRINTK1(KERN_INFO "pause\n"); snd_card_asihpi_pcm_timer_stop(substream); - hpi_handle_error(hpi_stream_stop(ss, dpcm->h_stream)); + hpi_handle_error(hpi_stream_stop(dpcm->h_stream)); break; default: - snd_printd("\tINVALID\n"); + snd_printd(KERN_ERR "\tINVALID\n"); return -EINVAL; } |