ALSA的ioctl - hwdep

hwdep模塊簡述


字符設備驅動中,ioctl是一個很常見的IO設備操作函數,可以自定義cmd命令字並實現對應的設備IO控制。

音頻設備的控制有所不同:驅動層大部分控制操作定義各種snd_kcontrol_new,然後註冊到SNDRV_DEV_CONTROL模塊中(sound\core\control.c),詳見snd_kcontrol探究;而上層調用alsa-lib的snd_ctl_open/snd_mixer_open來打開底層的SNDRV_DEV_CONTROL模塊,詳見DAPM之二:audio paths與dapm kcontrol。這方法常見於mixer-control,如音量調整、部件開關、通路連接等等。

除此之外,alsa還是可以實現類似於ioctl的函數的,只不過它封裝成一個設備模塊SNDRV_DEV_HWDEP,代碼sound\core\ hwdep.c。該模塊實現了read/write/ioctl/llseek/poll/mmap等接口。hwdep是Hardware Dependant Interface的簡稱。


題外話:如果想看自己板上的alsa有什麼類型的設備可以cat /proc/asound/devices,如

~ # cat /proc/asound/devices 
  0: [ 0]   : control
  4: [ 0- 0]: hardware dependent
 16: [ 0- 0]: digital audio playback
 24: [ 0- 0]: digital audio capture
 33:        : timer
設備節點號minor=0是control,=4是hwdep,=16是pcm-playback,=24是pcm-capture,=33是timer。


如下簡單分析ioctl:

//套接字接口函數集
static const struct file_operations snd_hwdep_f_ops =
{
	.owner = 	THIS_MODULE,
	.llseek =	snd_hwdep_llseek,
	.read = 	snd_hwdep_read,
	.write =	snd_hwdep_write,
	.open =		snd_hwdep_open,
	.release =	snd_hwdep_release,
	.poll =		snd_hwdep_poll,
	.unlocked_ioctl =	snd_hwdep_ioctl,
	.compat_ioctl =	snd_hwdep_ioctl_compat,
	.mmap =		snd_hwdep_mmap,
};

static long snd_hwdep_ioctl(struct file * file, unsigned int cmd,
			    unsigned long arg)
{
	struct snd_hwdep *hw = file->private_data;
	void __user *argp = (void __user *)arg;
	switch (cmd) {
	case SNDRV_HWDEP_IOCTL_PVERSION:
		return put_user(SNDRV_HWDEP_VERSION, (int __user *)argp);
	case SNDRV_HWDEP_IOCTL_INFO:
		return snd_hwdep_info(hw, argp);
	case SNDRV_HWDEP_IOCTL_DSP_STATUS:
		return snd_hwdep_dsp_status(hw, argp);
	case SNDRV_HWDEP_IOCTL_DSP_LOAD:
		return snd_hwdep_dsp_load(hw, argp);
	}
	if (hw->ops.ioctl)
		return hw->ops.ioctl(hw, file, cmd, arg);
	return -ENOTTY;
}

從snd_hwdep_ioctl可以看出,系統默認只有4個cmd,功能主要是download dsp image。從return hw->ops.ioctl(hw, file, cmd, arg)語句可以看出,我們可自定義cmd和ioctl函數。


實現自定義的hwdep操作函數


1、 首先實現需要的操作函數:

static int my_hwdep_open(struct snd_hwdep * hw, struct file *file)
{
	printk(KERN_INFO "my_hwdep_open\n");
	return 0;
}

static int my_hwdep_ioctl(struct snd_hwdep * hw, struct file *file, unsigned int cmd, unsigned long arg)
{
#define MY_SOC_IOCTL_SET_CALL_PATH   _IOWR('H', 0x10, int)

	switch (cmd) {
	case MY_SOC_IOCTL_SET_CALL_PATH:
		//設置電話語音通路
		return 0;
		break;
	//......
	}
	
	err("Not supported ioctl for MY-HWDEP");
	return -ENOIOCTLCMD;
}

2、 註冊操作函數到hwdep模塊:
struct snd_hwdep *hwdep;

if (snd_hwdep_new(codec->card, "MY-HWDEP", 0, &hwdep) < 0) {
	printk(KERN_ERR "create MY-HWDEP fail");
	return;
}

sprintf(hwdep->name, "MY-HWDEP %d", 0);

hwdep->iface = SNDRV_HWDEP_IFACE_WMT;
hwdep->ops.open = wmt_hwdep_open;
hwdep->ops.ioctl = wmt_hwdep_ioctl;
這裏摘錄snd_hwdep_new的代碼註釋,讓大家更明白上面的註冊過程:

/**
 * snd_hwdep_new - create a new hwdep instance
 * @card: the card instance
 * @id: the id string
 * @device: the device index (zero-based)
 * @rhwdep: the pointer to store the new hwdep instance
 *
 * Creates a new hwdep instance with the given index on the card.
 * The callbacks (hwdep->ops) must be set on the returned instance
 * after this call manually by the caller.
 *
 * Returns zero if successful, or a negative error code on failure.
 */
按照以上實現hwdep ioctl後,上層可以通過alsa-lib的相關接口來調用。


上層調用範例


#include <fcntl.h>
#include <sys/ioctl.h>
#include <alsa/hwdep.h>
#include <alsa/error.h>
#include <stdio.h>

#define MY_SOC_IOCTL_SET_CALL_PATH   _IOWR('H', 0x10, int)

int main()
{
	const char *devicename = "hw:0,0";
	snd_hwdep_t *hwdep;
	int err;
	int enable = 1;
	
	if ((err = snd_hwdep_open(&hwdep, devicename, O_RDWR)) < 0) {
		printf("hwdep interface open error: %s \n", snd_strerror(err));
		return -1;
	}
	
	if ((err = snd_hwdep_ioctl(hwdep, MY_SOC_IOCTL_SET_CALL_PATH, &enable)) < 0) {
		printf("hwdep ioctl error: %s \n", snd_strerror(err));
	}
	
	snd_hwdep_close(hwdep);
	
	return 0;
}


總結


可以看出hwdep的本意主要是用於download dsp image,但通過它也可實現類似於其他字符設備的ioctl。我說過音頻大多控制是通過snd_kcontrol,但有些功能如果使用這種方式會比較繁瑣且模塊太過耦合。

舉個例子:電話語音通路,它不同於音樂回放通路,通話時才需要打開。如果用snd_kcontrol,則上層需要調用多個control.set,並且更換CODEC芯片的話,上層也要跟着修改control name;如果使用hwdep ioctl的話,就沒有這個問題,只需要保證命令字cmd一致,底層如何管理通話通路的一系列部件開關,上層都不需要關心。

發佈了59 篇原創文章 · 獲贊 62 · 訪問量 64萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章