skypopen: added a proof of concept standalone OSS audio driver (for Skype-oss clients)
This commit is contained in:
parent
009c41d460
commit
577d7b5538
|
@ -0,0 +1,43 @@
|
||||||
|
# Comment/uncomment the following line to disable/enable debugging
|
||||||
|
#DEBUG = y
|
||||||
|
LDDINC=/usr/src/linux-headers-2.6.32-26-server/include
|
||||||
|
|
||||||
|
# Add your debugging flag (or not) to CFLAGS
|
||||||
|
ifeq ($(DEBUG),y)
|
||||||
|
DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
|
||||||
|
else
|
||||||
|
DEBFLAGS = -O2 -Wall
|
||||||
|
endif
|
||||||
|
|
||||||
|
EXTRA_CFLAGS += $(DEBFLAGS)
|
||||||
|
EXTRA_CFLAGS += -I$(LDDINC)
|
||||||
|
|
||||||
|
ifneq ($(KERNELRELEASE),)
|
||||||
|
# call from kernel build system
|
||||||
|
|
||||||
|
scull-objs := main.o
|
||||||
|
|
||||||
|
obj-m := scull.o
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||||
|
PWD := $(shell pwd)
|
||||||
|
|
||||||
|
modules:
|
||||||
|
$(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
|
||||||
|
|
||||||
|
depend .depend dep:
|
||||||
|
$(CC) $(EXTRA_CFLAGS) -M *.c > .depend
|
||||||
|
|
||||||
|
|
||||||
|
ifeq (.depend,$(wildcard .depend))
|
||||||
|
include .depend
|
||||||
|
endif
|
|
@ -0,0 +1,335 @@
|
||||||
|
/*
|
||||||
|
* main.c -- the bare scull char module
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Giovanni Maruzzelli
|
||||||
|
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
|
||||||
|
* Copyright (C) 2001 O'Reilly & Associates
|
||||||
|
*
|
||||||
|
* The source code in this file can be freely used, adapted,
|
||||||
|
* and redistributed in source or binary form, so long as an
|
||||||
|
* acknowledgment appears in derived source files. The citation
|
||||||
|
* should list that the code comes from the book "Linux Device
|
||||||
|
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
|
||||||
|
* by O'Reilly & Associates. No warranty is attached;
|
||||||
|
* we cannot take responsibility for errors or fitness for use.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
|
||||||
|
#include <linux/kernel.h> /* printk() */
|
||||||
|
#include <linux/slab.h> /* kmalloc() */
|
||||||
|
#include <linux/fs.h> /* everything... */
|
||||||
|
#include <linux/errno.h> /* error codes */
|
||||||
|
#include <linux/types.h> /* size_t */
|
||||||
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/fcntl.h> /* O_ACCMODE */
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
|
||||||
|
#include <asm/system.h> /* cli(), *_flags */
|
||||||
|
#include <asm/uaccess.h> /* copy_*_user */
|
||||||
|
|
||||||
|
#include <linux/soundcard.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/hrtimer.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/hrtimer.h>
|
||||||
|
#include <linux/ktime.h>
|
||||||
|
|
||||||
|
#include "scull.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 */
|
||||||
|
|
||||||
|
module_param(scull_major, int, S_IRUGO);
|
||||||
|
module_param(scull_minor, int, S_IRUGO);
|
||||||
|
module_param(scull_nr_devs, int, S_IRUGO);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Original: Alessandro Rubini, Jonathan Corbet. Heavy modified by: Giovanni Maruzzelli");
|
||||||
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
|
|
||||||
|
static struct scull_dev *scull_devices; /* allocated in scull_init_module */
|
||||||
|
|
||||||
|
#define GIOVA_BLK 3840
|
||||||
|
#define GIOVA_SLEEP 40000
|
||||||
|
|
||||||
|
void my_timer_callback_inq( unsigned long data )
|
||||||
|
{
|
||||||
|
struct scull_dev *dev = (void *)data;
|
||||||
|
|
||||||
|
wake_up_interruptible(&dev->inq);
|
||||||
|
mod_timer( &dev->timer_inq, jiffies + msecs_to_jiffies(GIOVA_SLEEP/1000) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void my_timer_callback_outq( unsigned long data )
|
||||||
|
{
|
||||||
|
struct scull_dev *dev = (void *)data;
|
||||||
|
|
||||||
|
wake_up_interruptible(&dev->outq);
|
||||||
|
mod_timer( &dev->timer_outq, jiffies + msecs_to_jiffies(GIOVA_SLEEP/1000) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The clone-specific data structure includes a key field */
|
||||||
|
|
||||||
|
struct scull_listitem {
|
||||||
|
struct scull_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;
|
||||||
|
|
||||||
|
/* Look for a device or create one if missing */
|
||||||
|
static struct scull_dev *scull_c_lookfor_device(dev_t key)
|
||||||
|
{
|
||||||
|
struct scull_listitem *lptr;
|
||||||
|
|
||||||
|
list_for_each_entry(lptr, &scull_c_list, list) {
|
||||||
|
if (lptr->key == key)
|
||||||
|
return &(lptr->device);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not found */
|
||||||
|
lptr = kmalloc(sizeof(struct scull_listitem), GFP_KERNEL);
|
||||||
|
if (!lptr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* initialize the device */
|
||||||
|
memset(lptr, 0, sizeof(struct scull_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/1000, jiffies );
|
||||||
|
mod_timer( &lptr->device.timer_inq, jiffies + msecs_to_jiffies(GIOVA_SLEEP/1000) );
|
||||||
|
mod_timer( &lptr->device.timer_outq, jiffies + msecs_to_jiffies(GIOVA_SLEEP/1000) );
|
||||||
|
/* place it in the list */
|
||||||
|
list_add(&lptr->list, &scull_c_list);
|
||||||
|
|
||||||
|
return &(lptr->device);
|
||||||
|
}
|
||||||
|
static int scull_c_open(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
struct scull_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);
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* then, everything else is copied from the bare scull device */
|
||||||
|
filp->private_data = dev;
|
||||||
|
return 0; /* success */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scull_c_release(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Nothing to do, because the device is persistent.
|
||||||
|
* A `real' cloned device should be freed on last close
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************/
|
||||||
|
/*
|
||||||
|
* Open and close
|
||||||
|
*/
|
||||||
|
|
||||||
|
ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
|
||||||
|
loff_t *f_pos)
|
||||||
|
{
|
||||||
|
struct scull_dev *dev = filp->private_data;
|
||||||
|
|
||||||
|
DEFINE_WAIT(wait);
|
||||||
|
prepare_to_wait(&dev->inq, &wait, TASK_INTERRUPTIBLE);
|
||||||
|
schedule();
|
||||||
|
finish_wait(&dev->inq, &wait);
|
||||||
|
return count;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,
|
||||||
|
loff_t *f_pos)
|
||||||
|
{
|
||||||
|
struct scull_dev *dev = filp->private_data;
|
||||||
|
DEFINE_WAIT(wait);
|
||||||
|
prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
|
||||||
|
schedule();
|
||||||
|
finish_wait(&dev->outq, &wait);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The ioctl() implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
int scull_ioctl(struct inode *inode, struct file *filp,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
int __user *p = argp;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case OSS_GETVERSION:
|
||||||
|
return put_user(SOUND_VERSION, p);
|
||||||
|
case SNDCTL_DSP_GETBLKSIZE:
|
||||||
|
return put_user(GIOVA_BLK, p);
|
||||||
|
case SNDCTL_DSP_GETFMTS:
|
||||||
|
return put_user(28731, p);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_operations scull_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.llseek = no_llseek,
|
||||||
|
.read = scull_read,
|
||||||
|
.write = scull_write,
|
||||||
|
.ioctl = scull_ioctl,
|
||||||
|
.open = scull_c_open,
|
||||||
|
.release = scull_c_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finally, the module stuff
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The cleanup function is used to handle initialization failures as well.
|
||||||
|
* Thefore, it must be careful to work correctly even if some of the items
|
||||||
|
* have not been initialized
|
||||||
|
*/
|
||||||
|
|
||||||
|
void scull_cleanup_module(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ret;
|
||||||
|
struct scull_listitem *lptr, *next;
|
||||||
|
dev_t devno = MKDEV(scull_major, scull_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);
|
||||||
|
}
|
||||||
|
kfree(scull_devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* And all the cloned devices */
|
||||||
|
list_for_each_entry_safe(lptr, next, &scull_c_list, list) {
|
||||||
|
ret= del_timer( &lptr->device.timer_inq );
|
||||||
|
if (ret) printk("The inq timer was still in use...\n");
|
||||||
|
ret= del_timer( &lptr->device.timer_outq );
|
||||||
|
if (ret) printk("The outq timer was still in use...\n");
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the char_dev structure for this device.
|
||||||
|
*/
|
||||||
|
static void scull_setup_cdev(struct scull_dev *dev, int index)
|
||||||
|
{
|
||||||
|
int err, devno = MKDEV(scull_major, scull_minor + index);
|
||||||
|
|
||||||
|
cdev_init(&dev->cdev, &scull_fops);
|
||||||
|
dev->cdev.owner = THIS_MODULE;
|
||||||
|
dev->cdev.ops = &scull_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int scull_init_module(void)
|
||||||
|
{
|
||||||
|
int result, i;
|
||||||
|
dev_t dev = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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");
|
||||||
|
} else {
|
||||||
|
result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,
|
||||||
|
"dsp");
|
||||||
|
scull_major = MAJOR(dev);
|
||||||
|
}
|
||||||
|
if (result < 0) {
|
||||||
|
printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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) {
|
||||||
|
result = -ENOMEM;
|
||||||
|
goto fail; /* Make this more graceful */
|
||||||
|
}
|
||||||
|
memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));
|
||||||
|
|
||||||
|
/* Initialize each device. */
|
||||||
|
for (i = 0; i < scull_nr_devs; i++) {
|
||||||
|
scull_setup_cdev(&scull_devices[i], i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point call the init function for any friend device */
|
||||||
|
dev = MKDEV(scull_major, scull_minor + scull_nr_devs);
|
||||||
|
return 0; /* succeed */
|
||||||
|
|
||||||
|
fail:
|
||||||
|
scull_cleanup_module();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(scull_init_module);
|
||||||
|
module_exit(scull_cleanup_module);
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* scull.h -- definitions for the char module
|
||||||
|
*
|
||||||
|
* Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
|
||||||
|
* Copyright (C) 2001 O'Reilly & Associates
|
||||||
|
*
|
||||||
|
* The source code in this file can be freely used, adapted,
|
||||||
|
* and redistributed in source or binary form, so long as an
|
||||||
|
* acknowledgment appears in derived source files. The citation
|
||||||
|
* should list that the code comes from the book "Linux Device
|
||||||
|
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
|
||||||
|
* 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 $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SCULL_H_
|
||||||
|
#define _SCULL_H_
|
||||||
|
|
||||||
|
#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */
|
||||||
|
|
||||||
|
#ifndef SCULL_MAJOR
|
||||||
|
#define SCULL_MAJOR 14 /* dynamic major by default */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SCULL_NR_DEVS
|
||||||
|
#define SCULL_NR_DEVS 1 /* scull0 through scull3 */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct scull_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;
|
||||||
|
//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
|
||||||
|
*/
|
||||||
|
extern int scull_major; /* main.c */
|
||||||
|
extern int scull_nr_devs;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes for shared functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
ssize_t scull_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,
|
||||||
|
loff_t *f_pos);
|
||||||
|
int scull_ioctl(struct inode *inode, struct file *filp,
|
||||||
|
unsigned int cmd, unsigned long arg);
|
||||||
|
|
||||||
|
#endif /* _SCULL_H_ */
|
|
@ -0,0 +1,142 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Sample init script for the a driver module <rubini@linux.it>
|
||||||
|
|
||||||
|
DEVICE="scull"
|
||||||
|
SECTION="misc"
|
||||||
|
|
||||||
|
# The list of filenames and minor numbers: $PREFIX is prefixed to all names
|
||||||
|
PREFIX="scull"
|
||||||
|
FILES=" 0 0 1 1 2 2 3 3 priv 16
|
||||||
|
pipe0 32 pipe1 33 pipe2 34 pipe3 35
|
||||||
|
single 48 uid 64 wuid 80"
|
||||||
|
|
||||||
|
INSMOD=/sbin/insmod; # use /sbin/modprobe if you prefer
|
||||||
|
|
||||||
|
function device_specific_post_load () {
|
||||||
|
true; # fill at will
|
||||||
|
}
|
||||||
|
function device_specific_pre_unload () {
|
||||||
|
true; # fill at will
|
||||||
|
}
|
||||||
|
|
||||||
|
# Everything below this line should work unchanged for any char device.
|
||||||
|
# Obviously, however, no options on the command line: either in
|
||||||
|
# /etc/${DEVICE}.conf or /etc/modules.conf (if modprobe is used)
|
||||||
|
|
||||||
|
# Optional configuration file: format is
|
||||||
|
# owner <ownername>
|
||||||
|
# group <groupname>
|
||||||
|
# mode <modename>
|
||||||
|
# options <insmod options>
|
||||||
|
CFG=/etc/${DEVICE}.conf
|
||||||
|
|
||||||
|
# kernel version, used to look for modules
|
||||||
|
KERNEL=`uname -r`
|
||||||
|
|
||||||
|
#FIXME: it looks like there is no misc section. Where should it be?
|
||||||
|
MODDIR="/lib/modules/${KERNEL}/kernel/drivers/${SECTION}"
|
||||||
|
if [ ! -d $MODDIR ]; then MODDIR="/lib/modules/${KERNEL}/${SECTION}"; fi
|
||||||
|
|
||||||
|
# Root or die
|
||||||
|
if [ "$(id -u)" != "0" ]
|
||||||
|
then
|
||||||
|
echo "You must be root to load or unload kernel modules"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Read configuration file
|
||||||
|
if [ -r $CFG ]; then
|
||||||
|
OWNER=`awk "\\$1==\"owner\" {print \\$2}" $CFG`
|
||||||
|
GROUP=`awk "\\$1==\"group\" {print \\$2}" $CFG`
|
||||||
|
MODE=`awk "\\$1==\"mode\" {print \\$2}" $CFG`
|
||||||
|
# The options string may include extra blanks or only blanks
|
||||||
|
OPTIONS=`sed -n '/^options / s/options //p' $CFG`
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Create device files
|
||||||
|
function create_files () {
|
||||||
|
cd /dev
|
||||||
|
local devlist=""
|
||||||
|
local file
|
||||||
|
while true; do
|
||||||
|
if [ $# -lt 2 ]; then break; fi
|
||||||
|
file="${DEVICE}$1"
|
||||||
|
mknod $file c $MAJOR $2
|
||||||
|
devlist="$devlist $file"
|
||||||
|
shift 2
|
||||||
|
done
|
||||||
|
if [ -n "$OWNER" ]; then chown $OWNER $devlist; fi
|
||||||
|
if [ -n "$GROUP" ]; then chgrp $GROUP $devlist; fi
|
||||||
|
if [ -n "$MODE" ]; then chmod $MODE $devlist; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove device files
|
||||||
|
function remove_files () {
|
||||||
|
cd /dev
|
||||||
|
local devlist=""
|
||||||
|
local file
|
||||||
|
while true; do
|
||||||
|
if [ $# -lt 2 ]; then break; fi
|
||||||
|
file="${DEVICE}$1"
|
||||||
|
devlist="$devlist $file"
|
||||||
|
shift 2
|
||||||
|
done
|
||||||
|
rm -f $devlist
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load and create files
|
||||||
|
function load_device () {
|
||||||
|
|
||||||
|
if [ -f $MODDIR/$DEVICE.o ]; then
|
||||||
|
devpath=$MODDIR/$DEVICE.o
|
||||||
|
else if [ -f ./$DEVICE.o ]; then
|
||||||
|
devpath=./$DEVICE.o
|
||||||
|
else
|
||||||
|
devpath=$DEVICE; # let insmod/modprobe guess
|
||||||
|
fi; fi
|
||||||
|
if [ "$devpath" != "$DEVICE" ]; then
|
||||||
|
echo -n " (loading file $devpath)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $INSMOD $devpath $OPTIONS; then
|
||||||
|
MAJOR=`awk "\\$2==\"$DEVICE\" {print \\$1}" /proc/devices`
|
||||||
|
remove_files $FILES
|
||||||
|
create_files $FILES
|
||||||
|
device_specific_post_load
|
||||||
|
else
|
||||||
|
echo " FAILED!"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Unload and remove files
|
||||||
|
function unload_device () {
|
||||||
|
device_specific_pre_unload
|
||||||
|
/sbin/rmmod $DEVICE
|
||||||
|
remove_files $FILES
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
echo -n "Loading $DEVICE"
|
||||||
|
load_device
|
||||||
|
echo "."
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
echo -n "Unloading $DEVICE"
|
||||||
|
unload_device
|
||||||
|
echo "."
|
||||||
|
;;
|
||||||
|
force-reload|restart)
|
||||||
|
echo -n "Reloading $DEVICE"
|
||||||
|
unload_device
|
||||||
|
load_device
|
||||||
|
echo "."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {start|stop|restart|force-reload}"
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
Loading…
Reference in New Issue