提交 e618a560 编写于 作者: T Takashi Iwai

Merge branch 'topic/ctxfi' into for-linus

* topic/ctxfi: (35 commits)
  ALSA: ctxfi - Clear PCM resources at hw_params and hw_free
  ALSA: ctxfi - Check the presence of SRC instance in PCM pointer callbacks
  ALSA: ctxfi - Add missing start check in atc_pcm_playback_start()
  ALSA: ctxfi - Add use_system_timer module option
  ALSA: ctxfi - Fix wrong model id for UAA
  ALSA: ctxfi - Clean up probe routines
  ALSA: ctxfi - Fix / clean up hw20k2 chip code
  ALSA: ctxfi - Fix possible buffer pointer overrun
  ALSA: ctxfi - Remove useless initializations and cast
  ALSA: ctxfi - Fix DMA mask for emu20k2 chip
  ALSA: ctxfi - Make volume controls more intuitive
  ALSA: ctxfi - Optimize the native timer handling using wc counter
  ALSA: ctxfi - Add missing inclusion of linux/math64.h
  ALSA: ctxfi - Set device 0 for mixer control elements
  ALSA: ctxfi - Clean up / optimize
  ALSA: ctxfi - Set periods_min to 2
  ALSA: ctxfi - Use native timer interrupt on emu20k1
  ALSA: ctxfi - Fix previous fix for 64bit DMA
  ALSA: ctxfi - Fix endian-dependent codes
  ALSA: ctxfi - Allow 64bit DMA
  ...
......@@ -460,6 +460,25 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
The power-management is supported.
Module snd-ctxfi
----------------
Module for Creative Sound Blaster X-Fi boards (20k1 / 20k2 chips)
* Creative Sound Blaster X-Fi Titanium Fatal1ty Champion Series
* Creative Sound Blaster X-Fi Titanium Fatal1ty Professional Series
* Creative Sound Blaster X-Fi Titanium Professional Audio
* Creative Sound Blaster X-Fi Titanium
* Creative Sound Blaster X-Fi Elite Pro
* Creative Sound Blaster X-Fi Platinum
* Creative Sound Blaster X-Fi Fatal1ty
* Creative Sound Blaster X-Fi XtremeGamer
* Creative Sound Blaster X-Fi XtremeMusic
reference_rate - reference sample rate, 44100 or 48000 (default)
multiple - multiple to ref. sample rate, 1 or 2 (default)
This module supports multiple cards.
Module snd-darla20
------------------
......
......@@ -1314,6 +1314,13 @@
#define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */
#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
#define PCI_DEVICE_ID_CREATIVE_20K1 0x0005
#define PCI_DEVICE_ID_CREATIVE_20K2 0x000b
#define PCI_SUBDEVICE_ID_CREATIVE_SB0760 0x0024
#define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041
#define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042
#define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043
#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000
#define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */
#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938
......
......@@ -275,6 +275,16 @@ config SND_CS5535AUDIO
To compile this driver as a module, choose M here: the module
will be called snd-cs5535audio.
config SND_CTXFI
tristate "Creative Sound Blaster X-Fi"
select SND_PCM
help
If you want to use soundcards based on Creative Sound Blastr X-Fi
boards with 20k1 or 20k2 chips, say Y here.
To compile this driver as a module, choose M here: the module
will be called snd-ctxfi.
config SND_DARLA20
tristate "(Echoaudio) Darla20"
select FW_LOADER
......
......@@ -59,6 +59,7 @@ obj-$(CONFIG_SND) += \
ali5451/ \
au88x0/ \
aw2/ \
ctxfi/ \
ca0106/ \
cs46xx/ \
cs5535audio/ \
......
snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \
ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \
cthw20k2.o cthw20k1.o
obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o
此差异已折叠。
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*/
#ifndef _20K2REGISTERS_H_
#define _20K2REGISTERS_H_
/* Timer Registers */
#define TIMER_TIMR 0x1B7004
#define INTERRUPT_GIP 0x1B7010
#define INTERRUPT_GIE 0x1B7014
/* I2C Registers */
#define I2C_IF_ADDRESS 0x1B9000
#define I2C_IF_WDATA 0x1B9004
#define I2C_IF_RDATA 0x1B9008
#define I2C_IF_STATUS 0x1B900C
#define I2C_IF_WLOCK 0x1B9010
/* Global Control Registers */
#define GLOBAL_CNTL_GCTL 0x1B7090
/* PLL Registers */
#define PLL_CTL 0x1B7080
#define PLL_STAT 0x1B7084
#define PLL_ENB 0x1B7088
/* SRC Registers */
#define SRC_CTL 0x1A0000 /* 0x1A0000 + (256 * Chn) */
#define SRC_CCR 0x1A0004 /* 0x1A0004 + (256 * Chn) */
#define SRC_IMAP 0x1A0008 /* 0x1A0008 + (256 * Chn) */
#define SRC_CA 0x1A0010 /* 0x1A0010 + (256 * Chn) */
#define SRC_CF 0x1A0014 /* 0x1A0014 + (256 * Chn) */
#define SRC_SA 0x1A0018 /* 0x1A0018 + (256 * Chn) */
#define SRC_LA 0x1A001C /* 0x1A001C + (256 * Chn) */
#define SRC_CTLSWR 0x1A0020 /* 0x1A0020 + (256 * Chn) */
#define SRC_CD 0x1A0080 /* 0x1A0080 + (256 * Chn) + (4 * Regn) */
#define SRC_MCTL 0x1A012C
#define SRC_IP 0x1A102C /* 0x1A102C + (256 * Regn) */
#define SRC_ENB 0x1A282C /* 0x1A282C + (256 * Regn) */
#define SRC_ENBSTAT 0x1A202C
#define SRC_ENBSA 0x1A232C
#define SRC_DN0Z 0x1A0030
#define SRC_DN1Z 0x1A0040
#define SRC_UPZ 0x1A0060
/* GPIO Registers */
#define GPIO_DATA 0x1B7020
#define GPIO_CTRL 0x1B7024
/* Virtual memory registers */
#define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */
#define VMEM_PTPAH 0x1C6304 /* 0x1C6304 + (16 * Chn) */
#define VMEM_CTL 0x1C7000
/* Transport Registers */
#define TRANSPORT_ENB 0x1B6000
#define TRANSPORT_CTL 0x1B6004
#define TRANSPORT_INT 0x1B6008
/* Audio IO */
#define AUDIO_IO_AIM 0x1B5000 /* 0x1B5000 + (0x04 * Chn) */
#define AUDIO_IO_TX_CTL 0x1B5400 /* 0x1B5400 + (0x40 * Chn) */
#define AUDIO_IO_TX_CSTAT_L 0x1B5408 /* 0x1B5408 + (0x40 * Chn) */
#define AUDIO_IO_TX_CSTAT_H 0x1B540C /* 0x1B540C + (0x40 * Chn) */
#define AUDIO_IO_RX_CTL 0x1B5410 /* 0x1B5410 + (0x40 * Chn) */
#define AUDIO_IO_RX_SRT_CTL 0x1B5420 /* 0x1B5420 + (0x40 * Chn) */
#define AUDIO_IO_MCLK 0x1B5600
#define AUDIO_IO_TX_BLRCLK 0x1B5604
#define AUDIO_IO_RX_BLRCLK 0x1B5608
/* Mixer */
#define MIXER_AMOPLO 0x130000 /* 0x130000 + (8 * Chn) [4095 : 0] */
#define MIXER_AMOPHI 0x130004 /* 0x130004 + (8 * Chn) [4095 : 0] */
#define MIXER_PRING_LO_HI 0x188000 /* 0x188000 + (4 * Chn) [4095 : 0] */
#define MIXER_PMOPLO 0x138000 /* 0x138000 + (8 * Chn) [4095 : 0] */
#define MIXER_PMOPHI 0x138004 /* 0x138004 + (8 * Chn) [4095 : 0] */
#define MIXER_AR_ENABLE 0x19000C
#endif
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctamixer.c
*
* @Brief
* This file contains the implementation of the Audio Mixer
* resource management object.
*
* @Author Liu Chun
* @Date May 21 2008
*
*/
#include "ctamixer.h"
#include "cthardware.h"
#include <linux/slab.h>
#define AMIXER_RESOURCE_NUM 256
#define SUM_RESOURCE_NUM 256
#define AMIXER_Y_IMMEDIATE 1
#define BLANK_SLOT 4094
static int amixer_master(struct rsc *rsc)
{
rsc->conj = 0;
return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
}
static int amixer_next_conj(struct rsc *rsc)
{
rsc->conj++;
return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
}
static int amixer_index(const struct rsc *rsc)
{
return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
}
static int amixer_output_slot(const struct rsc *rsc)
{
return (amixer_index(rsc) << 4) + 0x4;
}
static struct rsc_ops amixer_basic_rsc_ops = {
.master = amixer_master,
.next_conj = amixer_next_conj,
.index = amixer_index,
.output_slot = amixer_output_slot,
};
static int amixer_set_input(struct amixer *amixer, struct rsc *rsc)
{
struct hw *hw;
hw = amixer->rsc.hw;
hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
amixer->input = rsc;
if (NULL == rsc)
hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
else
hw->amixer_set_x(amixer->rsc.ctrl_blk,
rsc->ops->output_slot(rsc));
return 0;
}
/* y is a 14-bit immediate constant */
static int amixer_set_y(struct amixer *amixer, unsigned int y)
{
struct hw *hw;
hw = amixer->rsc.hw;
hw->amixer_set_y(amixer->rsc.ctrl_blk, y);
return 0;
}
static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv)
{
struct hw *hw;
hw = amixer->rsc.hw;
hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv);
return 0;
}
static int amixer_set_sum(struct amixer *amixer, struct sum *sum)
{
struct hw *hw;
hw = amixer->rsc.hw;
amixer->sum = sum;
if (NULL == sum) {
hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
} else {
hw->amixer_set_se(amixer->rsc.ctrl_blk, 1);
hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
sum->rsc.ops->index(&sum->rsc));
}
return 0;
}
static int amixer_commit_write(struct amixer *amixer)
{
struct hw *hw;
unsigned int index;
int i;
struct rsc *input;
struct sum *sum;
hw = amixer->rsc.hw;
input = amixer->input;
sum = amixer->sum;
/* Program master and conjugate resources */
amixer->rsc.ops->master(&amixer->rsc);
if (NULL != input)
input->ops->master(input);
if (NULL != sum)
sum->rsc.ops->master(&sum->rsc);
for (i = 0; i < amixer->rsc.msr; i++) {
hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
if (NULL != input) {
hw->amixer_set_x(amixer->rsc.ctrl_blk,
input->ops->output_slot(input));
input->ops->next_conj(input);
}
if (NULL != sum) {
hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
sum->rsc.ops->index(&sum->rsc));
sum->rsc.ops->next_conj(&sum->rsc);
}
index = amixer->rsc.ops->output_slot(&amixer->rsc);
hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
amixer->rsc.ops->next_conj(&amixer->rsc);
}
amixer->rsc.ops->master(&amixer->rsc);
if (NULL != input)
input->ops->master(input);
if (NULL != sum)
sum->rsc.ops->master(&sum->rsc);
return 0;
}
static int amixer_commit_raw_write(struct amixer *amixer)
{
struct hw *hw;
unsigned int index;
hw = amixer->rsc.hw;
index = amixer->rsc.ops->output_slot(&amixer->rsc);
hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
return 0;
}
static int amixer_get_y(struct amixer *amixer)
{
struct hw *hw;
hw = amixer->rsc.hw;
return hw->amixer_get_y(amixer->rsc.ctrl_blk);
}
static int amixer_setup(struct amixer *amixer, struct rsc *input,
unsigned int scale, struct sum *sum)
{
amixer_set_input(amixer, input);
amixer_set_y(amixer, scale);
amixer_set_sum(amixer, sum);
amixer_commit_write(amixer);
return 0;
}
static struct amixer_rsc_ops amixer_ops = {
.set_input = amixer_set_input,
.set_invalid_squash = amixer_set_invalid_squash,
.set_scale = amixer_set_y,
.set_sum = amixer_set_sum,
.commit_write = amixer_commit_write,
.commit_raw_write = amixer_commit_raw_write,
.setup = amixer_setup,
.get_scale = amixer_get_y,
};
static int amixer_rsc_init(struct amixer *amixer,
const struct amixer_desc *desc,
struct amixer_mgr *mgr)
{
int err;
err = rsc_init(&amixer->rsc, amixer->idx[0],
AMIXER, desc->msr, mgr->mgr.hw);
if (err)
return err;
/* Set amixer specific operations */
amixer->rsc.ops = &amixer_basic_rsc_ops;
amixer->ops = &amixer_ops;
amixer->input = NULL;
amixer->sum = NULL;
amixer_setup(amixer, NULL, 0, NULL);
return 0;
}
static int amixer_rsc_uninit(struct amixer *amixer)
{
amixer_setup(amixer, NULL, 0, NULL);
rsc_uninit(&amixer->rsc);
amixer->ops = NULL;
amixer->input = NULL;
amixer->sum = NULL;
return 0;
}
static int get_amixer_rsc(struct amixer_mgr *mgr,
const struct amixer_desc *desc,
struct amixer **ramixer)
{
int err, i;
unsigned int idx;
struct amixer *amixer;
unsigned long flags;
*ramixer = NULL;
/* Allocate mem for amixer resource */
amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
if (NULL == amixer) {
err = -ENOMEM;
return err;
}
/* Check whether there are sufficient
* amixer resources to meet request. */
spin_lock_irqsave(&mgr->mgr_lock, flags);
for (i = 0; i < desc->msr; i++) {
err = mgr_get_resource(&mgr->mgr, 1, &idx);
if (err)
break;
amixer->idx[i] = idx;
}
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
if (err) {
printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n");
goto error;
}
err = amixer_rsc_init(amixer, desc, mgr);
if (err)
goto error;
*ramixer = amixer;
return 0;
error:
spin_lock_irqsave(&mgr->mgr_lock, flags);
for (i--; i >= 0; i--)
mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
kfree(amixer);
return err;
}
static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
{
unsigned long flags;
int i;
spin_lock_irqsave(&mgr->mgr_lock, flags);
for (i = 0; i < amixer->rsc.msr; i++)
mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
amixer_rsc_uninit(amixer);
kfree(amixer);
return 0;
}
int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr)
{
int err;
struct amixer_mgr *amixer_mgr;
*ramixer_mgr = NULL;
amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
if (NULL == amixer_mgr)
return -ENOMEM;
err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
if (err)
goto error;
spin_lock_init(&amixer_mgr->mgr_lock);
amixer_mgr->get_amixer = get_amixer_rsc;
amixer_mgr->put_amixer = put_amixer_rsc;
*ramixer_mgr = amixer_mgr;
return 0;
error:
kfree(amixer_mgr);
return err;
}
int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
{
rsc_mgr_uninit(&amixer_mgr->mgr);
kfree(amixer_mgr);
return 0;
}
/* SUM resource management */
static int sum_master(struct rsc *rsc)
{
rsc->conj = 0;
return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
}
static int sum_next_conj(struct rsc *rsc)
{
rsc->conj++;
return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
}
static int sum_index(const struct rsc *rsc)
{
return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
}
static int sum_output_slot(const struct rsc *rsc)
{
return (sum_index(rsc) << 4) + 0xc;
}
static struct rsc_ops sum_basic_rsc_ops = {
.master = sum_master,
.next_conj = sum_next_conj,
.index = sum_index,
.output_slot = sum_output_slot,
};
static int sum_rsc_init(struct sum *sum,
const struct sum_desc *desc,
struct sum_mgr *mgr)
{
int err;
err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
if (err)
return err;
sum->rsc.ops = &sum_basic_rsc_ops;
return 0;
}
static int sum_rsc_uninit(struct sum *sum)
{
rsc_uninit(&sum->rsc);
return 0;
}
static int get_sum_rsc(struct sum_mgr *mgr,
const struct sum_desc *desc,
struct sum **rsum)
{
int err, i;
unsigned int idx;
struct sum *sum;
unsigned long flags;
*rsum = NULL;
/* Allocate mem for sum resource */
sum = kzalloc(sizeof(*sum), GFP_KERNEL);
if (NULL == sum) {
err = -ENOMEM;
return err;
}
/* Check whether there are sufficient sum resources to meet request. */
spin_lock_irqsave(&mgr->mgr_lock, flags);
for (i = 0; i < desc->msr; i++) {
err = mgr_get_resource(&mgr->mgr, 1, &idx);
if (err)
break;
sum->idx[i] = idx;
}
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
if (err) {
printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n");
goto error;
}
err = sum_rsc_init(sum, desc, mgr);
if (err)
goto error;
*rsum = sum;
return 0;
error:
spin_lock_irqsave(&mgr->mgr_lock, flags);
for (i--; i >= 0; i--)
mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
kfree(sum);
return err;
}
static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
{
unsigned long flags;
int i;
spin_lock_irqsave(&mgr->mgr_lock, flags);
for (i = 0; i < sum->rsc.msr; i++)
mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
sum_rsc_uninit(sum);
kfree(sum);
return 0;
}
int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr)
{
int err;
struct sum_mgr *sum_mgr;
*rsum_mgr = NULL;
sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
if (NULL == sum_mgr)
return -ENOMEM;
err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
if (err)
goto error;
spin_lock_init(&sum_mgr->mgr_lock);
sum_mgr->get_sum = get_sum_rsc;
sum_mgr->put_sum = put_sum_rsc;
*rsum_mgr = sum_mgr;
return 0;
error:
kfree(sum_mgr);
return err;
}
int sum_mgr_destroy(struct sum_mgr *sum_mgr)
{
rsc_mgr_uninit(&sum_mgr->mgr);
kfree(sum_mgr);
return 0;
}
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctamixer.h
*
* @Brief
* This file contains the definition of the Audio Mixer
* resource management object.
*
* @Author Liu Chun
* @Date May 21 2008
*
*/
#ifndef CTAMIXER_H
#define CTAMIXER_H
#include "ctresource.h"
#include <linux/spinlock.h>
/* Define the descriptor of a summation node resource */
struct sum {
struct rsc rsc; /* Basic resource info */
unsigned char idx[8];
};
/* Define sum resource request description info */
struct sum_desc {
unsigned int msr;
};
struct sum_mgr {
struct rsc_mgr mgr; /* Basic resource manager info */
spinlock_t mgr_lock;
/* request one sum resource */
int (*get_sum)(struct sum_mgr *mgr,
const struct sum_desc *desc, struct sum **rsum);
/* return one sum resource */
int (*put_sum)(struct sum_mgr *mgr, struct sum *sum);
};
/* Constructor and destructor of daio resource manager */
int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr);
int sum_mgr_destroy(struct sum_mgr *sum_mgr);
/* Define the descriptor of a amixer resource */
struct amixer_rsc_ops;
struct amixer {
struct rsc rsc; /* Basic resource info */
unsigned char idx[8];
struct rsc *input; /* pointer to a resource acting as source */
struct sum *sum; /* Put amixer output to this summation node */
struct amixer_rsc_ops *ops; /* AMixer specific operations */
};
struct amixer_rsc_ops {
int (*set_input)(struct amixer *amixer, struct rsc *rsc);
int (*set_scale)(struct amixer *amixer, unsigned int scale);
int (*set_invalid_squash)(struct amixer *amixer, unsigned int iv);
int (*set_sum)(struct amixer *amixer, struct sum *sum);
int (*commit_write)(struct amixer *amixer);
/* Only for interleaved recording */
int (*commit_raw_write)(struct amixer *amixer);
int (*setup)(struct amixer *amixer, struct rsc *input,
unsigned int scale, struct sum *sum);
int (*get_scale)(struct amixer *amixer);
};
/* Define amixer resource request description info */
struct amixer_desc {
unsigned int msr;
};
struct amixer_mgr {
struct rsc_mgr mgr; /* Basic resource manager info */
spinlock_t mgr_lock;
/* request one amixer resource */
int (*get_amixer)(struct amixer_mgr *mgr,
const struct amixer_desc *desc,
struct amixer **ramixer);
/* return one amixer resource */
int (*put_amixer)(struct amixer_mgr *mgr, struct amixer *amixer);
};
/* Constructor and destructor of amixer resource manager */
int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr);
int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr);
#endif /* CTAMIXER_H */
此差异已折叠。
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctatc.h
*
* @Brief
* This file contains the definition of the device resource management object.
*
* @Author Liu Chun
* @Date Mar 28 2008
*
*/
#ifndef CTATC_H
#define CTATC_H
#include <linux/types.h>
#include <linux/spinlock_types.h>
#include <linux/pci.h>
#include <linux/timer.h>
#include <sound/core.h>
#include "ctvmem.h"
#include "ctresource.h"
enum CTALSADEVS { /* Types of alsa devices */
FRONT,
SURROUND,
CLFE,
SIDE,
IEC958,
MIXER,
NUM_CTALSADEVS /* This should always be the last */
};
struct ct_atc_chip_sub_details {
u16 subsys;
const char *nm_model;
};
struct ct_atc_chip_details {
u16 vendor;
u16 device;
const struct ct_atc_chip_sub_details *sub_details;
const char *nm_card;
};
struct ct_atc;
struct ct_timer;
struct ct_timer_instance;
/* alsa pcm stream descriptor */
struct ct_atc_pcm {
struct snd_pcm_substream *substream;
void (*interrupt)(struct ct_atc_pcm *apcm);
struct ct_timer_instance *timer;
unsigned int started:1;
/* Only mono and interleaved modes are supported now. */
struct ct_vm_block *vm_block;
void *src; /* SRC for interacting with host memory */
void **srccs; /* SRCs for sample rate conversion */
void **srcimps; /* SRC Input Mappers */
void **amixers; /* AMIXERs for routing converted data */
void *mono; /* A SUM resource for mixing chs to one */
unsigned char n_srcc; /* Number of converting SRCs */
unsigned char n_srcimp; /* Number of SRC Input Mappers */
unsigned char n_amixer; /* Number of AMIXERs */
};
/* Chip resource management object */
struct ct_atc {
struct pci_dev *pci;
struct snd_card *card;
unsigned int rsr; /* reference sample rate in Hz */
unsigned int msr; /* master sample rate in rsr */
unsigned int pll_rate; /* current rate of Phase Lock Loop */
int chip_type;
int model;
const char *chip_name;
const char *model_name;
struct ct_vm *vm; /* device virtual memory manager for this card */
int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index);
spinlock_t atc_lock;
int (*pcm_playback_prepare)(struct ct_atc *atc,
struct ct_atc_pcm *apcm);
int (*pcm_playback_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
int (*pcm_playback_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
int (*pcm_playback_position)(struct ct_atc *atc,
struct ct_atc_pcm *apcm);
int (*spdif_passthru_playback_prepare)(struct ct_atc *atc,
struct ct_atc_pcm *apcm);
int (*pcm_capture_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
int (*pcm_capture_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
int (*pcm_capture_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
int (*pcm_capture_position)(struct ct_atc *atc,
struct ct_atc_pcm *apcm);
int (*pcm_release_resources)(struct ct_atc *atc,
struct ct_atc_pcm *apcm);
int (*select_line_in)(struct ct_atc *atc);
int (*select_mic_in)(struct ct_atc *atc);
int (*select_digit_io)(struct ct_atc *atc);
int (*line_front_unmute)(struct ct_atc *atc, unsigned char state);
int (*line_surround_unmute)(struct ct_atc *atc, unsigned char state);
int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state);
int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state);
int (*line_in_unmute)(struct ct_atc *atc, unsigned char state);
int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state);
int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state);
int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status);
int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status);
int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state);
int (*have_digit_io_switch)(struct ct_atc *atc);
/* Don't touch! Used for internal object. */
void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */
void *mixer; /* internal mixer object */
void *hw; /* chip specific hardware access object */
void **daios; /* digital audio io resources */
void **pcm; /* SUMs for collecting all pcm stream */
void **srcs; /* Sample Rate Converters for input signal */
void **srcimps; /* input mappers for SRCs */
unsigned char n_daio;
unsigned char n_src;
unsigned char n_srcimp;
unsigned char n_pcm;
struct ct_timer *timer;
};
int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
unsigned int rsr, unsigned int msr, int chip_type,
struct ct_atc **ratc);
int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc);
#endif /* CTATC_H */
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctdaio.c
*
* @Brief
* This file contains the implementation of Digital Audio Input Output
* resource management object.
*
* @Author Liu Chun
* @Date May 23 2008
*
*/
#include "ctdaio.h"
#include "cthardware.h"
#include "ctimap.h"
#include <linux/slab.h>
#include <linux/kernel.h>
#define DAIO_RESOURCE_NUM NUM_DAIOTYP
#define DAIO_OUT_MAX SPDIFOO
union daio_usage {
struct {
unsigned short lineo1:1;
unsigned short lineo2:1;
unsigned short lineo3:1;
unsigned short lineo4:1;
unsigned short spdifoo:1;
unsigned short lineim:1;
unsigned short spdifio:1;
unsigned short spdifi1:1;
} bf;
unsigned short data;
};
struct daio_rsc_idx {
unsigned short left;
unsigned short right;
};
struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = {
[LINEO1] = {.left = 0x00, .right = 0x01},
[LINEO2] = {.left = 0x18, .right = 0x19},
[LINEO3] = {.left = 0x08, .right = 0x09},
[LINEO4] = {.left = 0x10, .right = 0x11},
[LINEIM] = {.left = 0x1b5, .right = 0x1bd},
[SPDIFOO] = {.left = 0x20, .right = 0x21},
[SPDIFIO] = {.left = 0x15, .right = 0x1d},
[SPDIFI1] = {.left = 0x95, .right = 0x9d},
};
struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
[LINEO1] = {.left = 0x40, .right = 0x41},
[LINEO2] = {.left = 0x70, .right = 0x71},
[LINEO3] = {.left = 0x50, .right = 0x51},
[LINEO4] = {.left = 0x60, .right = 0x61},
[LINEIM] = {.left = 0x45, .right = 0xc5},
[SPDIFOO] = {.left = 0x00, .right = 0x01},
[SPDIFIO] = {.left = 0x05, .right = 0x85},
};
static int daio_master(struct rsc *rsc)
{
/* Actually, this is not the resource index of DAIO.
* For DAO, it is the input mapper index. And, for DAI,
* it is the output time-slot index. */
return rsc->conj = rsc->idx;
}
static int daio_index(const struct rsc *rsc)
{
return rsc->conj;
}
static int daio_out_next_conj(struct rsc *rsc)
{
return rsc->conj += 2;
}
static int daio_in_next_conj_20k1(struct rsc *rsc)
{
return rsc->conj += 0x200;
}
static int daio_in_next_conj_20k2(struct rsc *rsc)
{
return rsc->conj += 0x100;
}
static struct rsc_ops daio_out_rsc_ops = {
.master = daio_master,
.next_conj = daio_out_next_conj,
.index = daio_index,
.output_slot = NULL,
};
static struct rsc_ops daio_in_rsc_ops_20k1 = {
.master = daio_master,
.next_conj = daio_in_next_conj_20k1,
.index = NULL,
.output_slot = daio_index,
};
static struct rsc_ops daio_in_rsc_ops_20k2 = {
.master = daio_master,
.next_conj = daio_in_next_conj_20k2,
.index = NULL,
.output_slot = daio_index,
};
static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
{
switch (hw->chip_type) {
case ATC20K1:
switch (type) {
case SPDIFOO: return 0;
case SPDIFIO: return 0;
case SPDIFI1: return 1;
case LINEO1: return 4;
case LINEO2: return 7;
case LINEO3: return 5;
case LINEO4: return 6;
case LINEIM: return 7;
default: return -EINVAL;
}
case ATC20K2:
switch (type) {
case SPDIFOO: return 0;
case SPDIFIO: return 0;
case LINEO1: return 4;
case LINEO2: return 7;
case LINEO3: return 5;
case LINEO4: return 6;
case LINEIM: return 4;
default: return -EINVAL;
}
default:
return -EINVAL;
}
}
static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc);
static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos)
{
((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos);
return 0;
}
static int dao_spdif_set_spos(struct dao *dao, unsigned int spos)
{
((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos);
return 0;
}
static int dao_commit_write(struct dao *dao)
{
((struct hw *)dao->hw)->dao_commit_write(dao->hw,
daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk);
return 0;
}
static int dao_set_left_input(struct dao *dao, struct rsc *input)
{
struct imapper *entry;
struct daio *daio = &dao->daio;
int i;
entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL);
if (NULL == entry)
return -ENOMEM;
/* Program master and conjugate resources */
input->ops->master(input);
daio->rscl.ops->master(&daio->rscl);
for (i = 0; i < daio->rscl.msr; i++, entry++) {
entry->slot = input->ops->output_slot(input);
entry->user = entry->addr = daio->rscl.ops->index(&daio->rscl);
dao->mgr->imap_add(dao->mgr, entry);
dao->imappers[i] = entry;
input->ops->next_conj(input);
daio->rscl.ops->next_conj(&daio->rscl);
}
input->ops->master(input);
daio->rscl.ops->master(&daio->rscl);
return 0;
}
static int dao_set_right_input(struct dao *dao, struct rsc *input)
{
struct imapper *entry;
struct daio *daio = &dao->daio;
int i;
entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL);
if (NULL == entry)
return -ENOMEM;
/* Program master and conjugate resources */
input->ops->master(input);
daio->rscr.ops->master(&daio->rscr);
for (i = 0; i < daio->rscr.msr; i++, entry++) {
entry->slot = input->ops->output_slot(input);
entry->user = entry->addr = daio->rscr.ops->index(&daio->rscr);
dao->mgr->imap_add(dao->mgr, entry);
dao->imappers[daio->rscl.msr + i] = entry;
input->ops->next_conj(input);
daio->rscr.ops->next_conj(&daio->rscr);
}
input->ops->master(input);
daio->rscr.ops->master(&daio->rscr);
return 0;
}
static int dao_clear_left_input(struct dao *dao)
{
struct imapper *entry;
struct daio *daio = &dao->daio;
int i;
if (NULL == dao->imappers[0])
return 0;
entry = dao->imappers[0];
dao->mgr->imap_delete(dao->mgr, entry);
/* Program conjugate resources */
for (i = 1; i < daio->rscl.msr; i++) {
entry = dao->imappers[i];
dao->mgr->imap_delete(dao->mgr, entry);
dao->imappers[i] = NULL;
}
kfree(dao->imappers[0]);
dao->imappers[0] = NULL;
return 0;
}
static int dao_clear_right_input(struct dao *dao)
{
struct imapper *entry;
struct daio *daio = &dao->daio;
int i;
if (NULL == dao->imappers[daio->rscl.msr])
return 0;
entry = dao->imappers[daio->rscl.msr];
dao->mgr->imap_delete(dao->mgr, entry);
/* Program conjugate resources */
for (i = 1; i < daio->rscr.msr; i++) {
entry = dao->imappers[daio->rscl.msr + i];
dao->mgr->imap_delete(dao->mgr, entry);
dao->imappers[daio->rscl.msr + i] = NULL;
}
kfree(dao->imappers[daio->rscl.msr]);
dao->imappers[daio->rscl.msr] = NULL;
return 0;
}
static struct dao_rsc_ops dao_ops = {
.set_spos = dao_spdif_set_spos,
.commit_write = dao_commit_write,
.get_spos = dao_spdif_get_spos,
.reinit = dao_rsc_reinit,
.set_left_input = dao_set_left_input,
.set_right_input = dao_set_right_input,
.clear_left_input = dao_clear_left_input,
.clear_right_input = dao_clear_right_input,
};
static int dai_set_srt_srcl(struct dai *dai, struct rsc *src)
{
src->ops->master(src);
((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk,
src->ops->index(src));
return 0;
}
static int dai_set_srt_srcr(struct dai *dai, struct rsc *src)
{
src->ops->master(src);
((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk,
src->ops->index(src));
return 0;
}
static int dai_set_srt_msr(struct dai *dai, unsigned int msr)
{
unsigned int rsr;
for (rsr = 0; msr > 1; msr >>= 1)
rsr++;
((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr);
return 0;
}
static int dai_set_enb_src(struct dai *dai, unsigned int enb)
{
((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb);
return 0;
}
static int dai_set_enb_srt(struct dai *dai, unsigned int enb)
{
((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb);
return 0;
}
static int dai_commit_write(struct dai *dai)
{
((struct hw *)dai->hw)->dai_commit_write(dai->hw,
daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
return 0;
}
static struct dai_rsc_ops dai_ops = {
.set_srt_srcl = dai_set_srt_srcl,
.set_srt_srcr = dai_set_srt_srcr,
.set_srt_msr = dai_set_srt_msr,
.set_enb_src = dai_set_enb_src,
.set_enb_srt = dai_set_enb_srt,
.commit_write = dai_commit_write,
};
static int daio_rsc_init(struct daio *daio,
const struct daio_desc *desc,
void *hw)
{
int err;
unsigned int idx_l, idx_r;
switch (((struct hw *)hw)->chip_type) {
case ATC20K1:
idx_l = idx_20k1[desc->type].left;
idx_r = idx_20k1[desc->type].right;
break;
case ATC20K2:
idx_l = idx_20k2[desc->type].left;
idx_r = idx_20k2[desc->type].right;
break;
default:
return -EINVAL;
}
err = rsc_init(&daio->rscl, idx_l, DAIO, desc->msr, hw);
if (err)
return err;
err = rsc_init(&daio->rscr, idx_r, DAIO, desc->msr, hw);
if (err)
goto error1;
/* Set daio->rscl/r->ops to daio specific ones */
if (desc->type <= DAIO_OUT_MAX) {
daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
} else {
switch (((struct hw *)hw)->chip_type) {
case ATC20K1:
daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1;
break;
case ATC20K2:
daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k2;
break;
default:
break;
}
}
daio->type = desc->type;
return 0;
error1:
rsc_uninit(&daio->rscl);
return err;
}
static int daio_rsc_uninit(struct daio *daio)
{
rsc_uninit(&daio->rscl);
rsc_uninit(&daio->rscr);
return 0;
}
static int dao_rsc_init(struct dao *dao,
const struct daio_desc *desc,
struct daio_mgr *mgr)
{
struct hw *hw = mgr->mgr.hw;
unsigned int conf;
int err;
err = daio_rsc_init(&dao->daio, desc, mgr->mgr.hw);
if (err)
return err;
dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL);
if (NULL == dao->imappers) {
err = -ENOMEM;
goto error1;
}
dao->ops = &dao_ops;
dao->mgr = mgr;
dao->hw = hw;
err = hw->dao_get_ctrl_blk(&dao->ctrl_blk);
if (err)
goto error2;
hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
daio_device_index(dao->daio.type, hw));
hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
conf = (desc->msr & 0x7) | (desc->passthru << 3);
hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk,
daio_device_index(dao->daio.type, hw), conf);
hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
daio_device_index(dao->daio.type, hw));
hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
return 0;
error2:
kfree(dao->imappers);
dao->imappers = NULL;
error1:
daio_rsc_uninit(&dao->daio);
return err;
}
static int dao_rsc_uninit(struct dao *dao)
{
if (NULL != dao->imappers) {
if (NULL != dao->imappers[0])
dao_clear_left_input(dao);
if (NULL != dao->imappers[dao->daio.rscl.msr])
dao_clear_right_input(dao);
kfree(dao->imappers);
dao->imappers = NULL;
}
((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk);
dao->hw = dao->ctrl_blk = NULL;
daio_rsc_uninit(&dao->daio);
return 0;
}
static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc)
{
struct daio_mgr *mgr = dao->mgr;
struct daio_desc dsc = {0};
dsc.type = dao->daio.type;
dsc.msr = desc->msr;
dsc.passthru = desc->passthru;
dao_rsc_uninit(dao);
return dao_rsc_init(dao, &dsc, mgr);
}
static int dai_rsc_init(struct dai *dai,
const struct daio_desc *desc,
struct daio_mgr *mgr)
{
int err;
struct hw *hw = mgr->mgr.hw;
unsigned int rsr, msr;
err = daio_rsc_init(&dai->daio, desc, mgr->mgr.hw);
if (err)
return err;
dai->ops = &dai_ops;
dai->hw = mgr->mgr.hw;
err = hw->dai_get_ctrl_blk(&dai->ctrl_blk);
if (err)
goto error1;
for (rsr = 0, msr = desc->msr; msr > 1; msr >>= 1)
rsr++;
hw->dai_srt_set_rsr(dai->ctrl_blk, rsr);
hw->dai_srt_set_drat(dai->ctrl_blk, 0);
/* default to disabling control of a SRC */
hw->dai_srt_set_ec(dai->ctrl_blk, 0);
hw->dai_srt_set_et(dai->ctrl_blk, 0); /* default to disabling SRT */
hw->dai_commit_write(hw,
daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk);
return 0;
error1:
daio_rsc_uninit(&dai->daio);
return err;
}
static int dai_rsc_uninit(struct dai *dai)
{
((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk);
dai->hw = dai->ctrl_blk = NULL;
daio_rsc_uninit(&dai->daio);
return 0;
}
static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
{
if (((union daio_usage *)mgr->rscs)->data & (0x1 << type))
return -ENOENT;
((union daio_usage *)mgr->rscs)->data |= (0x1 << type);
return 0;
}
static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type)
{
((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type);
return 0;
}
static int get_daio_rsc(struct daio_mgr *mgr,
const struct daio_desc *desc,
struct daio **rdaio)
{
int err;
struct dai *dai = NULL;
struct dao *dao = NULL;
unsigned long flags;
*rdaio = NULL;
/* Check whether there are sufficient daio resources to meet request. */
spin_lock_irqsave(&mgr->mgr_lock, flags);
err = daio_mgr_get_rsc(&mgr->mgr, desc->type);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
if (err) {
printk(KERN_ERR "Can't meet DAIO resource request!\n");
return err;
}
/* Allocate mem for daio resource */
if (desc->type <= DAIO_OUT_MAX) {
dao = kzalloc(sizeof(*dao), GFP_KERNEL);
if (NULL == dao) {
err = -ENOMEM;
goto error;
}
err = dao_rsc_init(dao, desc, mgr);
if (err)
goto error;
*rdaio = &dao->daio;
} else {
dai = kzalloc(sizeof(*dai), GFP_KERNEL);
if (NULL == dai) {
err = -ENOMEM;
goto error;
}
err = dai_rsc_init(dai, desc, mgr);
if (err)
goto error;
*rdaio = &dai->daio;
}
mgr->daio_enable(mgr, *rdaio);
mgr->commit_write(mgr);
return 0;
error:
if (NULL != dao)
kfree(dao);
else if (NULL != dai)
kfree(dai);
spin_lock_irqsave(&mgr->mgr_lock, flags);
daio_mgr_put_rsc(&mgr->mgr, desc->type);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
return err;
}
static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio)
{
unsigned long flags;
mgr->daio_disable(mgr, daio);
mgr->commit_write(mgr);
spin_lock_irqsave(&mgr->mgr_lock, flags);
daio_mgr_put_rsc(&mgr->mgr, daio->type);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
if (daio->type <= DAIO_OUT_MAX) {
dao_rsc_uninit(container_of(daio, struct dao, daio));
kfree(container_of(daio, struct dao, daio));
} else {
dai_rsc_uninit(container_of(daio, struct dai, daio));
kfree(container_of(daio, struct dai, daio));
}
return 0;
}
static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
if (DAIO_OUT_MAX >= daio->type) {
hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
} else {
hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
}
return 0;
}
static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio)
{
struct hw *hw = mgr->mgr.hw;
if (DAIO_OUT_MAX >= daio->type) {
hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
} else {
hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk,
daio_device_index(daio->type, hw));
}
return 0;
}
static int daio_map_op(void *data, struct imapper *entry)
{
struct rsc_mgr *mgr = &((struct daio_mgr *)data)->mgr;
struct hw *hw = mgr->hw;
hw->daio_mgr_set_imaparc(mgr->ctrl_blk, entry->slot);
hw->daio_mgr_set_imapnxt(mgr->ctrl_blk, entry->next);
hw->daio_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr);
hw->daio_mgr_commit_write(mgr->hw, mgr->ctrl_blk);
return 0;
}
static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry)
{
unsigned long flags;
int err;
spin_lock_irqsave(&mgr->imap_lock, flags);
if ((0 == entry->addr) && (mgr->init_imap_added)) {
input_mapper_delete(&mgr->imappers, mgr->init_imap,
daio_map_op, mgr);
mgr->init_imap_added = 0;
}
err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr);
spin_unlock_irqrestore(&mgr->imap_lock, flags);
return err;
}
static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry)
{
unsigned long flags;
int err;
spin_lock_irqsave(&mgr->imap_lock, flags);
err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr);
if (list_empty(&mgr->imappers)) {
input_mapper_add(&mgr->imappers, mgr->init_imap,
daio_map_op, mgr);
mgr->init_imap_added = 1;
}
spin_unlock_irqrestore(&mgr->imap_lock, flags);
return err;
}
static int daio_mgr_commit_write(struct daio_mgr *mgr)
{
struct hw *hw = mgr->mgr.hw;
hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk);
return 0;
}
int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr)
{
int err, i;
struct daio_mgr *daio_mgr;
struct imapper *entry;
*rdaio_mgr = NULL;
daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL);
if (NULL == daio_mgr)
return -ENOMEM;
err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw);
if (err)
goto error1;
spin_lock_init(&daio_mgr->mgr_lock);
spin_lock_init(&daio_mgr->imap_lock);
INIT_LIST_HEAD(&daio_mgr->imappers);
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (NULL == entry) {
err = -ENOMEM;
goto error2;
}
entry->slot = entry->addr = entry->next = entry->user = 0;
list_add(&entry->list, &daio_mgr->imappers);
daio_mgr->init_imap = entry;
daio_mgr->init_imap_added = 1;
daio_mgr->get_daio = get_daio_rsc;
daio_mgr->put_daio = put_daio_rsc;
daio_mgr->daio_enable = daio_mgr_enb_daio;
daio_mgr->daio_disable = daio_mgr_dsb_daio;
daio_mgr->imap_add = daio_imap_add;
daio_mgr->imap_delete = daio_imap_delete;
daio_mgr->commit_write = daio_mgr_commit_write;
for (i = 0; i < 8; i++) {
((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i);
((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i);
}
((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk);
*rdaio_mgr = daio_mgr;
return 0;
error2:
rsc_mgr_uninit(&daio_mgr->mgr);
error1:
kfree(daio_mgr);
return err;
}
int daio_mgr_destroy(struct daio_mgr *daio_mgr)
{
unsigned long flags;
/* free daio input mapper list */
spin_lock_irqsave(&daio_mgr->imap_lock, flags);
free_input_mapper_list(&daio_mgr->imappers);
spin_unlock_irqrestore(&daio_mgr->imap_lock, flags);
rsc_mgr_uninit(&daio_mgr->mgr);
kfree(daio_mgr);
return 0;
}
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctdaio.h
*
* @Brief
* This file contains the definition of Digital Audio Input Output
* resource management object.
*
* @Author Liu Chun
* @Date May 23 2008
*
*/
#ifndef CTDAIO_H
#define CTDAIO_H
#include "ctresource.h"
#include "ctimap.h"
#include <linux/spinlock.h>
#include <linux/list.h>
/* Define the descriptor of a daio resource */
enum DAIOTYP {
LINEO1,
LINEO2,
LINEO3,
LINEO4,
SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */
LINEIM,
SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */
SPDIFI1, /* S/PDIF In on internal Drive Bay */
NUM_DAIOTYP
};
struct dao_rsc_ops;
struct dai_rsc_ops;
struct daio_mgr;
struct daio {
struct rsc rscl; /* Basic resource info for left TX/RX */
struct rsc rscr; /* Basic resource info for right TX/RX */
enum DAIOTYP type;
};
struct dao {
struct daio daio;
struct dao_rsc_ops *ops; /* DAO specific operations */
struct imapper **imappers;
struct daio_mgr *mgr;
void *hw;
void *ctrl_blk;
};
struct dai {
struct daio daio;
struct dai_rsc_ops *ops; /* DAI specific operations */
void *hw;
void *ctrl_blk;
};
struct dao_desc {
unsigned int msr:4;
unsigned int passthru:1;
};
struct dao_rsc_ops {
int (*set_spos)(struct dao *dao, unsigned int spos);
int (*commit_write)(struct dao *dao);
int (*get_spos)(struct dao *dao, unsigned int *spos);
int (*reinit)(struct dao *dao, const struct dao_desc *desc);
int (*set_left_input)(struct dao *dao, struct rsc *input);
int (*set_right_input)(struct dao *dao, struct rsc *input);
int (*clear_left_input)(struct dao *dao);
int (*clear_right_input)(struct dao *dao);
};
struct dai_rsc_ops {
int (*set_srt_srcl)(struct dai *dai, struct rsc *src);
int (*set_srt_srcr)(struct dai *dai, struct rsc *src);
int (*set_srt_msr)(struct dai *dai, unsigned int msr);
int (*set_enb_src)(struct dai *dai, unsigned int enb);
int (*set_enb_srt)(struct dai *dai, unsigned int enb);
int (*commit_write)(struct dai *dai);
};
/* Define daio resource request description info */
struct daio_desc {
unsigned int type:4;
unsigned int msr:4;
unsigned int passthru:1;
};
struct daio_mgr {
struct rsc_mgr mgr; /* Basic resource manager info */
spinlock_t mgr_lock;
spinlock_t imap_lock;
struct list_head imappers;
struct imapper *init_imap;
unsigned int init_imap_added;
/* request one daio resource */
int (*get_daio)(struct daio_mgr *mgr,
const struct daio_desc *desc, struct daio **rdaio);
/* return one daio resource */
int (*put_daio)(struct daio_mgr *mgr, struct daio *daio);
int (*daio_enable)(struct daio_mgr *mgr, struct daio *daio);
int (*daio_disable)(struct daio_mgr *mgr, struct daio *daio);
int (*imap_add)(struct daio_mgr *mgr, struct imapper *entry);
int (*imap_delete)(struct daio_mgr *mgr, struct imapper *entry);
int (*commit_write)(struct daio_mgr *mgr);
};
/* Constructor and destructor of daio resource manager */
int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr);
int daio_mgr_destroy(struct daio_mgr *daio_mgr);
#endif /* CTDAIO_H */
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File cthardware.c
*
* @Brief
* This file contains the implementation of hardware access methord.
*
* @Author Liu Chun
* @Date Jun 26 2008
*
*/
#include "cthardware.h"
#include "cthw20k1.h"
#include "cthw20k2.h"
#include <linux/bug.h>
int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
enum CTCARDS model, struct hw **rhw)
{
int err;
switch (chip_type) {
case ATC20K1:
err = create_20k1_hw_obj(rhw);
break;
case ATC20K2:
err = create_20k2_hw_obj(rhw);
break;
default:
err = -ENODEV;
break;
}
if (err)
return err;
(*rhw)->pci = pci;
(*rhw)->chip_type = chip_type;
(*rhw)->model = model;
return 0;
}
int destroy_hw_obj(struct hw *hw)
{
int err;
switch (hw->pci->device) {
case 0x0005: /* 20k1 device */
err = destroy_20k1_hw_obj(hw);
break;
case 0x000B: /* 20k2 device */
err = destroy_20k2_hw_obj(hw);
break;
default:
err = -ENODEV;
break;
}
return err;
}
unsigned int get_field(unsigned int data, unsigned int field)
{
int i;
BUG_ON(!field);
/* @field should always be greater than 0 */
for (i = 0; !(field & (1 << i)); )
i++;
return (data & field) >> i;
}
void set_field(unsigned int *data, unsigned int field, unsigned int value)
{
int i;
BUG_ON(!field);
/* @field should always be greater than 0 */
for (i = 0; !(field & (1 << i)); )
i++;
*data = (*data & (~field)) | ((value << i) & field);
}
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File cthardware.h
*
* @Brief
* This file contains the definition of hardware access methord.
*
* @Author Liu Chun
* @Date May 13 2008
*
*/
#ifndef CTHARDWARE_H
#define CTHARDWARE_H
#include <linux/types.h>
#include <linux/pci.h>
enum CHIPTYP {
ATC20K1,
ATC20K2,
ATCNONE
};
enum CTCARDS {
/* 20k1 models */
CTSB055X,
CTSB073X,
CTUAA,
CT20K1_UNKNOWN,
/* 20k2 models */
CTSB0760,
CTHENDRIX,
CTSB0880,
NUM_CTCARDS /* This should always be the last */
};
/* Type of input source for ADC */
enum ADCSRC{
ADC_MICIN,
ADC_LINEIN,
ADC_VIDEO,
ADC_AUX,
ADC_NONE /* Switch to digital input */
};
struct card_conf {
/* device virtual mem page table page physical addr
* (supporting one page table page now) */
unsigned long vm_pgt_phys;
unsigned int rsr; /* reference sample rate in Hzs*/
unsigned int msr; /* master sample rate in rsrs */
};
struct hw {
int (*card_init)(struct hw *hw, struct card_conf *info);
int (*card_stop)(struct hw *hw);
int (*pll_init)(struct hw *hw, unsigned int rsr);
int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
int (*have_digit_io_switch)(struct hw *hw);
/* SRC operations */
int (*src_rsc_get_ctrl_blk)(void **rblk);
int (*src_rsc_put_ctrl_blk)(void *blk);
int (*src_set_state)(void *blk, unsigned int state);
int (*src_set_bm)(void *blk, unsigned int bm);
int (*src_set_rsr)(void *blk, unsigned int rsr);
int (*src_set_sf)(void *blk, unsigned int sf);
int (*src_set_wr)(void *blk, unsigned int wr);
int (*src_set_pm)(void *blk, unsigned int pm);
int (*src_set_rom)(void *blk, unsigned int rom);
int (*src_set_vo)(void *blk, unsigned int vo);
int (*src_set_st)(void *blk, unsigned int st);
int (*src_set_ie)(void *blk, unsigned int ie);
int (*src_set_ilsz)(void *blk, unsigned int ilsz);
int (*src_set_bp)(void *blk, unsigned int bp);
int (*src_set_cisz)(void *blk, unsigned int cisz);
int (*src_set_ca)(void *blk, unsigned int ca);
int (*src_set_sa)(void *blk, unsigned int sa);
int (*src_set_la)(void *blk, unsigned int la);
int (*src_set_pitch)(void *blk, unsigned int pitch);
int (*src_set_clear_zbufs)(void *blk, unsigned int clear);
int (*src_set_dirty)(void *blk, unsigned int flags);
int (*src_set_dirty_all)(void *blk);
int (*src_commit_write)(struct hw *hw, unsigned int idx, void *blk);
int (*src_get_ca)(struct hw *hw, unsigned int idx, void *blk);
unsigned int (*src_get_dirty)(void *blk);
unsigned int (*src_dirty_conj_mask)(void);
int (*src_mgr_get_ctrl_blk)(void **rblk);
int (*src_mgr_put_ctrl_blk)(void *blk);
/* syncly enable src @idx */
int (*src_mgr_enbs_src)(void *blk, unsigned int idx);
/* enable src @idx */
int (*src_mgr_enb_src)(void *blk, unsigned int idx);
/* disable src @idx */
int (*src_mgr_dsb_src)(void *blk, unsigned int idx);
int (*src_mgr_commit_write)(struct hw *hw, void *blk);
/* SRC Input Mapper operations */
int (*srcimp_mgr_get_ctrl_blk)(void **rblk);
int (*srcimp_mgr_put_ctrl_blk)(void *blk);
int (*srcimp_mgr_set_imaparc)(void *blk, unsigned int slot);
int (*srcimp_mgr_set_imapuser)(void *blk, unsigned int user);
int (*srcimp_mgr_set_imapnxt)(void *blk, unsigned int next);
int (*srcimp_mgr_set_imapaddr)(void *blk, unsigned int addr);
int (*srcimp_mgr_commit_write)(struct hw *hw, void *blk);
/* AMIXER operations */
int (*amixer_rsc_get_ctrl_blk)(void **rblk);
int (*amixer_rsc_put_ctrl_blk)(void *blk);
int (*amixer_mgr_get_ctrl_blk)(void **rblk);
int (*amixer_mgr_put_ctrl_blk)(void *blk);
int (*amixer_set_mode)(void *blk, unsigned int mode);
int (*amixer_set_iv)(void *blk, unsigned int iv);
int (*amixer_set_x)(void *blk, unsigned int x);
int (*amixer_set_y)(void *blk, unsigned int y);
int (*amixer_set_sadr)(void *blk, unsigned int sadr);
int (*amixer_set_se)(void *blk, unsigned int se);
int (*amixer_set_dirty)(void *blk, unsigned int flags);
int (*amixer_set_dirty_all)(void *blk);
int (*amixer_commit_write)(struct hw *hw, unsigned int idx, void *blk);
int (*amixer_get_y)(void *blk);
unsigned int (*amixer_get_dirty)(void *blk);
/* DAIO operations */
int (*dai_get_ctrl_blk)(void **rblk);
int (*dai_put_ctrl_blk)(void *blk);
int (*dai_srt_set_srco)(void *blk, unsigned int src);
int (*dai_srt_set_srcm)(void *blk, unsigned int src);
int (*dai_srt_set_rsr)(void *blk, unsigned int rsr);
int (*dai_srt_set_drat)(void *blk, unsigned int drat);
int (*dai_srt_set_ec)(void *blk, unsigned int ec);
int (*dai_srt_set_et)(void *blk, unsigned int et);
int (*dai_commit_write)(struct hw *hw, unsigned int idx, void *blk);
int (*dao_get_ctrl_blk)(void **rblk);
int (*dao_put_ctrl_blk)(void *blk);
int (*dao_set_spos)(void *blk, unsigned int spos);
int (*dao_commit_write)(struct hw *hw, unsigned int idx, void *blk);
int (*dao_get_spos)(void *blk, unsigned int *spos);
int (*daio_mgr_get_ctrl_blk)(struct hw *hw, void **rblk);
int (*daio_mgr_put_ctrl_blk)(void *blk);
int (*daio_mgr_enb_dai)(void *blk, unsigned int idx);
int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx);
int (*daio_mgr_enb_dao)(void *blk, unsigned int idx);
int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx);
int (*daio_mgr_dao_init)(void *blk, unsigned int idx,
unsigned int conf);
int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot);
int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next);
int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr);
int (*daio_mgr_commit_write)(struct hw *hw, void *blk);
int (*set_timer_irq)(struct hw *hw, int enable);
int (*set_timer_tick)(struct hw *hw, unsigned int tick);
unsigned int (*get_wc)(struct hw *hw);
void (*irq_callback)(void *data, unsigned int bit);
void *irq_callback_data;
struct pci_dev *pci; /* the pci kernel structure of this card */
int irq;
unsigned long io_base;
unsigned long mem_base;
enum CHIPTYP chip_type;
enum CTCARDS model;
};
int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
enum CTCARDS model, struct hw **rhw);
int destroy_hw_obj(struct hw *hw);
unsigned int get_field(unsigned int data, unsigned int field);
void set_field(unsigned int *data, unsigned int field, unsigned int value);
/* IRQ bits */
#define PLL_INT (1 << 10) /* PLL input-clock out-of-range */
#define FI_INT (1 << 9) /* forced interrupt */
#define IT_INT (1 << 8) /* timer interrupt */
#define PCI_INT (1 << 7) /* PCI bus error pending */
#define URT_INT (1 << 6) /* UART Tx/Rx */
#define GPI_INT (1 << 5) /* GPI pin */
#define MIX_INT (1 << 4) /* mixer parameter segment FIFO channels */
#define DAI_INT (1 << 3) /* DAI (SR-tracker or SPDIF-receiver) */
#define TP_INT (1 << 2) /* transport priority queue */
#define DSP_INT (1 << 1) /* DSP */
#define SRC_INT (1 << 0) /* SRC channels */
#endif /* CTHARDWARE_H */
此差异已折叠。
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File cthw20k1.h
*
* @Brief
* This file contains the definition of hardware access methord.
*
* @Author Liu Chun
* @Date May 13 2008
*
*/
#ifndef CTHW20K1_H
#define CTHW20K1_H
#include "cthardware.h"
int create_20k1_hw_obj(struct hw **rhw);
int destroy_20k1_hw_obj(struct hw *hw);
#endif /* CTHW20K1_H */
此差异已折叠。
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File cthw20k2.h
*
* @Brief
* This file contains the definition of hardware access methord.
*
* @Author Liu Chun
* @Date May 13 2008
*
*/
#ifndef CTHW20K2_H
#define CTHW20K2_H
#include "cthardware.h"
int create_20k2_hw_obj(struct hw **rhw);
int destroy_20k2_hw_obj(struct hw *hw);
#endif /* CTHW20K2_H */
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctimap.c
*
* @Brief
* This file contains the implementation of generic input mapper operations
* for input mapper management.
*
* @Author Liu Chun
* @Date May 23 2008
*
*/
#include "ctimap.h"
#include <linux/slab.h>
int input_mapper_add(struct list_head *mappers, struct imapper *entry,
int (*map_op)(void *, struct imapper *), void *data)
{
struct list_head *pos, *pre, *head;
struct imapper *pre_ent, *pos_ent;
head = mappers;
if (list_empty(head)) {
entry->next = entry->addr;
map_op(data, entry);
list_add(&entry->list, head);
return 0;
}
list_for_each(pos, head) {
pos_ent = list_entry(pos, struct imapper, list);
if (pos_ent->slot > entry->slot) {
/* found a position in list */
break;
}
}
if (pos != head) {
pre = pos->prev;
if (pre == head)
pre = head->prev;
__list_add(&entry->list, pos->prev, pos);
} else {
pre = head->prev;
pos = head->next;
list_add_tail(&entry->list, head);
}
pre_ent = list_entry(pre, struct imapper, list);
pos_ent = list_entry(pos, struct imapper, list);
entry->next = pos_ent->addr;
map_op(data, entry);
pre_ent->next = entry->addr;
map_op(data, pre_ent);
return 0;
}
int input_mapper_delete(struct list_head *mappers, struct imapper *entry,
int (*map_op)(void *, struct imapper *), void *data)
{
struct list_head *next, *pre, *head;
struct imapper *pre_ent, *next_ent;
head = mappers;
if (list_empty(head))
return 0;
pre = (entry->list.prev == head) ? head->prev : entry->list.prev;
next = (entry->list.next == head) ? head->next : entry->list.next;
if (pre == &entry->list) {
/* entry is the only one node in mappers list */
entry->next = entry->addr = entry->user = entry->slot = 0;
map_op(data, entry);
list_del(&entry->list);
return 0;
}
pre_ent = list_entry(pre, struct imapper, list);
next_ent = list_entry(next, struct imapper, list);
pre_ent->next = next_ent->addr;
map_op(data, pre_ent);
list_del(&entry->list);
return 0;
}
void free_input_mapper_list(struct list_head *head)
{
struct imapper *entry;
struct list_head *pos;
while (!list_empty(head)) {
pos = head->next;
list_del(pos);
entry = list_entry(pos, struct imapper, list);
kfree(entry);
}
}
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctimap.h
*
* @Brief
* This file contains the definition of generic input mapper operations
* for input mapper management.
*
* @Author Liu Chun
* @Date May 23 2008
*
*/
#ifndef CTIMAP_H
#define CTIMAP_H
#include <linux/list.h>
struct imapper {
unsigned short slot; /* the id of the slot containing input data */
unsigned short user; /* the id of the user resource consuming data */
unsigned short addr; /* the input mapper ram id */
unsigned short next; /* the next input mapper ram id */
struct list_head list;
};
int input_mapper_add(struct list_head *mappers, struct imapper *entry,
int (*map_op)(void *, struct imapper *), void *data);
int input_mapper_delete(struct list_head *mappers, struct imapper *entry,
int (*map_op)(void *, struct imapper *), void *data);
void free_input_mapper_list(struct list_head *mappers);
#endif /* CTIMAP_H */
此差异已折叠。
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctmixer.h
*
* @Brief
* This file contains the definition of the mixer device functions.
*
* @Author Liu Chun
* @Date Mar 28 2008
*
*/
#ifndef CTMIXER_H
#define CTMIXER_H
#include "ctatc.h"
#include "ctresource.h"
#define INIT_VOL 0x1c00
enum MIXER_PORT_T {
MIX_WAVE_FRONT,
MIX_WAVE_REAR,
MIX_WAVE_CENTLFE,
MIX_WAVE_SURROUND,
MIX_SPDIF_OUT,
MIX_PCMO_FRONT,
MIX_MIC_IN,
MIX_LINE_IN,
MIX_SPDIF_IN,
MIX_PCMI_FRONT,
MIX_PCMI_REAR,
MIX_PCMI_CENTLFE,
MIX_PCMI_SURROUND,
NUM_MIX_PORTS
};
/* alsa mixer descriptor */
struct ct_mixer {
struct ct_atc *atc;
void **amixers; /* amixer resources for volume control */
void **sums; /* sum resources for signal collection */
unsigned int switch_state; /* A bit-map to indicate state of switches */
int (*get_output_ports)(struct ct_mixer *mixer, enum MIXER_PORT_T type,
struct rsc **rleft, struct rsc **rright);
int (*set_input_left)(struct ct_mixer *mixer,
enum MIXER_PORT_T type, struct rsc *rsc);
int (*set_input_right)(struct ct_mixer *mixer,
enum MIXER_PORT_T type, struct rsc *rsc);
};
int ct_alsa_mix_create(struct ct_atc *atc,
enum CTALSADEVS device,
const char *device_name);
int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer);
int ct_mixer_destroy(struct ct_mixer *mixer);
#endif /* CTMIXER_H */
此差异已折叠。
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctpcm.h
*
* @Brief
* This file contains the definition of the pcm device functions.
*
* @Author Liu Chun
* @Date Mar 28 2008
*
*/
#ifndef CTPCM_H
#define CTPCM_H
#include "ctatc.h"
int ct_alsa_pcm_create(struct ct_atc *atc,
enum CTALSADEVS device,
const char *device_name);
#endif /* CTPCM_H */
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctresource.c
*
* @Brief
* This file contains the implementation of some generic helper functions.
*
* @Author Liu Chun
* @Date May 15 2008
*
*/
#include "ctresource.h"
#include "cthardware.h"
#include <linux/err.h>
#include <linux/slab.h>
#define AUDIO_SLOT_BLOCK_NUM 256
/* Resource allocation based on bit-map management mechanism */
static int
get_resource(u8 *rscs, unsigned int amount,
unsigned int multi, unsigned int *ridx)
{
int i, j, k, n;
/* Check whether there are sufficient resources to meet request. */
for (i = 0, n = multi; i < amount; i++) {
j = i / 8;
k = i % 8;
if (rscs[j] & ((u8)1 << k)) {
n = multi;
continue;
}
if (!(--n))
break; /* found sufficient contiguous resources */
}
if (i >= amount) {
/* Can not find sufficient contiguous resources */
return -ENOENT;
}
/* Mark the contiguous bits in resource bit-map as used */
for (n = multi; n > 0; n--) {
j = i / 8;
k = i % 8;
rscs[j] |= ((u8)1 << k);
i--;
}
*ridx = i + 1;
return 0;
}
static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx)
{
unsigned int i, j, k, n;
/* Mark the contiguous bits in resource bit-map as used */
for (n = multi, i = idx; n > 0; n--) {
j = i / 8;
k = i % 8;
rscs[j] &= ~((u8)1 << k);
i++;
}
return 0;
}
int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx)
{
int err;
if (n > mgr->avail)
return -ENOENT;
err = get_resource(mgr->rscs, mgr->amount, n, ridx);
if (!err)
mgr->avail -= n;
return err;
}
int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx)
{
put_resource(mgr->rscs, n, idx);
mgr->avail += n;
return 0;
}
static unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = {
/* SRC channel is at Audio Ring slot 1 every 16 slots. */
[SRC] = 0x1,
[AMIXER] = 0x4,
[SUM] = 0xc,
};
static int rsc_index(const struct rsc *rsc)
{
return rsc->conj;
}
static int audio_ring_slot(const struct rsc *rsc)
{
return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];
}
static int rsc_next_conj(struct rsc *rsc)
{
unsigned int i;
for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )
i++;
rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);
return rsc->conj;
}
static int rsc_master(struct rsc *rsc)
{
return rsc->conj = rsc->idx;
}
static struct rsc_ops rsc_generic_ops = {
.index = rsc_index,
.output_slot = audio_ring_slot,
.master = rsc_master,
.next_conj = rsc_next_conj,
};
int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw)
{
int err = 0;
rsc->idx = idx;
rsc->conj = idx;
rsc->type = type;
rsc->msr = msr;
rsc->hw = hw;
rsc->ops = &rsc_generic_ops;
if (NULL == hw) {
rsc->ctrl_blk = NULL;
return 0;
}
switch (type) {
case SRC:
err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
break;
case AMIXER:
err = ((struct hw *)hw)->
amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
break;
case SRCIMP:
case SUM:
case DAIO:
break;
default:
printk(KERN_ERR
"ctxfi: Invalid resource type value %d!\n", type);
return -EINVAL;
}
if (err) {
printk(KERN_ERR
"ctxfi: Failed to get resource control block!\n");
return err;
}
return 0;
}
int rsc_uninit(struct rsc *rsc)
{
if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {
switch (rsc->type) {
case SRC:
((struct hw *)rsc->hw)->
src_rsc_put_ctrl_blk(rsc->ctrl_blk);
break;
case AMIXER:
((struct hw *)rsc->hw)->
amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
break;
case SUM:
case DAIO:
break;
default:
printk(KERN_ERR "ctxfi: "
"Invalid resource type value %d!\n", rsc->type);
break;
}
rsc->hw = rsc->ctrl_blk = NULL;
}
rsc->idx = rsc->conj = 0;
rsc->type = NUM_RSCTYP;
rsc->msr = 0;
return 0;
}
int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
unsigned int amount, void *hw_obj)
{
int err = 0;
struct hw *hw = hw_obj;
mgr->type = NUM_RSCTYP;
mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL);
if (NULL == mgr->rscs)
return -ENOMEM;
switch (type) {
case SRC:
err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk);
break;
case SRCIMP:
err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk);
break;
case AMIXER:
err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk);
break;
case DAIO:
err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk);
break;
case SUM:
break;
default:
printk(KERN_ERR
"ctxfi: Invalid resource type value %d!\n", type);
err = -EINVAL;
goto error;
}
if (err) {
printk(KERN_ERR
"ctxfi: Failed to get manager control block!\n");
goto error;
}
mgr->type = type;
mgr->avail = mgr->amount = amount;
mgr->hw = hw;
return 0;
error:
kfree(mgr->rscs);
return err;
}
int rsc_mgr_uninit(struct rsc_mgr *mgr)
{
if (NULL != mgr->rscs) {
kfree(mgr->rscs);
mgr->rscs = NULL;
}
if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {
switch (mgr->type) {
case SRC:
((struct hw *)mgr->hw)->
src_mgr_put_ctrl_blk(mgr->ctrl_blk);
break;
case SRCIMP:
((struct hw *)mgr->hw)->
srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
break;
case AMIXER:
((struct hw *)mgr->hw)->
amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
break;
case DAIO:
((struct hw *)mgr->hw)->
daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
break;
case SUM:
break;
default:
printk(KERN_ERR "ctxfi: "
"Invalid resource type value %d!\n", mgr->type);
break;
}
mgr->hw = mgr->ctrl_blk = NULL;
}
mgr->type = NUM_RSCTYP;
mgr->avail = mgr->amount = 0;
return 0;
}
/**
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
*
* This source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
* @File ctresource.h
*
* @Brief
* This file contains the definition of generic hardware resources for
* resource management.
*
* @Author Liu Chun
* @Date May 13 2008
*
*/
#ifndef CTRESOURCE_H
#define CTRESOURCE_H
#include <linux/types.h>
enum RSCTYP {
SRC,
SRCIMP,
AMIXER,
SUM,
DAIO,
NUM_RSCTYP /* This must be the last one and less than 16 */
};
struct rsc_ops;
struct rsc {
u32 idx:12; /* The index of a resource */
u32 type:4; /* The type (RSCTYP) of a resource */
u32 conj:12; /* Current conjugate index */
u32 msr:4; /* The Master Sample Rate a resource working on */
void *ctrl_blk; /* Chip specific control info block for a resource */
void *hw; /* Chip specific object for hardware access means */
struct rsc_ops *ops; /* Generic resource operations */
};
struct rsc_ops {
int (*master)(struct rsc *rsc); /* Move to master resource */
int (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */
int (*index)(const struct rsc *rsc); /* Return the index of resource */
/* Return the output slot number */
int (*output_slot)(const struct rsc *rsc);
};
int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw);
int rsc_uninit(struct rsc *rsc);
struct rsc_mgr {
enum RSCTYP type; /* The type (RSCTYP) of resource to manage */
unsigned int amount; /* The total amount of a kind of resource */
unsigned int avail; /* The amount of currently available resources */
unsigned char *rscs; /* The bit-map for resource allocation */
void *ctrl_blk; /* Chip specific control info block */
void *hw; /* Chip specific object for hardware access */
};
/* Resource management is based on bit-map mechanism */
int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
unsigned int amount, void *hw);
int rsc_mgr_uninit(struct rsc_mgr *mgr);
int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx);
int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx);
#endif /* CTRESOURCE_H */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册