//这是一个最简单的字符设备驱动,入门专用.
//scull1.h
#ifndef _SCULL1_H
#define _SCULL1_H
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/version.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/errno.h>
#define SCULL_MAJOR 0
#define SCULL_SIZE 0x1000
#define SCULL_CMD_CLEAR 0x01
struct scull_dev{
struct cdev cDev;
char mem[SCULL_SIZE];
};
int scull_open(struct inode* inode,struct file* filp);
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_release(struct inode* inode,struct file* filp);
#endif
//scull1.c
#include "scull1.h"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Aaron.xu");
MODULE_DESCRIPTION("hello driver test");
MODULE_VERSION("0.1");
static int scull_major = SCULL_MAJOR;
struct scull_dev mydev;
struct file_operations scull_fops =
{
.owner = THIS_MODULE,
.open = scull_open,
.release = scull_release,
.read = scull_read,
.write = scull_write,
};
static void scull_setup_cdev(void)
{
int err;
dev_t devid = MKDEV(scull_major,0);
cdev_init(&mydev.cDev,&scull_fops);
printk(KERN_INFO "&mydev.cDev.ops:%p \n",&mydev.cDev.ops);
mydev.cDev.owner = THIS_MODULE;
mydev.cDev.ops = &scull_fops;
printk(KERN_INFO "&mydev.cDev.ops:%p \n",&mydev.cDev.ops);
err = cdev_add(&mydev.cDev,devid,1);
if (err!=0)
{
printk(KERN_ERR "cdev_add Error,err:%d \n",err);
}
}
static int scull_init(void)
{
int err;
dev_t devid = MKDEV(scull_major,0);
if (scull_major)
{
err = register_chrdev_region(devid,1,"scull1");
}
else
{
err = alloc_chrdev_region(&devid,0,1,"scull1");
scull_major = MAJOR(devid);
}
if (err !=0 )
{
printk(KERN_ERR "register chrdev region error,err:%d \n",err);
return err;
}
scull_setup_cdev();
return 0;
}
static void scull_exit(void)
{
cdev_del(&mydev.cDev);
unregister_chrdev_region(MKDEV(scull_major,0),1);
}
int scull_open(struct inode* inode,struct file* filp)
{
filp->private_data = &mydev;
return 0;
}
ssize_t scull_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
unsigned long pos = *f_pos;
int err = 0;
int ret = 0;
struct scull_dev* p_mydev = filp->private_data;
if (pos >= SCULL_SIZE)
{
return 0;
}
if (count > (SCULL_SIZE - pos) )
{
count = SCULL_SIZE - pos;
}
err = copy_to_user(buf,p_mydev->mem+pos,count);
if (err !=0 )
{
ret = -EFAULT;
}
else
{
*f_pos += count;
ret = count;
printk(KERN_INFO "read %d byte(s) from %lu \n",ret,pos);
}
return ret;
}
ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
unsigned long pos = *f_pos;
int err = 0;
int ret = 0;
struct scull_dev* p_mydev = filp->private_data;
if (pos >= SCULL_SIZE)
{
return 0;
}
if (count > (SCULL_SIZE - pos) )
{
count = SCULL_SIZE - pos;
}
err = copy_from_user(p_mydev->mem+pos,buf,count);
if (err !=0 )
{
ret = -EFAULT;
}
else
{
*f_pos += count;
ret = count;
printk(KERN_INFO "write %d byte(s) from %lu \n",ret,pos);
}
return ret;
}
int scull_release(struct inode* inode,struct file* filp)
{
return 0;
}
module_init(scull_init);
module_exit(scull_exit);
//Makefile
obj-m +=scull1.o
KERNELDIR := /usr/src/linux-headers-2.6.32-5-686
PWD :=$(shell pwd)
.PHONY: test clean all
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versionsm *.order *.symvers .tmp_versions
test:
insmod ./scull1.ko
rmmod scull1
dmesg -c
//创建设备节点
make_dev_node
#!/bin/bash
DEVICE="scull1"
MAJOR=`awk "\\$2==\"$DEVICE\" {print \\$1}" /proc/devices`
cmd="mknod /dev/$DEVICE c $MAJOR 0"
echo $cmd
`$cmd`