Linux设备驱动程序学习笔记:(1) 字符设备驱动入门1
//
这是一个最简单的字符设备驱动,入门专用.
// 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`
// 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`