📄 harmony.c
字号:
return IRQ_HANDLED;}/* * proc entry * this proc file will give some debugging info */static void snd_harmony_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer){ snd_card_harmony_t *harmony = (snd_card_harmony_t *)entry->private_data; snd_iprintf(buffer, "LASI Harmony driver\nLaurent Canet <canetl@esiee.fr>\n\n"); snd_iprintf(buffer, "IRQ %d, hpa %lx, id %d rev %d\n", harmony->irq, harmony->hpa, harmony->id, harmony->rev); snd_iprintf(buffer, "Current gain %lx\n", (unsigned long) harmony->current_gain); snd_iprintf(buffer, "\tsample rate=%d\n", harmony->sample_rate); snd_iprintf(buffer, "\tstereo select=%d\n", harmony->stereo_select); snd_iprintf(buffer, "\tbitperchan=%d\n\n", harmony->data_format); snd_iprintf(buffer, "Play status:\n"); snd_iprintf(buffer, "\tstopped %d\n", harmony->ply_stopped); snd_iprintf(buffer, "\tbuffer %lx, count %d\n", harmony->ply_buffer, harmony->ply_count); snd_iprintf(buffer, "\tbuf %d size %d\n\n", harmony->ply_buf, harmony->ply_size); snd_iprintf(buffer, "Capture status:\n"); snd_iprintf(buffer, "\tstopped %d\n", harmony->cap_stopped); snd_iprintf(buffer, "\tbuffer %lx, count %d\n", harmony->cap_buffer, harmony->cap_count); snd_iprintf(buffer, "\tbuf %d, size %d\n\n", harmony->cap_buf, harmony->cap_size); snd_iprintf(buffer, "Funny stats: total played=%d, recorded=%d\n\n", harmony->ply_total, harmony->cap_total); snd_iprintf(buffer, "Register:\n"); snd_iprintf(buffer, "\tgainctl: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_GAINCTL)); snd_iprintf(buffer, "\tcntl: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_CNTL)); snd_iprintf(buffer, "\tid: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_ID)); snd_iprintf(buffer, "\tpcuradd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_PCURADD)); snd_iprintf(buffer, "\trcuradd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_RCURADD)); snd_iprintf(buffer, "\tpnxtadd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_PNXTADD)); snd_iprintf(buffer, "\trnxtadd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_RNXTADD)); snd_iprintf(buffer, "\tdstatus: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_DSTATUS)); snd_iprintf(buffer, "\tov: %lx\n\n", (unsigned long) gsc_readl(harmony->hpa+REG_OV)); }static void __devinit snd_harmony_proc_init(snd_card_harmony_t *harmony){ snd_info_entry_t *entry; if (! snd_card_proc_new(harmony->card, "harmony", &entry)) snd_info_set_text_ops(entry, harmony, 2048, snd_harmony_proc_read);}/* * PCM Stuff */static int snd_card_harmony_playback_ioctl(snd_pcm_substream_t * substream, unsigned int cmd, void *arg){ return snd_pcm_lib_ioctl(substream, cmd, arg);}static int snd_card_harmony_capture_ioctl(snd_pcm_substream_t * substream, unsigned int cmd, void *arg){ return snd_pcm_lib_ioctl(substream, cmd, arg);}static int snd_card_harmony_playback_trigger(snd_pcm_substream_t * substream, int cmd){ snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_STOP: if (harmony->ply_stopped) return -EBUSY; harmony->ply_stopped = 1; snd_harmony_disable_interrupts(harmony); break; case SNDRV_PCM_TRIGGER_START: if (!harmony->ply_stopped) return -EBUSY; harmony->ply_stopped = 0; /* write the location of the first buffer to play */ gsc_writel(harmony->ply_buffer, harmony->hpa+REG_PNXTADD); snd_harmony_enable_interrupts(harmony); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_SUSPEND: DPRINTK(KERN_INFO PFX "received unimplemented trigger: %d\n", cmd); default: return -EINVAL; } return 0;}static int snd_card_harmony_capture_trigger(snd_pcm_substream_t * substream, int cmd){ snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_STOP: if (harmony->cap_stopped) return -EBUSY; harmony->cap_stopped = 1; snd_harmony_disable_interrupts(harmony); break; case SNDRV_PCM_TRIGGER_START: if (!harmony->cap_stopped) return -EBUSY; harmony->cap_stopped = 0; snd_harmony_enable_interrupts(harmony); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_SUSPEND: DPRINTK(KERN_INFO PFX "Received unimplemented trigger: %d\n", cmd); default: return -EINVAL; } return 0;}/* set data format */static int snd_harmony_set_data_format(snd_card_harmony_t *harmony, int pcm_format){ int old_format = harmony->data_format; int new_format = old_format; switch (pcm_format) { case SNDRV_PCM_FORMAT_S16_BE: new_format = HARMONY_DF_16BIT_LINEAR; break; case SNDRV_PCM_FORMAT_A_LAW: new_format = HARMONY_DF_8BIT_ALAW; break; case SNDRV_PCM_FORMAT_MU_LAW: new_format = HARMONY_DF_8BIT_ULAW; break; } /* re-initialize silence buffer if needed */ if (old_format != new_format) snd_pcm_format_set_silence(pcm_format, harmony->silence_dma.area, (HARMONY_BUF_SIZE * SILENCE_BUFS * 8) / snd_pcm_format_width(pcm_format)); return new_format;}static int snd_card_harmony_playback_prepare(snd_pcm_substream_t * substream){ snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; harmony->ply_size = snd_pcm_lib_buffer_bytes(substream); harmony->ply_count = snd_pcm_lib_period_bytes(substream); harmony->ply_buf = 0; harmony->ply_stopped = 1; /* initialize given sample rate */ harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate); /* data format */ harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format); /* number of channels */ if (runtime->channels == 2) harmony->stereo_select = HARMONY_SS_STEREO; else harmony->stereo_select = HARMONY_SS_MONO; DPRINTK(KERN_INFO PFX "Playback_prepare, sr=%d(%x), df=%x, ss=%x hpa=%lx\n", runtime->rate, harmony->sample_rate, harmony->data_format, harmony->stereo_select, harmony->hpa); snd_harmony_update_control(harmony); harmony->format_initialized = 1; harmony->ply_buffer = runtime->dma_addr; return 0;}static int snd_card_harmony_capture_prepare(snd_pcm_substream_t * substream){ snd_pcm_runtime_t *runtime = substream->runtime; snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); harmony->cap_size = snd_pcm_lib_buffer_bytes(substream); harmony->cap_count = snd_pcm_lib_period_bytes(substream); harmony->cap_count = 0; harmony->cap_stopped = 1; /* initialize given sample rate */ harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate); /* data format */ harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format); /* number of channels */ if (runtime->channels == 1) harmony->stereo_select = HARMONY_SS_MONO; else if (runtime->channels == 2) harmony->stereo_select = HARMONY_SS_STEREO; snd_harmony_update_control(harmony); harmony->format_initialized = 1; harmony->cap_buffer = runtime->dma_addr; return 0;}static snd_pcm_uframes_t snd_card_harmony_capture_pointer(snd_pcm_substream_t * substream){ snd_pcm_runtime_t *runtime = substream->runtime; snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); unsigned long rcuradd; int recorded; if (harmony->cap_stopped) return 0; if (harmony->capture_substream == NULL) return 0; rcuradd = gsc_readl(harmony->hpa+REG_RCURADD); recorded = (rcuradd - harmony->cap_buffer); recorded %= harmony->cap_size; return bytes_to_frames(runtime, recorded);}/* */static snd_pcm_uframes_t snd_card_harmony_playback_pointer(snd_pcm_substream_t * substream){ snd_pcm_runtime_t *runtime = substream->runtime; snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); int played; long int pcuradd = gsc_readl(harmony->hpa+REG_PCURADD); if ((harmony->ply_stopped) || (harmony->playback_substream == NULL)) return 0; if ((harmony->ply_buffer == 0) || (harmony->ply_size == 0)) return 0; played = (pcuradd - harmony->ply_buffer); printk(KERN_DEBUG PFX "Pointer is %lx-%lx = %d\n", pcuradd, harmony->ply_buffer, played); if (pcuradd > harmony->ply_buffer + harmony->ply_size) return 0; return bytes_to_frames(runtime, played);}static snd_pcm_hardware_t snd_card_harmony_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER), .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_MU_LAW), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 5500, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = MAX_BUFFER_SIZE, .period_bytes_min = HARMONY_BUF_SIZE, .period_bytes_max = HARMONY_BUF_SIZE, .periods_min = 1, .periods_max = MAX_BUFS, .fifo_size = 0,};static snd_pcm_hardware_t snd_card_harmony_capture ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER), .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_MU_LAW), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 5500, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = MAX_BUFFER_SIZE, .period_bytes_min = HARMONY_BUF_SIZE, .period_bytes_max = HARMONY_BUF_SIZE, .periods_min = 1, .periods_max = MAX_BUFS, .fifo_size = 0,};static int snd_card_harmony_playback_open(snd_pcm_substream_t * substream){ snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; harmony->playback_substream = substream; runtime->hw = snd_card_harmony_playback; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates); if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; return 0;}static int snd_card_harmony_capture_open(snd_pcm_substream_t * substream){ snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; harmony->capture_substream = substream; runtime->hw = snd_card_harmony_capture; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates); if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; return 0;}static int snd_card_harmony_playback_close(snd_pcm_substream_t * substream){ snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); harmony->playback_substream = NULL; harmony->ply_size = 0; harmony->ply_buf = 0; harmony->ply_buffer = 0; harmony->ply_count = 0; harmony->ply_stopped = 1; harmony->format_initialized = 0; return 0;}static int snd_card_harmony_capture_close(snd_pcm_substream_t * substream){ snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); harmony->capture_substream = NULL; harmony->cap_size = 0; harmony->cap_buf = 0; harmony->cap_buffer = 0; harmony->cap_count = 0; harmony->cap_stopped = 1; harmony->format_initialized = 0; return 0;}static int snd_card_harmony_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t * hw_params){ int err; err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err > 0 && substream->dma_device.type == SNDRV_DMA_TYPE_CONTINUOUS) substream->runtime->dma_addr = __pa(substream->runtime->dma_area); DPRINTK(KERN_INFO PFX "HW Params returned %d, dma_addr %lx\n", err, (unsigned long)substream->runtime->dma_addr); return err;}static int snd_card_harmony_hw_free(snd_pcm_substream_t *substream) { snd_pcm_lib_free_pages(substream); return 0;}static snd_pcm_ops_t snd_card_harmony_playback_ops = { .open = snd_card_harmony_playback_open, .close = snd_card_harmony_playback_close, .ioctl = snd_card_harmony_playback_ioctl, .hw_params = snd_card_harmony_hw_params,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -