示例#1
0
static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
			     		struct snd_pcm_hw_params *hw_params)
{
	debug("%s(%p)\n", __func__, sub);
	return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
}
示例#2
0
static int davinci_pcm_hw_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *hw_params)
{
	return snd_pcm_lib_malloc_pages(substream,
					params_buffer_bytes(hw_params));
}
示例#3
0
static int snd_ad1816a_hw_params(snd_pcm_substream_t * substream,
				 snd_pcm_hw_params_t * hw_params)
{
	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
}
示例#4
0
文件: mixart.c 项目: 274914765/C
int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr,
                 struct mixart_pipe *pipe, int monitoring)
{
    int err = 0;

    if(pipe->status == PIPE_UNDEFINED)
        return 0;

    if(monitoring)
        pipe->monitoring = 0;
    else
        pipe->references--;

    if((pipe->references <= 0) && (pipe->monitoring == 0)) {

        struct mixart_msg request;
        struct mixart_delete_group_resp delete_resp;

        /* release the clock */
        err = mixart_set_clock( mgr, pipe, 0);
        if( err < 0 ) {
            snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n");
        }

        /* stop the pipe */
        err = mixart_set_pipe_state(mgr, pipe, 0);
        if( err < 0 ) {
            snd_printk(KERN_ERR "error stopping pipe!\n");
        }

        request.message_id = MSG_STREAM_DELETE_GROUP;
        request.uid = (struct mixart_uid){0,0};
        request.data = &pipe->group_uid;            /* the streaming group ! */
        request.size = sizeof(pipe->group_uid);

        /* delete the pipe */
        err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp);
        if ((err < 0) || (delete_resp.status != 0)) {
            snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status);
        }

        pipe->group_uid = (struct mixart_uid){0,0};
        pipe->stream_count = 0;
        pipe->status = PIPE_UNDEFINED;
    }

    return err;
}

static int mixart_set_stream_state(struct mixart_stream *stream, int start)
{
    struct snd_mixart *chip;
    struct mixart_stream_state_req stream_state_req;
    struct mixart_msg request;

    if(!stream->substream)
        return -EINVAL;

    memset(&stream_state_req, 0, sizeof(stream_state_req));
    stream_state_req.stream_count = 1;
    stream_state_req.stream_info.stream_desc.uid_pipe = stream->pipe->group_uid;
    stream_state_req.stream_info.stream_desc.stream_idx = stream->substream->number;

    if (stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
        request.message_id = start ? MSG_STREAM_START_INPUT_STAGE_PACKET : MSG_STREAM_STOP_INPUT_STAGE_PACKET;
    else
        request.message_id = start ? MSG_STREAM_START_OUTPUT_STAGE_PACKET : MSG_STREAM_STOP_OUTPUT_STAGE_PACKET;

    request.uid = (struct mixart_uid){0,0};
    request.data = &stream_state_req;
    request.size = sizeof(stream_state_req);

    stream->abs_period_elapsed = 0;            /* reset stream pos      */
    stream->buf_periods = 0;
    stream->buf_period_frag = 0;

    chip = snd_pcm_substream_chip(stream->substream);

    return snd_mixart_send_msg_nonblock(chip->mgr, &request);
}

/*
 *  Trigger callback
 */

static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd)
{
    struct mixart_stream *stream = subs->runtime->private_data;

    switch (cmd) {
    case SNDRV_PCM_TRIGGER_START:

        snd_printdd("SNDRV_PCM_TRIGGER_START\n");

        /* START_STREAM */
        if( mixart_set_stream_state(stream, 1) )
            return -EINVAL;

        stream->status = MIXART_STREAM_STATUS_RUNNING;

        break;
    case SNDRV_PCM_TRIGGER_STOP:

        /* STOP_STREAM */
        if( mixart_set_stream_state(stream, 0) )
            return -EINVAL;

        stream->status = MIXART_STREAM_STATUS_OPEN;

        snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");

        break;

    case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
        /* TODO */
        stream->status = MIXART_STREAM_STATUS_PAUSE;
        snd_printdd("SNDRV_PCM_PAUSE_PUSH\n");
        break;
    case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        /* TODO */
        stream->status = MIXART_STREAM_STATUS_RUNNING;
        snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n");
        break;
    default:
        return -EINVAL;
    }
    return 0;
}

static int mixart_sync_nonblock_events(struct mixart_mgr *mgr)
{
    unsigned long timeout = jiffies + HZ;
    while (atomic_read(&mgr->msg_processed) > 0) {
        if (time_after(jiffies, timeout)) {
            snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n");
            return -EBUSY;
        }
        schedule_timeout_uninterruptible(1);
    }
    return 0;
}

/*
 *  prepare callback for all pcms
 */
static int snd_mixart_prepare(struct snd_pcm_substream *subs)
{
    struct snd_mixart *chip = snd_pcm_substream_chip(subs);
    struct mixart_stream *stream = subs->runtime->private_data;

    /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */

    snd_printdd("snd_mixart_prepare\n");

    mixart_sync_nonblock_events(chip->mgr);

    /* only the first stream can choose the sample rate */
    /* the further opened streams will be limited to its frequency (see open) */
    if(chip->mgr->ref_count_rate == 1)
        chip->mgr->sample_rate = subs->runtime->rate;

    /* set the clock only once (first stream) on the same pipe */
    if(stream->pipe->references == 1) {
        if( mixart_set_clock(chip->mgr, stream->pipe, subs->runtime->rate) )
            return -EINVAL;
    }

    return 0;
}


static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t format)
{
    int err;
    struct snd_mixart *chip;
    struct mixart_msg request;
    struct mixart_stream_param_desc stream_param;
    struct mixart_return_uid 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 = (struct mixart_uid){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(struct snd_pcm_substream *subs,
                                struct snd_pcm_hw_params *hw)
{
    struct snd_mixart *chip = snd_pcm_substream_chip(subs);
    struct mixart_mgr *mgr = chip->mgr;
    struct mixart_stream *stream = 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);

    mutex_lock(&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);
    }
    mutex_unlock(&mgr->setup_mutex);

    return err;
}

static int snd_mixart_hw_free(struct snd_pcm_substream *subs)
{
    struct snd_mixart *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 struct snd_pcm_hardware snd_mixart_analog_caps =
{
    .info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                  SNDRV_PCM_INFO_MMAP_VALID |
                  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 struct snd_pcm_hardware snd_mixart_digital_caps =
{
    .info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                  SNDRV_PCM_INFO_MMAP_VALID |
                  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(struct snd_pcm_substream *subs)
{
    struct snd_mixart            *chip = snd_pcm_substream_chip(subs);
    struct mixart_mgr        *mgr = chip->mgr;
    struct snd_pcm_runtime *runtime = subs->runtime;
    struct snd_pcm *pcm = subs->pcm;
    struct mixart_stream     *stream;
    struct mixart_pipe       *pipe;
    int err = 0;
    int pcm_number;

    mutex_lock(&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:
    mutex_unlock(&mgr->setup_mutex);

    return err;
}


static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
{
    struct snd_mixart            *chip = snd_pcm_substream_chip(subs);
    struct mixart_mgr        *mgr = chip->mgr;
    struct snd_pcm_runtime *runtime = subs->runtime;
    struct snd_pcm *pcm = subs->pcm;
    struct mixart_stream     *stream;
    struct mixart_pipe       *pipe;
    int err = 0;
    int pcm_number;

    mutex_lock(&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:
    mutex_unlock(&mgr->setup_mutex);

    return err;
}



static int snd_mixart_close(struct snd_pcm_substream *subs)
{
    struct snd_mixart *chip = snd_pcm_substream_chip(subs);
    struct mixart_mgr *mgr = chip->mgr;
    struct mixart_stream *stream = subs->runtime->private_data;

    mutex_lock(&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;

    mutex_unlock(&mgr->setup_mutex);
    return 0;
}


static snd_pcm_uframes_t snd_mixart_stream_pointer(struct snd_pcm_substream *subs)
{
    struct snd_pcm_runtime *runtime = subs->runtime;
    struct mixart_stream   *stream  = runtime->private_data;

    return (snd_pcm_uframes_t)((stream->buf_periods * runtime->period_size) + stream->buf_period_frag);
}



static struct snd_pcm_ops 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 struct snd_pcm_ops 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(struct snd_mixart *chip, struct snd_pcm *pcm)
{
#if 0
    struct snd_pcm_substream *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(struct snd_mixart *chip)
{
    int err;
    struct snd_pcm *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(struct snd_mixart *chip)
{
    int err;
    struct snd_pcm *pcm;
    char name[32];

    sprintf(name, "miXart AES/EBU %d", chip->chip_idx);
    if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL,
                   MIXART_PLAYBACK_STREAMS,
                   MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
        snd_printk(KERN_ERR "cannot create the digital 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_dig = pcm;
    return 0;
}

static int snd_mixart_chip_free(struct snd_mixart *chip)
{
    kfree(chip);
    return 0;
}

static int snd_mixart_chip_dev_free(struct snd_device *device)
{
    struct snd_mixart *chip = device->device_data;
    return snd_mixart_chip_free(chip);
}


/*
 */
static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int idx)
{
    int err;
    struct snd_mixart *chip;
    static struct snd_device_ops ops = {
        .dev_free = snd_mixart_chip_dev_free,
    };

    mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL);
    if (! chip) {
        snd_printk(KERN_ERR "cannot allocate chip\n");
        return -ENOMEM;
    }

    chip->card = card;
    chip->chip_idx = idx;
    chip->mgr = mgr;

    if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
        snd_mixart_chip_free(chip);
        return err;
    }

    snd_card_set_dev(card, &mgr->pci->dev);

    return 0;
}
示例#5
0
static int loopback_hw_params(struct snd_pcm_substream *substream,
			      struct snd_pcm_hw_params *params)
{
	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
}
示例#6
0
/* this may get called several times by oss emulation */
static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
			      struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct hsw_priv_data *pdata =
		snd_soc_platform_get_drvdata(rtd->platform);
	struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
	struct sst_hsw *hsw = pdata->hsw;
	struct sst_module *module_data;
	struct sst_dsp *dsp;
	enum sst_hsw_stream_type stream_type;
	enum sst_hsw_stream_path_id path_id;
	u32 rate, bits, map, pages, module_id;
	u8 channels;
	int ret;

	/* stream direction */
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
	else
		path_id = SST_HSW_STREAM_PATH_SSP0_IN;

	/* DSP stream type depends on DAI ID */
	switch (rtd->cpu_dai->id) {
	case 0:
		stream_type = SST_HSW_STREAM_TYPE_SYSTEM;
		module_id = SST_HSW_MODULE_PCM_SYSTEM;
		break;
	case 1:
	case 2:
		stream_type = SST_HSW_STREAM_TYPE_RENDER;
		module_id = SST_HSW_MODULE_PCM;
		break;
	case 3:
		/* path ID needs to be OUT for loopback */
		stream_type = SST_HSW_STREAM_TYPE_LOOPBACK;
		path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
		module_id = SST_HSW_MODULE_PCM_REFERENCE;
		break;
	case 4:
		stream_type = SST_HSW_STREAM_TYPE_CAPTURE;
		module_id = SST_HSW_MODULE_PCM_CAPTURE;
		break;
	default:
		dev_err(rtd->dev, "error: invalid DAI ID %d\n",
			rtd->cpu_dai->id);
		return -EINVAL;
	};

	ret = sst_hsw_stream_format(hsw, pcm_data->stream,
		path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT);
	if (ret < 0) {
		dev_err(rtd->dev, "error: failed to set format %d\n", ret);
		return ret;
	}

	rate = params_rate(params);
	ret = sst_hsw_stream_set_rate(hsw, pcm_data->stream, rate);
	if (ret < 0) {
		dev_err(rtd->dev, "error: could not set rate %d\n", rate);
		return ret;
	}

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		bits = SST_HSW_DEPTH_16BIT;
		sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16);
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		bits = SST_HSW_DEPTH_24BIT;
		sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32);
		break;
	default:
		dev_err(rtd->dev, "error: invalid format %d\n",
			params_format(params));
		return -EINVAL;
	}

	ret = sst_hsw_stream_set_bits(hsw, pcm_data->stream, bits);
	if (ret < 0) {
		dev_err(rtd->dev, "error: could not set bits %d\n", bits);
		return ret;
	}

	/* we only support stereo atm */
	channels = params_channels(params);
	if (channels != 2) {
		dev_err(rtd->dev, "error: invalid channels %d\n", channels);
		return -EINVAL;
	}

	map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO);
	sst_hsw_stream_set_map_config(hsw, pcm_data->stream,
			map, SST_HSW_CHANNEL_CONFIG_STEREO);

	ret = sst_hsw_stream_set_channels(hsw, pcm_data->stream, channels);
	if (ret < 0) {
		dev_err(rtd->dev, "error: could not set channels %d\n",
			channels);
		return ret;
	}

	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
	if (ret < 0) {
		dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n",
			params_buffer_bytes(params), ret);
		return ret;
	}

	ret = create_adsp_page_table(pdata, rtd, runtime->dma_area,
		runtime->dma_bytes, rtd->cpu_dai->id, substream->stream);
	if (ret < 0)
		return ret;

	sst_hsw_stream_set_style(hsw, pcm_data->stream,
		SST_HSW_INTERLEAVING_PER_CHANNEL);

	if (runtime->dma_bytes % PAGE_SIZE)
		pages = (runtime->dma_bytes / PAGE_SIZE) + 1;
	else
		pages = runtime->dma_bytes / PAGE_SIZE;

	ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
		virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]),
		pages, runtime->dma_bytes, 0,
		(u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT));
	if (ret < 0) {
		dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
		return ret;
	}

	dsp = sst_hsw_get_dsp(hsw);

	module_data = sst_module_get_from_id(dsp, module_id);
	if (module_data == NULL) {
		dev_err(rtd->dev, "error: failed to get module config\n");
		return -EINVAL;
	}

	/* we use hardcoded memory offsets atm, will be updated for new FW */
	if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) {
		sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
			SST_HSW_MODULE_PCM_CAPTURE, module_data->entry);
		sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
			0x449400, 0x4000);
		sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
			0x400000, 0);
	} else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */
		sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
			SST_HSW_MODULE_PCM_SYSTEM, module_data->entry);

		sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
			module_data->offset, module_data->size);
		sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
			0x44d400, 0x3800);

		sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
			module_data->offset, module_data->size);
		sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
			0x400000, 0);
	}

	ret = sst_hsw_stream_commit(hsw, pcm_data->stream);
	if (ret < 0) {
		dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
		return ret;
	}

	ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
	if (ret < 0)
		dev_err(rtd->dev, "error: failed to pause %d\n", ret);

	return 0;
}
示例#7
0
/* hw_params callback */
static int snd_ca0106_pcm_hw_params_capture(snd_pcm_substream_t *substream,
				      snd_pcm_hw_params_t * hw_params)
{
	return snd_pcm_lib_malloc_pages(substream,
					params_buffer_bytes(hw_params));
}
示例#8
0
/* this may get called several times by oss emulation */
static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct sst_byt_priv_data *pdata =
		snd_soc_platform_get_drvdata(rtd->platform);
	struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
	struct sst_byt *byt = pdata->byt;
	u32 rate, bits;
	u8 channels;
	int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);

	dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);

	ret = sst_byt_stream_type(byt, pcm_data->stream,
				  1, 1, !playback);
	if (ret < 0) {
		dev_err(rtd->dev, "failed to set stream format %d\n", ret);
		return ret;
	}

	rate = params_rate(params);
	ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
	if (ret < 0) {
		dev_err(rtd->dev, "could not set rate %d\n", rate);
		return ret;
	}

	bits = snd_pcm_format_width(params_format(params));
	ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
	if (ret < 0) {
		dev_err(rtd->dev, "could not set formats %d\n",
			params_rate(params));
		return ret;
	}

	channels = (u8)(params_channels(params) & 0xF);
	ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
	if (ret < 0) {
		dev_err(rtd->dev, "could not set channels %d\n",
			params_rate(params));
		return ret;
	}

	snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));

	ret = sst_byt_stream_buffer(byt, pcm_data->stream,
				    substream->dma_buffer.addr,
				    params_buffer_bytes(params));
	if (ret < 0) {
		dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
		return ret;
	}

	ret = sst_byt_stream_commit(byt, pcm_data->stream);
	if (ret < 0) {
		dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
		return ret;
	}

	return 0;
}
/* hw_params callback */
static int
snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream,
			 snd_pcm_hw_params_t * hw_params)
{
	vortex_t *chip = snd_pcm_substream_chip(substream);
	stream_t *stream = (stream_t *) (substream->runtime->private_data);
	snd_pcm_sgbuf_t *sgbuf;
	int err;

	// Alloc buffer memory.
	err =
	    snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
	if (err < 0) {
		printk(KERN_ERR "Vortex: pcm page alloc failed!\n");
		return err;
	}
	//sgbuf = (snd_pcm_sgbuf_t *) substream->runtime->dma_private;
	sgbuf = snd_pcm_substream_sgbuf(substream);
	/*
	   printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
	   params_period_bytes(hw_params), params_channels(hw_params));
	 */
	spin_lock_irq(&chip->lock);
	// Make audio routes and config buffer DMA.
	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
		int dma, type = VORTEX_PCM_TYPE(substream->pcm);
		/* Dealloc any routes. */
		if (stream != NULL)
			vortex_adb_allocroute(chip, stream->dma,
					      stream->nr_ch, stream->dir,
					      stream->type);
		/* Alloc routes. */
		dma =
		    vortex_adb_allocroute(chip, -1,
					  params_channels(hw_params),
					  substream->stream, type);
		if (dma < 0) {
			spin_unlock_irq(&chip->lock);
			return dma;
		}
		stream = substream->runtime->private_data = &chip->dma_adb[dma];
		stream->substream = substream;
		/* Setup Buffers. */
		vortex_adbdma_setbuffers(chip, dma, sgbuf,
					 params_period_bytes(hw_params),
					 params_periods(hw_params));
	}
#ifndef CHIP_AU8810
	else {
		/* if (stream != NULL)
		   vortex_wt_allocroute(chip, substream->number, 0); */
		vortex_wt_allocroute(chip, substream->number,
				     params_channels(hw_params));
		stream = substream->runtime->private_data =
		    &chip->dma_wt[substream->number];
		stream->dma = substream->number;
		stream->substream = substream;
		vortex_wtdma_setbuffers(chip, substream->number, sgbuf,
					params_period_bytes(hw_params),
					params_periods(hw_params));
	}
#endif
	spin_unlock_irq(&chip->lock);
	return 0;
}