📄 mixart.c
字号:
} return 0;}static int mixart_set_format(mixart_stream_t *stream, snd_pcm_format_t format){ int err; mixart_t *chip; mixart_msg_t request; mixart_stream_param_desc_t stream_param; mixart_return_uid_t resp; chip = snd_pcm_substream_chip(stream->substream); memset(&stream_param, 0, sizeof(stream_param)); stream_param.coding_type = CT_LINEAR; stream_param.number_of_channel = stream->channels; stream_param.sampling_freq = chip->mgr->sample_rate; if(stream_param.sampling_freq == 0) stream_param.sampling_freq = 44100; /* if frequency not yet defined, use some default */ switch(format){ case SNDRV_PCM_FORMAT_U8: stream_param.sample_type = ST_INTEGER_8; stream_param.sample_size = 8; break; case SNDRV_PCM_FORMAT_S16_LE: stream_param.sample_type = ST_INTEGER_16LE; stream_param.sample_size = 16; break; case SNDRV_PCM_FORMAT_S16_BE: stream_param.sample_type = ST_INTEGER_16BE; stream_param.sample_size = 16; break; case SNDRV_PCM_FORMAT_S24_3LE: stream_param.sample_type = ST_INTEGER_24LE; stream_param.sample_size = 24; break; case SNDRV_PCM_FORMAT_S24_3BE: stream_param.sample_type = ST_INTEGER_24BE; stream_param.sample_size = 24; break; case SNDRV_PCM_FORMAT_FLOAT_LE: stream_param.sample_type = ST_FLOATING_POINT_32LE; stream_param.sample_size = 32; break; case SNDRV_PCM_FORMAT_FLOAT_BE: stream_param.sample_type = ST_FLOATING_POINT_32BE; stream_param.sample_size = 32; break; default: snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n"); return -EINVAL; } snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n", stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels); /* TODO: what else to configure ? */ /* stream_param.samples_per_frame = 2; */ /* stream_param.bytes_per_frame = 4; */ /* stream_param.bytes_per_sample = 2; */ stream_param.pipe_count = 1; /* set to 1 */ stream_param.stream_count = 1; /* set to 1 */ stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid; stream_param.stream_desc[0].stream_idx = stream->substream->number; request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM; request.uid = (mixart_uid_t){0,0}; request.data = &stream_param; request.size = sizeof(stream_param); err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp); if((err < 0) || resp.error_code) { snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code); return -EINVAL; } return 0;}/* * HW_PARAMS callback for all pcms */static int snd_mixart_hw_params(snd_pcm_substream_t *subs, snd_pcm_hw_params_t *hw){ mixart_t *chip = snd_pcm_substream_chip(subs); mixart_mgr_t *mgr = chip->mgr; mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data; snd_pcm_format_t format; int err; int channels; /* set up channels */ channels = params_channels(hw); /* set up format for the stream */ format = params_format(hw); down(&mgr->setup_mutex); /* update the stream levels */ if( stream->pcm_number <= MIXART_PCM_DIGITAL ) { int is_aes = stream->pcm_number > MIXART_PCM_ANALOG; if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK ) mixart_update_playback_stream_level(chip, is_aes, subs->number); else mixart_update_capture_stream_level( chip, is_aes); } stream->channels = channels; /* set the format to the board */ err = mixart_set_format(stream, format); if(err < 0) { return err; } /* allocate buffer */ err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw)); if (err > 0) { struct mixart_bufferinfo *bufferinfo; int i = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (stream->pcm_number * (MIXART_PLAYBACK_STREAMS+MIXART_CAPTURE_STREAMS)) + subs->number; if( subs->stream == SNDRV_PCM_STREAM_CAPTURE ) { i += MIXART_PLAYBACK_STREAMS; /* in array capture is behind playback */ } bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area; bufferinfo[i].buffer_address = subs->runtime->dma_addr; bufferinfo[i].available_length = subs->runtime->dma_bytes; /* bufferinfo[i].buffer_id is already defined */ snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i, bufferinfo[i].buffer_address, bufferinfo[i].available_length, subs->number); } up(&mgr->setup_mutex); return err;}static int snd_mixart_hw_free(snd_pcm_substream_t *subs){ mixart_t *chip = snd_pcm_substream_chip(subs); snd_pcm_lib_free_pages(subs); mixart_sync_nonblock_events(chip->mgr); return 0;}/* * TODO CONFIGURATION SPACE for all pcms, mono pcm must update channels_max */static snd_pcm_hardware_t snd_mixart_analog_caps ={ .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_PAUSE), .formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ), .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (32*1024), .period_bytes_min = 256, /* 256 frames U8 mono*/ .period_bytes_max = (16*1024), .periods_min = 2, .periods_max = (32*1024/256),};static snd_pcm_hardware_t snd_mixart_digital_caps ={ .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_PAUSE), .formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ), .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 32000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (32*1024), .period_bytes_min = 256, /* 256 frames U8 mono*/ .period_bytes_max = (16*1024), .periods_min = 2, .periods_max = (32*1024/256),};static int snd_mixart_playback_open(snd_pcm_substream_t *subs){ mixart_t *chip = snd_pcm_substream_chip(subs); mixart_mgr_t *mgr = chip->mgr; snd_pcm_runtime_t *runtime = subs->runtime; snd_pcm_t *pcm = subs->pcm; mixart_stream_t *stream; mixart_pipe_t *pipe; int err = 0; int pcm_number; down(&mgr->setup_mutex); if ( pcm == chip->pcm ) { pcm_number = MIXART_PCM_ANALOG; runtime->hw = snd_mixart_analog_caps; } else { snd_assert ( pcm == chip->pcm_dig ); pcm_number = MIXART_PCM_DIGITAL; runtime->hw = snd_mixart_digital_caps; } snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number); /* get stream info */ stream = &(chip->playback_stream[pcm_number][subs->number]); if (stream->status != MIXART_STREAM_STATUS_FREE){ /* streams in use */ snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); err = -EBUSY; goto _exit_open; } /* get pipe pointer (out pipe) */ pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0); if (pipe == NULL) { err = -EINVAL; goto _exit_open; } /* start the pipe if necessary */ err = mixart_set_pipe_state(chip->mgr, pipe, 1); if( err < 0 ) { snd_printk(KERN_ERR "error starting pipe!\n"); snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); err = -EINVAL; goto _exit_open; } stream->pipe = pipe; stream->pcm_number = pcm_number; stream->status = MIXART_STREAM_STATUS_OPEN; stream->substream = subs; stream->channels = 0; /* not configured yet */ runtime->private_data = stream; snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64); /* if a sample rate is already used, another stream cannot change */ if(mgr->ref_count_rate++) { if(mgr->sample_rate) { runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate; } } _exit_open: up(&mgr->setup_mutex); return err;}static int snd_mixart_capture_open(snd_pcm_substream_t *subs){ mixart_t *chip = snd_pcm_substream_chip(subs); mixart_mgr_t *mgr = chip->mgr; snd_pcm_runtime_t *runtime = subs->runtime; snd_pcm_t *pcm = subs->pcm; mixart_stream_t *stream; mixart_pipe_t *pipe; int err = 0; int pcm_number; down(&mgr->setup_mutex); if ( pcm == chip->pcm ) { pcm_number = MIXART_PCM_ANALOG; runtime->hw = snd_mixart_analog_caps; } else { snd_assert ( pcm == chip->pcm_dig ); pcm_number = MIXART_PCM_DIGITAL; runtime->hw = snd_mixart_digital_caps; } runtime->hw.channels_min = 2; /* for instance, no mono */ snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number); /* get stream info */ stream = &(chip->capture_stream[pcm_number]); if (stream->status != MIXART_STREAM_STATUS_FREE){ /* streams in use */ snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); err = -EBUSY; goto _exit_open; } /* get pipe pointer (in pipe) */ pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0); if (pipe == NULL) { err = -EINVAL; goto _exit_open; } /* start the pipe if necessary */ err = mixart_set_pipe_state(chip->mgr, pipe, 1); if( err < 0 ) { snd_printk(KERN_ERR "error starting pipe!\n"); snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); err = -EINVAL; goto _exit_open; } stream->pipe = pipe; stream->pcm_number = pcm_number; stream->status = MIXART_STREAM_STATUS_OPEN; stream->substream = subs; stream->channels = 0; /* not configured yet */ runtime->private_data = stream; snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64); /* if a sample rate is already used, another stream cannot change */ if(mgr->ref_count_rate++) { if(mgr->sample_rate) { runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate; } } _exit_open: up(&mgr->setup_mutex); return err;}static int snd_mixart_close(snd_pcm_substream_t *subs){ mixart_t *chip = snd_pcm_substream_chip(subs); mixart_mgr_t *mgr = chip->mgr; mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data; down(&mgr->setup_mutex); snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number); /* sample rate released */ if(--mgr->ref_count_rate == 0) { mgr->sample_rate = 0; } /* delete pipe */ if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) { snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number); } stream->pipe = NULL; stream->status = MIXART_STREAM_STATUS_FREE; stream->substream = NULL; up(&mgr->setup_mutex); return 0;}static snd_pcm_uframes_t snd_mixart_stream_pointer(snd_pcm_substream_t * subs){ snd_pcm_runtime_t *runtime = subs->runtime; mixart_stream_t *stream = (mixart_stream_t*)runtime->private_data; return (snd_pcm_uframes_t)((stream->buf_periods * runtime->period_size) + stream->buf_period_frag);}static snd_pcm_ops_t snd_mixart_playback_ops = { .open = snd_mixart_playback_open, .close = snd_mixart_close, .ioctl = snd_pcm_lib_ioctl, .prepare = snd_mixart_prepare, .hw_params = snd_mixart_hw_params, .hw_free = snd_mixart_hw_free, .trigger = snd_mixart_trigger, .pointer = snd_mixart_stream_pointer,};static snd_pcm_ops_t snd_mixart_capture_ops = { .open = snd_mixart_capture_open, .close = snd_mixart_close, .ioctl = snd_pcm_lib_ioctl, .prepare = snd_mixart_prepare, .hw_params = snd_mixart_hw_params, .hw_free = snd_mixart_hw_free, .trigger = snd_mixart_trigger, .pointer = snd_mixart_stream_pointer,};static void preallocate_buffers(mixart_t *chip, snd_pcm_t *pcm){#if 0 snd_pcm_substream_t *subs; int stream; for (stream = 0; stream < 2; stream++) { int idx = 0; for (subs = pcm->streams[stream].substream; subs; subs = subs->next, idx++) /* set up the unique device id with the chip index */ subs->dma_device.id = subs->pcm->device << 16 | subs->stream << 8 | (subs->number + 1) | (chip->chip_idx + 1) << 24; }#endif snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->mgr->pci), 32*1024, 32*1024);}/* */static int snd_mixart_pcm_analog(mixart_t *chip){ int err; snd_pcm_t *pcm; char name[32]; sprintf(name, "miXart analog %d", chip->chip_idx); if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG, MIXART_PLAYBACK_STREAMS, MIXART_CAPTURE_STREAMS, &pcm)) < 0) { snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx); return err; } pcm->private_data = chip; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); pcm->info_flags = 0; strcpy(pcm->name, name); preallocate_buffers(chip, pcm); chip->pcm = pcm; return 0;}/* */static int snd_mixart_pcm_digital(mixart_t *chip){ int err; snd_pcm_t *pcm; char name[32]; sprintf(name, "miXart AES/EBU %d", chip->chip_idx); if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -