skypopen: tweaking the OSS audio driver
This commit is contained in:
parent
1d668e25ab
commit
eafd7e5e15
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_ */
|
Loading…
Reference in New Issue