将普通字符设备驱动改造成misc设备,misc设备没有字符设备那么麻烦,以后自己写的驱动尽量用misc设备来代替
scull.c
#include
#include
#include
#include
#include
#include
#include
#include
#define SCULL_NAME "scull"
#define MAX_DATA 0x1000
struct scull_dev {
struct miscdevice misc_scull;
char data[MAX_DATA];
struct semaphore sem;
};
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("BG2BKK");
struct scull_dev *scull_devp;
int scull_open(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "open the scull device\n");
return 0;
}
int scull_release(struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "close the scull device\n");
return 0;
}
ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops)
{
unsigned long p = *f_ops;
unsigned int cnt = count;
int ret = 0;
if(down_interruptible(&scull_devp->sem))
return -ERESTARTSYS;
if(copy_to_user(buf, scull_devp->data,cnt)){
ret = -EFAULT;
} else {
*f_ops += cnt;
ret = cnt;
printk(KERN_ALERT "read %u bytes from %lu\n",cnt, p);
}
up(&scull_devp->sem);
printk(KERN_ALERT "read %d bytes\n",count);
return ret;
}
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)
{
unsigned long p = *f_ops;
unsigned int cnt = count;
int ret = 0;
if(down_interruptible(&scull_devp->sem))
return -ERESTARTSYS;
if(copy_from_user(scull_devp->data,buf, cnt))
ret = -EFAULT;
else {
*f_ops += cnt;
ret = cnt;
printk(KERN_ALERT "written %u bytes from %lu\n",cnt, p);
}
up(&scull_devp->sem);
printk(KERN_ALERT "write %d bytes\n",count);
return ret;
}
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.open = scull_open,
.release= scull_release,
.write = scull_write,
.read = scull_read,
};
int scull_init(void)
{
int result;
scull_devp = kmalloc(sizeof(struct scull_dev), GFP_KERNEL);
if(!scull_devp){
printk(KERN_ALERT "fialed to malloc a device\n");
result = -ENOMEM;
goto fail_malloc;
}
memset(scull_devp, 0 , sizeof(struct scull_dev));
scull_devp->misc_scull.name = SCULL_NAME;
scull_devp->misc_scull.minor = MISC_DYNAMIC_MINOR;
scull_devp->misc_scull.fops = &scull_fops;
result = misc_register(&scull_devp->misc_scull);
if(result){
printk(KERN_ALERT "failed to register a misc device\n");
result = -1;
goto fail_register;
}
init_MUTEX(&scull_devp->sem);
printk(KERN_ALERT "init scull device\n");
return 0;
fail_register:
kfree(scull_devp);
scull_devp = NULL;
fail_malloc:
return result;
}
void scull_cleanup(void)
{
misc_deregister(&scull_devp->misc_scull);
kfree(scull_devp);
scull_devp = NULL;
printk(KERN_ALERT "clean scull device\n");
}
module_init(scull_init);
module_exit(scull_cleanup);
测试代码
test.c
/*************************************************************************
*fileName: test.c
*description: test the myscull.c
*author: Hzc
*create time: 2007-04-20
*modify info: -
*************************************************************************/
#include
#include
#include
#include
/* device path */
char path[] = "/dev/scull";
char buf[10];
char rbuf[10];
int i;
int t = 1;
int
main ()
{
int f = open (path, O_RDWR);
for (i = 0; i < 10; i++)
{
buf[i] = i;
printf("buf[%d] = %d\n",i,buf[i]);
}
printf("write %d bytes\n",write (f, buf, 10));
// close (f);
//
//
// f = open (path, O_RDONLY);
// if (f == -1)
// {
// printf ("device open error 2!\n");
// return 1;
// }
printf ("Read the string from device...\n");
printf("read %d bytes\n",read (f, rbuf, 10));
for (i = 0; i < 10; i++)
{
printf ("%d\n", rbuf[i]);
}
close (f);
}
#KERNEL_DIR := /home/huang/linux-2.6.18/
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
obj-m := scull.o
default:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
test: test.c
gcc $< -o [email protected] -g
clean:
rm -rf *.o *.ko *~ *.order *.symvers *.markers *.mod.c
测试脚本
1 load_scull.sh
#!/bin/sh
/sbin/insmod scull.ko
2 unload_scull.sh
#!/bin/sh
/sbin/rmmod scull.ko
3 test.sh
#!/bin/sh
make clean
make
make test
sudo ./unload_scull
sudo ./load_scull
sudo ./test.o