skypopen: tweaking the OSS audio driver

This commit is contained in:
Giovanni Maruzzelli 2010-12-14 16:55:31 -06:00
parent 1d668e25ab
commit eafd7e5e15
3 changed files with 110 additions and 126 deletions

View File

@ -4,7 +4,7 @@
# Add your debugging flag (or not) to CFLAGS # Add your debugging flag (or not) to CFLAGS
ifeq ($(DEBUG),y) ifeq ($(DEBUG),y)
DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines DEBFLAGS = -O -g -DSKYPOPEN_DEBUG # "-O" is needed to expand inlines
else else
DEBFLAGS = -O2 -Wall DEBFLAGS = -O2 -Wall
endif endif
@ -15,9 +15,9 @@ EXTRA_CFLAGS += -I$(LDDINC)
ifneq ($(KERNELRELEASE),) ifneq ($(KERNELRELEASE),)
# call from kernel build system # call from kernel build system
scull-objs := main.o skypopen-objs := main.o
obj-m := scull.o obj-m := skypopen.o
else else

View File

@ -1,5 +1,5 @@
/* /*
* main.c -- the bare scull char module * main.c -- the bare skypopen char module
* *
* Copyright (C) 2010 Giovanni Maruzzelli * Copyright (C) 2010 Giovanni Maruzzelli
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
@ -41,33 +41,32 @@
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include "scull.h" /* local definitions */ #include "skypopen.h" /* local definitions */
/* /*
* Our parameters which can be set at load time. * Our parameters which can be set at load time.
*/ */
int scull_major = SCULL_MAJOR; int skypopen_major = SKYPOPEN_MAJOR;
int scull_minor = 3; int skypopen_minor = 3;
int scull_nr_devs = SCULL_NR_DEVS; /* number of bare scull devices */ int skypopen_nr_devs = SKYPOPEN_NR_DEVS; /* number of bare skypopen devices */
module_param(scull_major, int, S_IRUGO); module_param(skypopen_major, int, S_IRUGO);
module_param(scull_minor, int, S_IRUGO); module_param(skypopen_minor, int, S_IRUGO);
module_param(scull_nr_devs, int, S_IRUGO); module_param(skypopen_nr_devs, int, S_IRUGO);
MODULE_AUTHOR("Original: Alessandro Rubini, Jonathan Corbet. Heavy modified by: Giovanni Maruzzelli"); MODULE_AUTHOR("Original: Alessandro Rubini, Jonathan Corbet. Modified by: Giovanni Maruzzelli for FreeSWITCH skypopen");
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
static struct scull_dev *scull_devices; /* allocated in scull_init_module */ static struct skypopen_dev *skypopen_devices; /* allocated in skypopen_init_module */
#define GIOVA_BLK 1920 #define GIOVA_BLK 1920
#define GIOVA_SLEEP 20 #define GIOVA_SLEEP 20
void my_timer_callback_inq( unsigned long data ) void my_timer_callback_inq( unsigned long data )
{ {
struct scull_dev *dev = (void *)data; struct skypopen_dev *dev = (void *)data;
//dev->readable=1;
wake_up_interruptible(&dev->inq); wake_up_interruptible(&dev->inq);
mod_timer( &dev->timer_inq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) ); mod_timer( &dev->timer_inq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) );
@ -75,83 +74,83 @@ void my_timer_callback_inq( unsigned long data )
void my_timer_callback_outq( unsigned long data ) void my_timer_callback_outq( unsigned long data )
{ {
struct scull_dev *dev = (void *)data; struct skypopen_dev *dev = (void *)data;
//dev->writable=1;
wake_up_interruptible(&dev->outq); wake_up_interruptible(&dev->outq);
mod_timer( &dev->timer_outq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) ); mod_timer( &dev->timer_outq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) );
} }
/* The clone-specific data structure includes a key field */ /* The clone-specific data structure includes a key field */
struct scull_listitem { struct skypopen_listitem {
struct scull_dev device; struct skypopen_dev device;
dev_t key; dev_t key;
struct list_head list; struct list_head list;
}; };
/* The list of devices, and a lock to protect it */ /* The list of devices, and a lock to protect it */
static LIST_HEAD(scull_c_list); static LIST_HEAD(skypopen_c_list);
static spinlock_t scull_c_lock = SPIN_LOCK_UNLOCKED; static spinlock_t skypopen_c_lock = SPIN_LOCK_UNLOCKED;
/* Look for a device or create one if missing */ /* Look for a device or create one if missing */
static struct scull_dev *scull_c_lookfor_device(dev_t key) static struct skypopen_dev *skypopen_c_lookfor_device(dev_t key)
{ {
struct scull_listitem *lptr; struct skypopen_listitem *lptr;
list_for_each_entry(lptr, &scull_c_list, list) { list_for_each_entry(lptr, &skypopen_c_list, list) {
if (lptr->key == key) if (lptr->key == key)
return &(lptr->device); return &(lptr->device);
} }
/* not found */ /* not found */
lptr = kmalloc(sizeof(struct scull_listitem), GFP_KERNEL); lptr = kmalloc(sizeof(struct skypopen_listitem), GFP_KERNEL);
if (!lptr) if (!lptr)
return NULL; return NULL;
/* initialize the device */ /* initialize the device */
memset(lptr, 0, sizeof(struct scull_listitem)); memset(lptr, 0, sizeof(struct skypopen_listitem));
lptr->key = key; lptr->key = key;
init_waitqueue_head(&lptr->device.inq); init_waitqueue_head(&lptr->device.inq);
init_waitqueue_head(&lptr->device.outq); init_waitqueue_head(&lptr->device.outq);
printk(" Timer installing\n"); setup_timer( &lptr->device.timer_inq, my_timer_callback_inq, (long int)lptr );
setup_timer( &lptr->device.timer_inq, my_timer_callback_inq, (long int)lptr ); setup_timer( &lptr->device.timer_outq, my_timer_callback_outq, (long int)lptr );
setup_timer( &lptr->device.timer_outq, my_timer_callback_outq, (long int)lptr ); printk( "Starting skypopen OSS driver read timer (%dms) skype client:(%d)\n", GIOVA_SLEEP, current->tgid );
printk( "Starting timer to fire in %dms (%ld)\n", GIOVA_SLEEP, jiffies ); mod_timer( &lptr->device.timer_inq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) );
mod_timer( &lptr->device.timer_inq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) ); printk( "Starting skypopen OSS driver write timer (%dms) skype client:(%d)\n", GIOVA_SLEEP, current->tgid );
mod_timer( &lptr->device.timer_outq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) ); mod_timer( &lptr->device.timer_outq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) );
/* place it in the list */ /* place it in the list */
list_add(&lptr->list, &scull_c_list); list_add(&lptr->list, &skypopen_c_list);
return &(lptr->device); return &(lptr->device);
} }
static int scull_c_open(struct inode *inode, struct file *filp)
/*
* Open and close
*/
static int skypopen_c_open(struct inode *inode, struct file *filp)
{ {
struct scull_dev *dev; struct skypopen_dev *dev;
dev_t key; dev_t key;
if (!current->pid) {
printk("Process \"%s\" has no pid\n", current->comm);
return -EINVAL;
}
key = current->pid; key = current->pid;
/* look for a scullc device in the list */ /* look for a skypopenc device in the list */
spin_lock(&scull_c_lock); spin_lock(&skypopen_c_lock);
dev = scull_c_lookfor_device(key); dev = skypopen_c_lookfor_device(key);
spin_unlock(&scull_c_lock); spin_unlock(&skypopen_c_lock);
if (!dev) if (!dev)
return -ENOMEM; return -ENOMEM;
/* then, everything else is copied from the bare scull device */ /* then, everything else is copied from the bare skypopen device */
filp->private_data = dev; filp->private_data = dev;
return 0; /* success */ return 0; /* success */
} }
static int scull_c_release(struct inode *inode, struct file *filp) static int skypopen_c_release(struct inode *inode, struct file *filp)
{ {
/* /*
* Nothing to do, because the device is persistent. * Nothing to do, because the device is persistent.
@ -163,39 +162,29 @@ static int scull_c_release(struct inode *inode, struct file *filp)
/*************************************************************/ /*************************************************************/
/*
* Open and close
*/
ssize_t scull_read(struct file *filp, char __user *buf, size_t count, ssize_t skypopen_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos) loff_t *f_pos)
{ {
struct scull_dev *dev = filp->private_data; struct skypopen_dev *dev = filp->private_data;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
prepare_to_wait(&dev->inq, &wait, TASK_INTERRUPTIBLE); prepare_to_wait(&dev->inq, &wait, TASK_INTERRUPTIBLE);
schedule(); schedule();
finish_wait(&dev->inq, &wait); finish_wait(&dev->inq, &wait);
//memset(buf, 255, count);
//wait_event_interruptible(dev->inq, dev->readable);
//dev->readable=0;
return count; return count;
} }
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos) loff_t *f_pos)
{ {
struct scull_dev *dev = filp->private_data; struct skypopen_dev *dev = filp->private_data;
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE); prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
schedule(); schedule();
finish_wait(&dev->outq, &wait); finish_wait(&dev->outq, &wait);
//wait_event_interruptible(dev->outq, dev->writable);
//dev->writable=0;
return count; return count;
} }
@ -203,7 +192,7 @@ ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
* The ioctl() implementation * The ioctl() implementation
*/ */
int scull_ioctl(struct inode *inode, struct file *filp, int skypopen_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
@ -223,14 +212,14 @@ int scull_ioctl(struct inode *inode, struct file *filp,
} }
struct file_operations scull_fops = { struct file_operations skypopen_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.read = scull_read, .read = skypopen_read,
.write = scull_write, .write = skypopen_write,
.ioctl = scull_ioctl, .ioctl = skypopen_ioctl,
.open = scull_c_open, .open = skypopen_c_open,
.release = scull_c_release, .release = skypopen_c_release,
}; };
/* /*
@ -243,34 +232,34 @@ struct file_operations scull_fops = {
* have not been initialized * have not been initialized
*/ */
void scull_cleanup_module(void) void skypopen_cleanup_module(void)
{ {
int i; int i;
int ret; int ret;
struct scull_listitem *lptr, *next; struct skypopen_listitem *lptr, *next;
dev_t devno = MKDEV(scull_major, scull_minor); dev_t devno = MKDEV(skypopen_major, skypopen_minor);
/* Get rid of our char dev entries */ /* Get rid of our char dev entries */
if (scull_devices) { if (skypopen_devices) {
for (i = 0; i < scull_nr_devs; i++) { for (i = 0; i < skypopen_nr_devs; i++) {
cdev_del(&scull_devices[i].cdev); cdev_del(&skypopen_devices[i].cdev);
} }
kfree(scull_devices); kfree(skypopen_devices);
} }
/* And all the cloned devices */ /* And all the cloned devices */
list_for_each_entry_safe(lptr, next, &scull_c_list, list) { list_for_each_entry_safe(lptr, next, &skypopen_c_list, list) {
ret= del_timer( &lptr->device.timer_inq ); ret= del_timer( &lptr->device.timer_inq );
if (ret) printk("The inq timer was still in use...\n"); //printk( "Stopped skypopen OSS driver read timer (%dms) skype client:(%d)\n", GIOVA_SLEEP, current->tgid );
ret= del_timer( &lptr->device.timer_outq ); ret= del_timer( &lptr->device.timer_outq );
if (ret) printk("The outq timer was still in use...\n"); //printk( "Stopped skypopen OSS driver write timer (%dms) skype client:(%d)\n", GIOVA_SLEEP, current->tgid );
list_del(&lptr->list); list_del(&lptr->list);
kfree(lptr); kfree(lptr);
} }
printk("Timer uninstalling\n");
/* cleanup_module is never called if registering failed */ /* cleanup_module is never called if registering failed */
unregister_chrdev_region(devno, scull_nr_devs); unregister_chrdev_region(devno, skypopen_nr_devs);
printk("skypopen OSS driver unloaded\n");
} }
@ -278,40 +267,41 @@ void scull_cleanup_module(void)
/* /*
* Set up the char_dev structure for this device. * Set up the char_dev structure for this device.
*/ */
static void scull_setup_cdev(struct scull_dev *dev, int index) static void skypopen_setup_cdev(struct skypopen_dev *dev, int index)
{ {
int err, devno = MKDEV(scull_major, scull_minor + index); int err, devno = MKDEV(skypopen_major, skypopen_minor + index);
cdev_init(&dev->cdev, &scull_fops); cdev_init(&dev->cdev, &skypopen_fops);
dev->cdev.owner = THIS_MODULE; dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops; dev->cdev.ops = &skypopen_fops;
err = cdev_add (&dev->cdev, devno, 1); err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */ /* Fail gracefully if need be */
if (err) if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index); printk(KERN_NOTICE "Error %d adding skypopen%d", err, index);
} }
int scull_init_module(void) int skypopen_init_module(void)
{ {
int result, i; int result, i;
dev_t dev = 0; dev_t dev = 0;
printk("skypopen OSS driver loading (www.freeswitch.org)\n");
/* /*
* Get a range of minor numbers to work with, asking for a dynamic * Get a range of minor numbers to work with, asking for a dynamic
* major unless directed otherwise at load time. * major unless directed otherwise at load time.
*/ */
if (scull_major) { if (skypopen_major) {
dev = MKDEV(scull_major, scull_minor); dev = MKDEV(skypopen_major, skypopen_minor);
result = register_chrdev_region(dev, scull_nr_devs, "dsp"); result = register_chrdev_region(dev, skypopen_nr_devs, "dsp");
} else { } else {
result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, result = alloc_chrdev_region(&dev, skypopen_minor, skypopen_nr_devs,
"dsp"); "dsp");
scull_major = MAJOR(dev); skypopen_major = MAJOR(dev);
} }
if (result < 0) { if (result < 0) {
printk(KERN_WARNING "scull: can't get major %d\n", scull_major); printk(KERN_WARNING "skypopen OSS driver: can't get major %d\n", skypopen_major);
return result; return result;
} }
@ -319,26 +309,26 @@ int scull_init_module(void)
* allocate the devices -- we can't have them static, as the number * allocate the devices -- we can't have them static, as the number
* can be specified at load time * can be specified at load time
*/ */
scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL); skypopen_devices = kmalloc(skypopen_nr_devs * sizeof(struct skypopen_dev), GFP_KERNEL);
if (!scull_devices) { if (!skypopen_devices) {
result = -ENOMEM; result = -ENOMEM;
goto fail; /* Make this more graceful */ goto fail; /* Make this more graceful */
} }
memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev)); memset(skypopen_devices, 0, skypopen_nr_devs * sizeof(struct skypopen_dev));
/* Initialize each device. */ /* Initialize each device. */
for (i = 0; i < scull_nr_devs; i++) { for (i = 0; i < skypopen_nr_devs; i++) {
scull_setup_cdev(&scull_devices[i], i); skypopen_setup_cdev(&skypopen_devices[i], i);
} }
/* At this point call the init function for any friend device */ /* At this point call the init function for any friend device */
dev = MKDEV(scull_major, scull_minor + scull_nr_devs); dev = MKDEV(skypopen_major, skypopen_minor + skypopen_nr_devs);
return 0; /* succeed */ return 0; /* succeed */
fail: fail:
scull_cleanup_module(); skypopen_cleanup_module();
return result; return result;
} }
module_init(scull_init_module); module_init(skypopen_init_module);
module_exit(scull_cleanup_module); module_exit(skypopen_cleanup_module);

View File

@ -1,5 +1,5 @@
/* /*
* scull.h -- definitions for the char module * skypopen.h -- definitions for the char module
* *
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
* Copyright (C) 2001 O'Reilly & Associates * Copyright (C) 2001 O'Reilly & Associates
@ -12,55 +12,49 @@
* by O'Reilly & Associates. No warranty is attached; * by O'Reilly & Associates. No warranty is attached;
* we cannot take responsibility for errors or fitness for use. * we cannot take responsibility for errors or fitness for use.
* *
* $Id: scull.h,v 1.15 2004/11/04 17:51:18 rubini Exp $ * $Id: skypopen.h,v 1.15 2004/11/04 17:51:18 rubini Exp $
*/ */
#ifndef _SCULL_H_ #ifndef _SKYPOPEN_H_
#define _SCULL_H_ #define _SKYPOPEN_H_
#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */ #include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */
#ifndef SCULL_MAJOR #ifndef SKYPOPEN_MAJOR
#define SCULL_MAJOR 14 /* dynamic major by default */ #define SKYPOPEN_MAJOR 14 /* dynamic major by default */
#endif #endif
#ifndef SCULL_NR_DEVS #ifndef SKYPOPEN_NR_DEVS
#define SCULL_NR_DEVS 1 /* scull0 through scull3 */ #define SKYPOPEN_NR_DEVS 1 /* skypopen0 through skypopen3 */
#endif #endif
struct scull_dev { struct skypopen_dev {
struct cdev cdev; /* Char device structure */ struct cdev cdev; /* Char device structure */
wait_queue_head_t inq; /* read and write queues */ wait_queue_head_t inq; /* read and write queues */
wait_queue_head_t outq; /* read and write queues */ wait_queue_head_t outq; /* read and write queues */
struct timer_list timer_inq; struct timer_list timer_inq;
struct timer_list timer_outq; struct timer_list timer_outq;
int readable; int timer_inq_started;
int writable; int timer_outq_started;
//unsigned long read_howmany;
//unsigned long write_howmany;
//unsigned long read_sleeped_acc;
//unsigned long write_sleeped_acc;
//double read_delay; /* how much delay last time */
//double write_delay; /* how much delay last time */
}; };
/* /*
* The different configurable parameters * The different configurable parameters
*/ */
extern int scull_major; /* main.c */ extern int skypopen_major; /* main.c */
extern int scull_nr_devs; extern int skypopen_nr_devs;
/* /*
* Prototypes for shared functions * Prototypes for shared functions
*/ */
ssize_t scull_read(struct file *filp, char __user *buf, size_t count, ssize_t skypopen_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos); loff_t *f_pos);
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos); loff_t *f_pos);
int scull_ioctl(struct inode *inode, struct file *filp, int skypopen_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
#endif /* _SCULL_H_ */ #endif /* _SKYPOPEN_H_ */