fseek char linux device - linux

I'm trying to write a simple char device for linux, I need to read and write the device by fread/fwrite and use fopen and fseek. I've written a simple test program to use my device and I've noted that fpos in fseek function doesn't work and unknow fread after fseek appears. I cannot get the device working because fseek doesn't get a correct file position when opened in r+ mode, everything works except fread if I use file opened in w mode instead.
Thanks folks
/* Makefile */
obj-m += char.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
/* char device char.c */
// to complie:
// # make
// # insmod char.ko
// # dmesg
// (to get majornumber)
// # mknod /dev/dp0 c majornumber 0
// # ./test
// # dmesg
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
int char_init (void);
void char_exit (void);
int char_open (struct inode *, struct file *);
int char_release (struct inode *, struct file *);
ssize_t char_read (struct file *, char __user *, size_t, loff_t *);
ssize_t char_write (struct file *, const char __user *, size_t, loff_t *);
loff_t char_llseek (struct file *, loff_t, int);
int char_open (struct inode *inode, struct file *fp)
{
printk ("f_mode=%d f_pos=%d\n", (int) fp->f_mode, (int)fp->f_pos);
return 0;
}
int char_release (struct inode *inode, struct file *fp)
{
return 0;
}
ssize_t char_read (struct file *fp, char __user *buff, size_t count, loff_t *fpos)
{
printk ("char_read() fp->f_pos=%d\n", (int) fp->f_pos);
return count;
}
ssize_t char_write (struct file *fp, const char __user *buff, size_t count, loff_t *fpos)
{
printk ("char_write() fp->f_pos=%d\n", (int) fp->f_pos);
return count;
}
loff_t char_llseek (struct file *fp, loff_t fpos, int whe)
{
printk ("char_llseek() fpos=%d\n ", (int) fpos);
fp->f_pos = fpos;
return fpos;
}
struct file_operations char_fops =
{
.owner = THIS_MODULE,
.open = char_open,
.release = char_release,
.read = char_read,
.write = char_write,
.llseek = char_llseek,
.ioctl = NULL,
};
/* the char device */
struct cdev cdev;
int char_init ()
{
dev_t mm;
int mj, mi, ret;
mi = 0;
ret = alloc_chrdev_region (&mm, mi, 1, "dp0");
mj = MAJOR(mm);
cdev_init (&cdev, &char_fops);
ret = cdev_add (&cdev, mm, 1);
if (ret<0)
{
printk ("char: unable to add device\n");
return -1;
}
printk ("char: device added major=%d\n", mj);
return 0;
}
void char_exit ()
{
cdev_del(&cdev);
printk ("char: device deleted\n");
}
module_init(char_init);
module_exit(char_exit);
/* test program test.c */
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[])
{
int ret;
FILE *fp;
fp = fopen ("/dev/dp0", "r+");
if (fp == NULL)
{
printf ("open failed\n");
return -1;
}
int x;
x= fseek (fp, 1, SEEK_SET);
printf("ret fseek=%d\n", x);
fseek (fp, 1, SEEK_SET);
fwrite ("\0", 1, 1, fp);
fseek (fp, 2, SEEK_SET);
fread (&ret, 1, 1, fp);
printf ("DONE\n");
fclose (fp);
return 0;
}
// this is my dmesg:
f_mode=31 f_pos=0 // this is my fopen
char_llseek() fpos=0 // this is my first fseek but why fpos=0? it should be 1
char_read() fp->f_pos=0 // what's that?
char_llseek() fpos=0 //this is my second fseek but why fpos is 0 again?
char_read() fp->f_pos=0 // I suppose this is my fread fpos=0?
char_llseek() fpos=-4095 // what's that?
char_llseek() fpos=-4095 // What's that too?
char_llseek() fpos=-4095 // What's that too?

You are using stdio (fread, fseek, etc.) which generally has a buffer of sorts. It may not necessarily translate directly to the syscalls, hence the "unexpected" reads and seeks.

Related

How could I use `kallsyms_lookup_name` function to fix `unknown character` error when loading Linux kernel module?

I'm trying to complete a hooking sample attachment in a program for my uni assignment. The task requires to get a system call sys_rt_sigaction hooked when initiating a loadable module in Linux kernel (I use Ubuntu 18.04 LTS, kernel version is 5.0.0-23-generic). So, the case I'm struggling originates from an error could not insert module <module name>: Unknown symbol in module once I started sudo insmod <my module name>.ko.
After some googling, I see clear this problem arises due to missing sys_call_table export to run inserting as smoothly as well. Following this post, I want to cope that invoking kallsyms_lookup_name call before kicking off init procedure.
There is .c-file which provides with definitions of operations accessible by module (file name is buffer.c):
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/syscalls.h>
#include <linux/kallsyms.h>
#include <linux/unistd.h>
void * sys_call_table = (void *) kallsyms_lookup_name("sys_call_table");// some wrongness here, but what exactly?
MODULE_LICENSE("GPL");
int (*real_rt_sigaction)(const char * path); // true syscall prototype
static int __init buffer_init_module(void);
static void __exit buffer_exit_module(void);
static int device_open(struct inode *, struct file *); // driver file opening
static int device_release(struct inode *, struct file *); // return of system resource control
static ssize_t device_read(struct file *, char *, size_t, loff_t *); // reading from driver file
static ssize_t device_write(struct file *, const char *, size_t, loff_t *); // writing into driver file
#define DEVICE_NAME "buffer"
#define BUF_LEN 80
// to be called instead
int alter_rt_sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact, size_t sigsetsize) {
printk(KERN_INFO "Syscall function hooked - you've lost control of your experience");
return 0;
}
static int Major;
static int Device_Open = 0;
static int total_open = 1;
static char Buf[BUF_LEN + 1] = "Buffer is empty, add some input\n";
static char *Msg_ptr;
static int Buf_Char = 50;
static int Bytes_Read = 0;
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
static int __init buffer_init_module(void)
{
printk(KERN_INFO
"Device initializing in progress...");
Major = register_chrdev(0, DEVICE_NAME, &fops);
if(Major < 0) {
printk("Major number hasn't been assigned - Driver registration failed\n");
return Major;
}
printk(KERN_INFO "Registration success - device major number: %d\n", Major);
real_rt_sigaction=sys_call_table[__NR_rt_sigaction];
sys_call_table[__NR_rt_sigaction]=alter_rt_sigaction; // hooking implementation
return 0;
}
static void __exit buffer_exit_module(void)
{
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_INFO "Outside the module - exit successfully completed\n");
sys_call_table[__NR_rt_sigaction]=real_rt_sigaction; // original call reset
}
static int device_open(struct inode *inode, struct file *file)
{
if(Device_Open)
return -EBUSY;
Device_Open++;
printk(KERN_INFO "Device file has been accessed %d time(s)\n", total_open++);
Msg_ptr = Buf;
try_module_get(THIS_MODULE);
Bytes_Read = 0;
return 0;
}
static int device_release(struct inode * node, struct file * filep)
{
Device_Open--;
module_put(THIS_MODULE);
printk(KERN_INFO "Device file gets close\n");
return 0;
}
static ssize_t device_read(struct file * filep, char * buffer, size_t len, loff_t * offset)
{
int got_read = Bytes_Read;
if(Bytes_Read >= Buf_Char)
return 0;
while(len && (Bytes_Read < Buf_Char)) {
put_user(Msg_ptr[Bytes_Read], buffer+Bytes_Read);
len--;
Bytes_Read++;
}
return Bytes_Read-got_read;
}
static ssize_t device_write(struct file * filep, const char * buffer, size_t len, loff_t * offset)
{
Buf_Char = 0;
if(Buf_Char >= BUF_LEN) {
return 0;
}
while(len && (Buf_Char < BUF_LEN))
{
get_user(Msg_ptr[Buf_Char], buffer+Buf_Char);
len--;
Buf_Char++;
}
return Buf_Char;
}
module_init(buffer_init_module);
module_exit(buffer_exit_module);
Additively, there is code in Makefile:
obj-m += buffer.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
The painful moment here is an error message initializer element is not constant whenever I was trying to build module via sudo make in my project folder. As I follow the beginner's tutorials and need for some basic insight, it might be highly appreciable to see any help with solution or even some ideas how to handle the same problem more effectively, indeed.

How to get the reference count on Linux driver level?

In the Linux kernel the opened file is indicated by struct file, and the file descriptor table contains a pointers which is point to struct file. f_count is an important member in the struct file. f_count, which means Reference Count. The system call dup() and fork() make other file descriptor point to same struct file.
As shown in the picture (sorry, my reputation is too low, the picture can not be uploaded), fd1 and fd2 point to the struct file, so the Reference Count is equal to 2, thus f_count = 2.
My question is how can i get the value of the f_count by programming.
UPDATE:ok,In order to make myself more clear i will show my code, both the char device driver,Makefile and my application.:D
deviceDriver.c
#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/fs.h"
#include "linux/init.h"
#include "linux/types.h"
#include "linux/errno.h"
#include "linux/uaccess.h"
#include "linux/kdev_t.h"
#define MAX_SIZE 1024
static int my_open(struct inode *inode, struct file *file);
static int my_release(struct inode *inode, struct file *file);
static ssize_t my_read(struct file *file, char __user *user, size_t t, loff_t *f);
static ssize_t my_write(struct file *file, const char __user *user, size_t t, loff_t *f);
static char message[MAX_SIZE] = "-------congratulations--------!";
static int device_num = 0;//device number
static int counter = 0;
static int mutex = 0;
static char* devName = "myDevice";//device name
struct file_operations pStruct =
{ open:my_open, release:my_release, read:my_read, write:my_write, };
/* regist the module */
int init_module()
{
int ret;
/ **/
ret = register_chrdev(0, devName, &pStruct);
if (ret < 0)
{
printk("regist failure!\n");
return -1;
}
else
{
printk("the device has been registered!\n");
device_num = ret;
printk("<1>the virtual device's major number %d.\n", device_num);
printk("<1>Or you can see it by using\n");
printk("<1>------more /proc/devices-------\n");
printk("<1>To talk to the driver,create a dev file with\n");
printk("<1>------'mknod /dev/myDevice c %d 0'-------\n", device_num);
printk("<1>Use \"rmmode\" to remove the module\n");
return 0;
}
}
void cleanup_module()
{
unregister_chrdev(device_num, devName);
printk("unregister it success!\n");
}
static int my_open(struct inode *inode, struct file *file)
{
if(mutex)
return -EBUSY;
mutex = 1;//lock
printk("<1>main device : %d\n", MAJOR(inode->i_rdev));
printk("<1>slave device : %d\n", MINOR(inode->i_rdev));
printk("<1>%d times to call the device\n", ++counter);
try_module_get(THIS_MODULE);
return 0;
}
/* release */
static int my_release(struct inode *inode, struct file *file)
{
printk("Device released!\n");
module_put(THIS_MODULE);
mutex = 0;//unlock
return 0;
}
static ssize_t my_read(struct file *file, char __user *user, size_t t, loff_t *f)
{
if(copy_to_user(user,message,sizeof(message)))
{
return -EFAULT;
}
return sizeof(message);
}
static ssize_t my_write(struct file *file, const char __user *user, size_t t, loff_t *f)
{
if(copy_from_user(message,user,sizeof(message)))
{
return -EFAULT;
}
return sizeof(message);
}
Makefile:
# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifeq ($(KERNELRELEASE),)
# Assume the source tree is where the running kernel was built
# You should set KERNELDIR in the environment if it's elsewhere
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
# called from kernel build system: just declare what our modules are
obj-m := devDrv.o
endif
application.c:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define MAX_SIZE 1024
int main(void)
{
int fd;
char buf[MAX_SIZE];
char get[MAX_SIZE];
char devName[20], dir[50] = "/dev/";
system("ls /dev/");
printf("Please input the device's name you wanna to use :");
gets(devName);
strcat(dir, devName);
fd = open(dir, O_RDWR | O_NONBLOCK);
if (fd != -1)
{
read(fd, buf, sizeof(buf));
printf("The device was inited with a string : %s\n", buf);
/* test fot writing */
printf("Please input a string :\n");
gets(get);
write(fd, get, sizeof(get));
/* test for reading */
read(fd, buf, sizeof(buf));
system("dmesg");
printf("\nThe string in the device now is : %s\n", buf);
close(fd);
return 0;
}
else
{
printf("Device open failed\n");
return -1;
}
}
Any idea to get the struct file's(char device file) f_count? Is it poassible get it by the way of printk?
You should divide reference counter to module from other module and from user-space application. lsmod show how many modules use your module.
sctp 247143 4
libcrc32c 12644 1 sctp
It is impossible load sctp without libcrc32c because sctp use exported function from libcrc32 to calculate control sum for packets.
The reference counter itself is embedded in the module data structure and can be obtained with the function uint module_refcount(struct module* module);
You can use:
printk("Module reference counter: %d\n", (int)module_refcount(THIS_MODULE));
THIS_MODULE it is a reference to current loadable module (for build-in module it is NULL) inside .owner field (inside struct file_operations).
If there is a need manually modify module's counter use:
int try_module_get(struct module* module);
void module_put(struct module* module);
If module unloaded it will return false. You also can move thru all modules. Modules linked via list.
File opening inside kernel it is bad idea. Inside kernel you can get access to inode. Try read man pages for dup and fork. In you system you can investigate lsof tools.

How to test your own Linux module?

Today I am getting started with developing Linux modules. It was rather hard to write, compile and work with Helloworld, but I've done it.
My second module with open, write, read functions is ready, but I really dont know how to test it. Write method just makes printk(). My module is loaded, its name is iamnoob. How to test this write(...) function and to find smth in var/log/syslog?
cat > iamnoob just writes a file to the dir. Same with cp and other.
Sorry for noob question, i've googled, but no answer has been found. Sorry for poor English.
A basic kernel module would normally include registering a character device.
Simple imlementation requires:
Register chrdev region with specific major & minor.
Allocate file operations structure and implement the basic read / write APIs.
Initialize and register character device with the file operations structure to the major / minor region.
See the following code snippet as a template of a module (only read / write APIs are imlemented):
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm-generic/uaccess.h>
#define MY_BUFFER_SIZE (1024 * 10)
#define MY_CHRDEV_MAJOR 217
#define MY_CHRDEV_MINOR 0
static struct cdev my_cdev;
static unsigned char *my_buf;
static dev_t my_dev = MKDEV(MY_CHRDEV_MAJOR, MY_CHRDEV_MINOR);
ssize_t my_read(struct file *file, char __user * buf, size_t count, loff_t * ppos)
{
int size;
size = MY_BUFFER_SIZE - 100 - (int)*ppos;
if (size > count)
size = count;
if (copy_to_user(buf, my_buf + *ppos, count))
return -EFAULT;
*ppos += size;
return size;
}
ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
int size;
size = MY_BUFFER_SIZE - 100 - (int)*ppos;
if (size > count)
size = count;
if (copy_from_user(my_buf + *ppos, buf, count))
return -EFAULT;
*ppos += size;
return size;
}
long my_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
printk ("%s!\n", __FUNCTION__);
return 0;
}
int my_mmap(struct file *f, struct vm_area_struct *vma)
{
printk ("%s!\n", __FUNCTION__);
return 0;
}
int my_open(struct inode *i, struct file *f)
{
printk ("%s!\n", __FUNCTION__);
return 0;
}
int my_release(struct inode *i, struct file *f)
{
printk ("%s!\n", __FUNCTION__);
return 0;
}
struct file_operations my_fops =
{
.owner = THIS_MODULE,
.read = &my_read,
.write = &my_write,
.unlocked_ioctl = &my_unlocked_ioctl,
.mmap = &my_mmap,
.open = &my_open,
.release = &my_release,
};
static int __init my_module_init(void)
{
int line = 0;
unsigned char *pos;
printk ("%s!\n", __FUNCTION__);
my_buf = (unsigned char *)kzalloc(MY_BUFFER_SIZE, 0);
if (my_buf == NULL) {
printk("%s - failed to kzallocate buf!\n", __FUNCTION__);
return -1;
}
pos = my_buf;
while (pos - my_buf < MY_BUFFER_SIZE - 100) {
sprintf(pos, "Line #%d\n", line++);
pos += strlen(pos);
}
cdev_init(&my_cdev, &my_fops);
if (register_chrdev_region(my_dev, 1, "my_dev")) {
pr_err("Failed to allocate device number\n");
}
cdev_add(&my_cdev, my_dev, 1);
printk ("%s - registered chrdev\n", __FUNCTION__);
return 0;
}
static void __exit my_module_exit(void)
{
printk ("my_module_exit.\n");
unregister_chrdev_region(my_dev, 1);
return;
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
This module uses a buffer for file operations, therefore can be tested on any machine, regardless of its HW. Make sure you avoid unnecessary printk's as loops may harm your kernel stability.
Once this is done, in user-space shell you should create a /dev node to represent your character device:
sudo mknod /dev/[dev_name] c [major] [minor]
for example:
sudo mknod /dev/my_dev c 217 0
Then you can test your read / write APIs with:
sudo insmod my_modult.ko
cat /dev/my_dev
less -f /dev/my_dev
sudo su
root> echo "This is a test" > /dev/my_dev
root> exit
cat /dev/my_dev
The shell commands listed above perform read, then login as root (to allow writing to device), write to the char dev, then exit and read again to see the changes.
Now you'd normally implement ioctl and mmap if needed.

Device driver not working

I wrote a small device driver for a "coin" device. I create an entry in /drivers/char/Kconfig
and corresponding Makefile, then selected built-in option in menuconfig. The kernel compiled fine (built-in.o file was created). But I still can't access the device (/dev/coin was not created) and there was no entry under /proc/devices.
Please help!!
I am cross-compiling for powerpc
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/random.h>
#include <linux/debugfs.h>
#include <linux/init.h>
#define DEVNAME "coin"
#define LEN 20
enum values {HEAD, TAIL};
struct dentry *dir, *file;
int file_value;
int stats[2] = {0, 0};
char *msg[2] = {"head\n", "tail\n"};
static int major;
static struct class *class_coin;
static struct device *dev_coin;
static ssize_t r_coin(struct file *f, char __user *b,
size_t cnt, loff_t *lf)
{
char *ret;
u32 value = random32() % 2;
ret = msg[value];
stats[value]++;
return simple_read_from_buffer(b, cnt,
lf, ret,
strlen(ret));
}
static struct file_operations fops = { .read = r_coin };
#ifdef CONFIG_COIN_STAT
static ssize_t r_stat(struct file *f, char __user *b,
size_t cnt, loff_t *lf)
{
char buf[LEN];
snprintf(buf, LEN, "head=%d tail=%d\n",
stats[HEAD], stats[TAIL]);
return simple_read_from_buffer(b, cnt,
lf, buf,
strlen(buf));
}
static struct file_operations fstat = { .read = r_stat };
#endif
static int __init coin_init(void)
{
void *ptr_err;
major = register_chrdev(0, DEVNAME, &fops);
if (major < 0)
return major;
class_coin = class_create(THIS_MODULE,
DEVNAME);
if (IS_ERR(class_coin)) {
ptr_err = class_coin;
goto err_class;
}
dev_coin = device_create(class_coin, NULL,
MKDEV(major, 0),
NULL, DEVNAME);
if (IS_ERR(dev_coin))
goto err_dev;
#ifdef CONFIG_COIN_STAT
dir = debugfs_create_dir("coin", NULL);
file = debugfs_create_file("stats", 0644,
dir, &file_value,
&fstat);
#endif
return 0;
err_dev:
ptr_err = class_coin;
class_destroy(class_coin);
err_class:
unregister_chrdev(major, DEVNAME);
return PTR_ERR(ptr_err);
}
static void __exit coin_exit(void)
{
#ifdef CONFIG_COIN_STAT
debugfs_remove(file);
debugfs_remove(dir);
#endif
device_destroy(class_coin, MKDEV(major, 0));
class_destroy(class_coin);
return unregister_chrdev(major, DEVNAME);
}
module_init(coin_init);
module_exit(coin_exit);
What if you manually insert module into kernel using insmod? Does it work? Any messages in dmesg?
As I remember entries in /dev (/dev/coin) should be created manually using mknod, but you need major number of registered device. Just printk it after register_chrdev().

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?
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.

Resources