- 论坛徽章:
- 0
|
我刚接触驱动开发。学习资料是Linux Device Drivers 3rd。我根据书中的代码,稍微改写了一下,结果试验时就出现以下情况了。
求高手指导!!
1. 编译通过,用complete.init start加载模块时,Failed,但是,查看、proc/devices文件显示该模块已经加载上了,有major number。但是,
用complete.init stop卸载该模块时,出现module complete is in use的提示,不能卸载。此时,我再用complete.init start加载模块时,还是
Failed了,说是file exists,说明该模块已经加载上了。怎么办?
2. 情形如下
user 1:
cat /dev/complete
(block)
user 2:
echo "hello" > complete
(唤醒user1的cat程序,但是没有任何显示,同时,用户从root变为test(自动变的。。。)不懂了。
另外,附上源码。附件中我已经附上文件。
求高手指导。- #ifndef _COMPLETEL_H_
- #define _COMPLETEL_H_
- struct complete_dev {
- void* data; /* Pointer to first quantum set */
- struct cdev cdev; /* Char device structure */
- };
- void complete_cleanup(void);
- #endif /* _COMPLETEL_H_ */
复制代码
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/sched.h> /* current and everything */
- #include <linux/kernel.h> /* printk() */
- #include <linux/fs.h> /* everything... */
- #include <linux/types.h> /* size_t */
- #include <linux/cdev.h>
- #include <linux/errno.h> /* error codes */
- #include <linux/completion.h>
- #include <asm/uaccess.h> /* copy_*_user */
- #include "complete.h"
- MODULE_LICENSE("Dual BSD/GPL");
- MODULE_AUTHOR("James Chen");
- static int complete_major = 0;
- struct complete_dev* complete_device;
- DECLARE_COMPLETION(comp);
- int complete_trim(struct complete_dev *dev)
- {
- if (dev->data)
- {
- kfree(dev->data);
- dev->data = NULL;
- }
- return 0;
- }
- int complete_open(struct inode *inode, struct file *filp)
- {
-
- /*struct complete_dev *dev; */ /* device information */
- /*
- dev = container_of(inode->i_cdev, struct complete_dev, cdev);
- */
- filp->private_data = complete_device; /* for other methods */
- /* now trim to 0 the length of the device if open was write-only */
- if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
- complete_trim(complete_device); /* ignore errors */
- }
- return 0; /* success */
- }
- int complete_release(struct inode *inode, struct file *filp)
- {
- return 0;
- }
- ssize_t complete_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
- {
- struct complete_dev *dev = filp->private_data;
- printk(KERN_DEBUG "process %i (%s) going to sleep\n",
- current->pid, current->comm);
- wait_for_completion(&comp);
- printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
- copy_to_user(buf, dev->data, count);
- return 0; /* EOF */
- }
- ssize_t complete_write (struct file *filp, const char __user *buf, size_t count,
- loff_t *pos)
- {
- struct complete_dev *dev = filp->private_data;
- printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
- current->pid, current->comm);
- complete(&comp);
- copy_from_user(dev->data, buf, count);
- return count; /* succeed, to avoid retrial */
- }
- struct file_operations complete_fops = {
- .owner = THIS_MODULE,
- .open = complete_open,
- .release = complete_release,
- .read = complete_read,
- .write = complete_write,
- };
- int complete_init(void)
- {
- int result;
- dev_t devno;
- /*
- * Register your major, and accept a dynamic number
- */
- /*int devno = MKDEV(complete_major, 0);*/
- result = register_chrdev(complete_major, "complete", &complete_fops);
- if (result < 0)
- goto fail;
- if (complete_major == 0)
- complete_major = result; /* dynamic */
- devno = MKDEV(complete_major, 0);
-
- complete_device= kmalloc(1 * sizeof(struct complete_dev), GFP_KERNEL);
- if (!complete_device) {
- result = -ENOMEM;
- goto fail; /* Make this more graceful */
- }
- complete_device->data = kmalloc(1024, GFP_KERNEL);
- if (!complete_device->data) {
- result = -ENOMEM;
- goto fail; /* Make this more graceful */
- }
- memset(complete_device, 0,1 * sizeof(struct complete_dev));
- memset(complete_device->data, 0, 1024);
-
- cdev_init(&complete_device->cdev, &complete_fops);
- complete_device->cdev.owner = THIS_MODULE;
- complete_device->cdev.ops = &complete_fops;
- result = cdev_add (&complete_device->cdev, devno, 1);
- /* Fail gracefully if need be */
- if (result)
- {
- goto fail;
- }
-
- return 0;
- fail:
- complete_cleanup();
- return result;
- }
- void complete_cleanup(void)
- {
- if (complete_device)
- {
- complete_trim(complete_device);
- cdev_del(&complete_device->cdev);
- kfree(complete_device);
- }
-
- unregister_chrdev(complete_major, "complete");
- }
- module_init(complete_init);
- module_exit(complete_cleanup);
复制代码 init脚本如下
#!/bin/bash
# Sample init script for the a driver module <rubini@linux.it>
DEVICE="complete"
SECTION="misc"
# The list of filenames and minor numbers: $PREFIX is prefixed to all names
PREFIX="complete"
FILES=" 0 0 "
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.ko ]; then
devpath=$MODDIR/$DEVICE.ko
else if [ -f ./$DEVICE.ko ]; then
devpath=./$DEVICE.ko
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 |
|