linux - 在 Linux 中注册一个声卡驱动

标签 linux audio linux-kernel driver

我想写一个虚拟声卡驱动程序,供linux系统使用,用于音频播放和采集。驱动程序应使用缓冲区进行音频数据读/写。我编写了以下基本驱动程序:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sound.h>

#include <linux/sysctl.h>
#include <linux/device.h>

#include <linux/slab.h> /* kmalloc() */
#include <linux/gfp.h>
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/err.h>

#include <sound/core.h>

static char* mod_name = "prosip";

MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1111");
MODULE_AUTHOR("DD-DDD");
MODULE_DESCRIPTION("proSip Virtual Sound Card");

//
static int ver_major = 133;

static int ver_minor = 3;

//
static int buffer_size = 0;
static char* buffer;
static int read_count = 0;

/* Declaration of memory.c functions */
int prosip_open(struct inode *inode, struct file *filp);
int prosip_release(struct inode *inode, struct file *filp);

//
ssize_t prosip_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t prosip_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos);

//
int prosip_ioctl(struct inode *inode,struct file *file,unsigned int ioctl_num,unsigned long ioctl_param);

//
static int  __init prosip_init(void);
static void __exit prosip_exit(void);

/* Structure that declares the usual file access functions */
struct file_operations sound_fops =
{
owner:
    THIS_MODULE,
read:
    prosip_read,
write:
    prosip_write,
open:
    prosip_open,
release:
    prosip_release,
ioctl:
    prosip_ioctl
};


/* Declaration of the init and exit functions */
module_init(prosip_init);
module_exit(prosip_exit);

static int __init prosip_init(void)
{
    int ret = -1;
    buffer_size = 0;

    printk("<1>[prosip] Init...!\n");

    ret = register_sound_dsp(&sound_fops, ver_minor);

    if(ret < 0)
    {
        printk("<1> [prosip] Registration failure\n");
        //
        return ret;
    }
    else
    {
        ver_minor = ret;
        //
        printk("<1> [prosip] DSP Registered succesfully with id %d\n", ret);
    }

    buffer = kmalloc(101, GFP_KERNEL);

    if(buffer == 0)
    {
        printk("<1>[prosip] Failed to allocate buffer !!!\n");
        //
        return -ENOMEM;
    }

    //
    return 0;
}

static void __exit prosip_exit(void)
{
    printk("<1> [prosip] Sound Exit...\n");

    unregister_sound_special(ver_minor);

    if(buffer)
    {
        kfree(buffer);
    }

}

/* Declaration of memory.c functions */
int prosip_open(struct inode *inode, struct file *filp)
{
    printk("<1> [prosip] Sound Open... \n");

    try_module_get(THIS_MODULE);

    return 0;
}

//
int prosip_release(struct inode *inode, struct file *filp)
{
    printk("<1> [MySound] Sound Release... \n");

    module_put(THIS_MODULE);

    return 0;
}

//
ssize_t prosip_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
    printk("<1> [prosip] Sound read...\n");
    printk("<1> [prosip] Writing Count: %d\n", count);

    if(buffer == 0)
    {
        printk("<1> NULL buffer!!! Unable to read");
        return 0;
    }

    //
    count =  buffer_size;

    if(read_count == 0)
    {
        read_count = buffer_size;
    }
    else
    {
        read_count = 0;
    }

    copy_to_user(buf, buffer, buffer_size);

    printk("<1> [prosip] Buffer: %s, buf: %s, Count: %d\n", buffer, buf, count);

    return read_count;
}

//
ssize_t prosip_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
    printk("<1> [prosip] Sound write...!\n");
    printk("<1> [prosip] Writing Count: %d\n", count);

    //
    if(buffer == 0)
    {
        printk("<1> NULL buffer!!! Unable to write");

        return 0;
    }

    copy_from_user(buffer, buf, count);

    buffer[count] = 0;
    buffer_size = count;

    printk("<1> [MySound] Writing Buffer: %s, Count: %d\n", buffer, count);

    return count;
}

/*
* This function is called whenever a process tries to do an ioctl on our
* device file.
*
*/
int prosip_ioctl(struct inode *inode,
                 struct file *file,
                 unsigned int ioctl_num,
                 unsigned long ioctl_param)
{
    //
    return 0;
}

insmod此模块会在 /dev/dsp 中创建一个驱动程序。也可以在/sys/devices/virtual/sound/dsp/中找到,所以它被系统识别为虚拟音频驱动程序。

我还不能选择这个设备来播放和从应用程序中捕获。我还需要做什么才能让音频应用程序枚举此驱动程序?

最佳答案

/dev/dsp 是在 linux 中旧的 OSS 声音系统下用于声卡的设备节点,但现在几乎所有的东西都会默认寻找基于较新的 ALSA 声音的设备系统。

有些软件仍然支持 OSS,但您可能需要为其提供特殊选项或更改配置,以告诉它使用 OSS 而不是 ALSA。

ALSA 设备位于 /dev/snd 下,通常不能直接访问,因为它们比旧的 OSS 设备更复杂。相反,libasound 通常用于与它们交互。

关于linux - 在 Linux 中注册一个声卡驱动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6841569/

相关文章:

c++ - 如何使用 Windows API 自动将 C++ 代码从 Windows 转换为 Linux

linux - 如何检测文件已被删除

iphone - SystemSoundID 的不同实例在不同的流上播放!

Linux 为 DECLARE_WORK 中的函数传递参数

security - 用户可以在Docker容器中更改内核配置形式吗?

c - 从内核模块中的串口读取

linux - 为什么 HashiCorp 的 Vault 需要启用 ipc_lock 功能?

c - limits.h 中定义的限制 FILENAME_MAX 是否适用于目录?

javascript - 我正在努力使用Javascript和XMLHTTPRequest从网页保存音频文件

html - 尝试在网页上实现两个音频文件