Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Register a sound card driver in Linux

I want to write a virtual sound card driver that shall be used by the linux system for audio playback and capture. The driver shall use a buffer for audio data read/write. I have written the following basic driver:

#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;
}

insmoding this module creates a driver at /dev/dsp. Also it is found in /sys/devices/virtual/sound/dsp/, so it is recognised by the system as a virtual audio driver.

I am not yet able to choose this device for playback and capture from applications. What else do I need to do to make this driver enumerated by audio applications?

like image 940
Khaled Avatar asked Nov 14 '22 19:11

Khaled


1 Answers

Well /dev/dsp was the device node used for a sound card under the old OSS sound system in linux but these days pretty much everything will default to looking for devices based on the newer ALSA sound system.

Some software still supports OSS but you may well need to give it special options, or change the configuration, to tell it to use OSS instead of ALSA.

ALSA devices are found under /dev/snd and aren't normally accessed directly, as they are more complicated than the old OSS devices. Instead libasound is normally used to interact with them.

like image 104
TomH Avatar answered Dec 27 '22 16:12

TomH