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
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
DEBFLAGS = -O2 -Wall
endif
@ -15,9 +15,9 @@ EXTRA_CFLAGS += -I$(LDDINC)
ifneq ($(KERNELRELEASE),)
# call from kernel build system
scull-objs := main.o
skypopen-objs := main.o
obj-m := scull.o
obj-m := skypopen.o
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) 2001 Alessandro Rubini and Jonathan Corbet
@ -41,33 +41,32 @@
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include "scull.h" /* local definitions */
#include "skypopen.h" /* local definitions */
/*
* Our parameters which can be set at load time.
*/
int scull_major = SCULL_MAJOR;
int scull_minor = 3;
int scull_nr_devs = SCULL_NR_DEVS; /* number of bare scull devices */
int skypopen_major = SKYPOPEN_MAJOR;
int skypopen_minor = 3;
int skypopen_nr_devs = SKYPOPEN_NR_DEVS; /* number of bare skypopen devices */
module_param(scull_major, int, S_IRUGO);
module_param(scull_minor, int, S_IRUGO);
module_param(scull_nr_devs, int, S_IRUGO);
module_param(skypopen_major, int, S_IRUGO);
module_param(skypopen_minor, 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");
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_SLEEP 20
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);
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 )
{
struct scull_dev *dev = (void *)data;
struct skypopen_dev *dev = (void *)data;
//dev->writable=1;
wake_up_interruptible(&dev->outq);
mod_timer( &dev->timer_outq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) );
}
/* The clone-specific data structure includes a key field */
struct scull_listitem {
struct scull_dev device;
struct skypopen_listitem {
struct skypopen_dev device;
dev_t key;
struct list_head list;
};
/* The list of devices, and a lock to protect it */
static LIST_HEAD(scull_c_list);
static spinlock_t scull_c_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(skypopen_c_list);
static spinlock_t skypopen_c_lock = SPIN_LOCK_UNLOCKED;
/* 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)
return &(lptr->device);
}
/* not found */
lptr = kmalloc(sizeof(struct scull_listitem), GFP_KERNEL);
lptr = kmalloc(sizeof(struct skypopen_listitem), GFP_KERNEL);
if (!lptr)
return NULL;
/* initialize the device */
memset(lptr, 0, sizeof(struct scull_listitem));
memset(lptr, 0, sizeof(struct skypopen_listitem));
lptr->key = key;
init_waitqueue_head(&lptr->device.inq);
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_outq, my_timer_callback_outq, (long int)lptr );
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_outq, jiffies + msecs_to_jiffies(GIOVA_SLEEP) );
init_waitqueue_head(&lptr->device.inq);
init_waitqueue_head(&lptr->device.outq);
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 );
printk( "Starting skypopen OSS driver read timer (%dms) skype client:(%d)\n", GIOVA_SLEEP, current->tgid );
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) );
/* place it in the list */
list_add(&lptr->list, &scull_c_list);
list_add(&lptr->list, &skypopen_c_list);
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;
if (!current->pid) {
printk("Process \"%s\" has no pid\n", current->comm);
return -EINVAL;
}
key = current->pid;
/* look for a scullc device in the list */
spin_lock(&scull_c_lock);
dev = scull_c_lookfor_device(key);
spin_unlock(&scull_c_lock);
/* look for a skypopenc device in the list */
spin_lock(&skypopen_c_lock);
dev = skypopen_c_lookfor_device(key);
spin_unlock(&skypopen_c_lock);
if (!dev)
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;
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.
@ -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)
{
struct scull_dev *dev = filp->private_data;
struct skypopen_dev *dev = filp->private_data;
DEFINE_WAIT(wait);
prepare_to_wait(&dev->inq, &wait, TASK_INTERRUPTIBLE);
schedule();
finish_wait(&dev->inq, &wait);
//memset(buf, 255, count);
//wait_event_interruptible(dev->inq, dev->readable);
//dev->readable=0;
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)
{
struct scull_dev *dev = filp->private_data;
struct skypopen_dev *dev = filp->private_data;
DEFINE_WAIT(wait);
prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
schedule();
finish_wait(&dev->outq, &wait);
//wait_event_interruptible(dev->outq, dev->writable);
//dev->writable=0;
return count;
}
@ -203,7 +192,7 @@ ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
* 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)
{
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,
.llseek = no_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_c_open,
.release = scull_c_release,
.read = skypopen_read,
.write = skypopen_write,
.ioctl = skypopen_ioctl,
.open = skypopen_c_open,
.release = skypopen_c_release,
};
/*
@ -243,34 +232,34 @@ struct file_operations scull_fops = {
* have not been initialized
*/
void scull_cleanup_module(void)
void skypopen_cleanup_module(void)
{
int i;
int ret;
struct scull_listitem *lptr, *next;
dev_t devno = MKDEV(scull_major, scull_minor);
struct skypopen_listitem *lptr, *next;
dev_t devno = MKDEV(skypopen_major, skypopen_minor);
/* Get rid of our char dev entries */
if (scull_devices) {
for (i = 0; i < scull_nr_devs; i++) {
cdev_del(&scull_devices[i].cdev);
if (skypopen_devices) {
for (i = 0; i < skypopen_nr_devs; i++) {
cdev_del(&skypopen_devices[i].cdev);
}
kfree(scull_devices);
kfree(skypopen_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 );
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 );
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);
kfree(lptr);
}
printk("Timer uninstalling\n");
/* 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.
*/
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.ops = &scull_fops;
dev->cdev.ops = &skypopen_fops;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
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;
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
* major unless directed otherwise at load time.
*/
if (scull_major) {
dev = MKDEV(scull_major, scull_minor);
result = register_chrdev_region(dev, scull_nr_devs, "dsp");
if (skypopen_major) {
dev = MKDEV(skypopen_major, skypopen_minor);
result = register_chrdev_region(dev, skypopen_nr_devs, "dsp");
} else {
result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,
result = alloc_chrdev_region(&dev, skypopen_minor, skypopen_nr_devs,
"dsp");
scull_major = MAJOR(dev);
skypopen_major = MAJOR(dev);
}
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;
}
@ -319,26 +309,26 @@ int scull_init_module(void)
* allocate the devices -- we can't have them static, as the number
* can be specified at load time
*/
scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);
if (!scull_devices) {
skypopen_devices = kmalloc(skypopen_nr_devs * sizeof(struct skypopen_dev), GFP_KERNEL);
if (!skypopen_devices) {
result = -ENOMEM;
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. */
for (i = 0; i < scull_nr_devs; i++) {
scull_setup_cdev(&scull_devices[i], i);
for (i = 0; i < skypopen_nr_devs; i++) {
skypopen_setup_cdev(&skypopen_devices[i], i);
}
/* 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 */
fail:
scull_cleanup_module();
skypopen_cleanup_module();
return result;
}
module_init(scull_init_module);
module_exit(scull_cleanup_module);
module_init(skypopen_init_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 O'Reilly & Associates
@ -12,55 +12,49 @@
* by O'Reilly & Associates. No warranty is attached;
* 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_
#define _SCULL_H_
#ifndef _SKYPOPEN_H_
#define _SKYPOPEN_H_
#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */
#ifndef SCULL_MAJOR
#define SCULL_MAJOR 14 /* dynamic major by default */
#ifndef SKYPOPEN_MAJOR
#define SKYPOPEN_MAJOR 14 /* dynamic major by default */
#endif
#ifndef SCULL_NR_DEVS
#define SCULL_NR_DEVS 1 /* scull0 through scull3 */
#ifndef SKYPOPEN_NR_DEVS
#define SKYPOPEN_NR_DEVS 1 /* skypopen0 through skypopen3 */
#endif
struct scull_dev {
struct skypopen_dev {
struct cdev cdev; /* Char device structure */
wait_queue_head_t inq; /* read and write queues */
wait_queue_head_t outq; /* read and write queues */
struct timer_list timer_inq;
struct timer_list timer_outq;
int readable;
int writable;
//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 */
int timer_inq_started;
int timer_outq_started;
};
/*
* The different configurable parameters
*/
extern int scull_major; /* main.c */
extern int scull_nr_devs;
extern int skypopen_major; /* main.c */
extern int skypopen_nr_devs;
/*
* 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);
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);
int scull_ioctl(struct inode *inode, struct file *filp,
int skypopen_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
#endif /* _SCULL_H_ */
#endif /* _SKYPOPEN_H_ */