最近学习《linxu设备驱动开发详解》中的关于字符设备驱动第六章的内容,记录如下,一.globalmem.c文件如下/*
* A globalmem driver as an example of char device drivers
*
* The initial developer of the original code is Barry Song
*
. All Rights Reserved.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GLOBALMEM_SIZE 0x1000 /*全局内存最大4K字节*/
#define MEM_CLEAR 0x1 /*清0全局内存*/
#define GLOBALMEM_MAJOR 250 /*预设的globalmem的主设备号*/
static int globalmem_major = GLOBALMEM_MAJOR;
/*globalmem设备结构体*/
struct globalmem_dev {
struct cdev cdev; /*cdev结构体*/
unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/
};
struct globalmem_dev *globalmem_devp; /*设备结构体指针*/
/*文件打开函数*/
int globalmem_open(struct inode *inode, struct file *filp)
{
/*将设备结构体指针赋值给文件私有数据指针*/
filp->private_data = globalmem_devp;
return 0;
}
/*文件释放函数*/
int globalmem_release(struct inode *inode, struct file *filp)
{
return 0;
}
/* ioctl设备控制函数 */
static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
int cmd, unsigned long arg)
{
struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/
switch (cmd) {
case MEM_CLEAR:
memset(dev->mem, 0, GLOBALMEM_SIZE);
printk(KERN_INFO "globalmem is set to zero\n");
break;
default:
return - EINVAL;
}
return 0;
}
/*读函数*/
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if (p >= GLOBALMEM_SIZE)
return 0;
if (count > GLOBALMEM_SIZE - p)
count = GLOBALMEM_SIZE - p;
/*内核空间->用户空间*/
if (copy_to_user(buf, (void *)(dev->mem + p), count)) {
ret = - EFAULT;
} else {
*ppos += count;
ret = count;
printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
}
return ret;
}
/*写函数*/
static ssize_t globalmem_write(struct file *filp, const char __user *buf,
size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if (p >= GLOBALMEM_SIZE)
return 0;
if (count > GLOBALMEM_SIZE - p)
count = GLOBALMEM_SIZE - p;
/*用户空间->内核空间*/
if (copy_from_user(dev->mem + p, buf, count))
ret = - EFAULT;
else {
*ppos += count;
ret = count;
printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
}
return ret;
}
/* seek文件定位函数 */
static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
{
loff_t ret = 0;
switch (orig) {
case 0: /*相对文件开始位置偏移*/
if (offset < 0) {
ret = - EINVAL;
break;
}
if ((unsigned int)offset > GLOBALMEM_SIZE) {
ret = - EINVAL;
break;
}
filp->f_pos = (unsigned int)offset;
ret = filp->f_pos;
break;
case 1: /*相对文件当前位置偏移*/
if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {
ret = - EINVAL;
break;
}
if ((filp->f_pos + offset) < 0) {
ret = - EINVAL;
break;
}
filp->f_pos += offset;
ret = filp->f_pos;
break;
default:
ret = - EINVAL;
break;
}
return ret;
}
/*文件操作结构体*/
static const struct file_operations globalmem_fops = {
.owner = THIS_MODULE,
.llseek = globalmem_llseek,
.read = globalmem_read,
.write = globalmem_write,
.ioctl = globalmem_ioctl,
.open = globalmem_open,
.release = globalmem_release,
};
/*初始化并注册cdev*/
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
int err, devno = MKDEV(globalmem_major, index);
cdev_init(&dev->cdev, &globalmem_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);
if (err)
printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}
/*设备驱动模块加载函数*/
int globalmem_init(void)
{
int result;
dev_t devno = MKDEV(globalmem_major, 0);
/* 申请设备号*/
if (globalmem_major)
result = register_chrdev_region(devno, 1, "globalmem");
else { /* 动态申请设备号 */
result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
globalmem_major = MAJOR(devno);
}
if (result < 0)
return result;
/* 动态申请设备结构体的内存*/
globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
if (!globalmem_devp) { /*申请失败*/
result = - ENOMEM;
goto fail_malloc;
}
memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
globalmem_setup_cdev(globalmem_devp, 0);
return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}
/*模块卸载函数*/
void globalmem_exit(void)
{
cdev_del(&globalmem_devp->cdev); /*注销cdev*/
kfree(globalmem_devp); /*释放设备结构体内存*/
unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/
}
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_LICENSE("Dual BSD/GPL");
module_param(globalmem_major, int, S_IRUGO);
module_init(globalmem_init);
module_exit(globalmem_exit);
二.makefile文件如下(因为是在主机上运行的,由于ubuntu系统自带的有内核,所以也可以放在那个内核代码中使用 make moduls来产生.ko文件,这样的话,就不需要自制Makfile了,不过这个事先要你会才行)
KVERS = $(shell uname -r)
# Kernel modules
obj-m += globalmem.o
# Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
三,make一下,生成.ko文件
四.最好切换用户到root模式,su
五.下面的操作,如果你学过内核移植的话,很好操作的,代码如下。
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# insmod globalmem.ko
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# lsmod
Module Size Used by
globalmem 11140 0
binfmt_misc 16776 1
vboxvideo 10368 1
drm 96296 2 vboxvideo
agpgart 42696 1 drm
vboxvfs 41800 0
bridge 56340 0
stp 10500 1 bridge
bnep 20224 2
nfsd 227756 13
lockd 74156 1 nfsd
nfs_acl 11136 1 nfsd
auth_rpcgss 42144 1 nfsd
sunrpc 195424 13 nfsd,lockd,nfs_acl,auth_rpcgss
exportfs 12544 1 nfsd
input_polldev 11912 0
video 25360 0
output 11008 1 video
lp 17156 0
ppdev 15620 0
psmouse 61972 0
snd_intel8x0 37532 3
pcspkr 10496 0
serio_raw 13316 0
snd_ac97_codec 112292 1 snd_intel8x0
ac97_bus 9856 1 snd_ac97_codec
snd_pcm_oss 46336 0
snd_mixer_oss 22656 1 snd_pcm_oss
snd_pcm 82948 3 snd_intel8x0,snd_ac97_codec,snd_pcm_oss
snd_seq_dummy 10756 0
snd_seq_oss 37760 0
snd_seq_midi 14336 0
snd_rawmidi 29696 1 snd_seq_midi
snd_seq_midi_event 15104 2 snd_seq_oss,snd_seq_midi
i2c_piix4 18448 0
snd_seq 56880 6 snd_seq_dummy,snd_seq_oss,snd_seq_midi,snd_seq_midi_event
joydev 18368 0
snd_timer 29704 2 snd_pcm,snd_seq
snd_seq_device 14988 5 snd_seq_dummy,snd_seq_oss,snd_seq_midi,snd_rawmidi,snd_seq
snd 62628 16 snd_intel8x0,snd_ac97_codec,snd_pcm_oss,snd_mixer_oss,snd_pcm,snd_seq_oss,snd_rawmidi,snd_seq,snd_timer,snd_seq_device
soundcore 15200 1 snd
snd_page_alloc 16904 2 snd_intel8x0,snd_pcm
vboxguest 160776 7 vboxvfs
parport_pc 40100 0
parport 42220 3 lp,ppdev,parport_pc
usbhid 42336 0
e1000 130500 0
fbcon 46112 0
tileblit 10752 1 fbcon
font 16384 1 fbcon
bitblit 13824 1 fbcon
softcursor 9984 1 bitblit
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6#
可以看到系统中已经globalmem 驱动模块,
六。建立节点:
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# mknod /dev/globalmem c 250 0
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# ls -l /dev/
total 0
crw-rw----+ 1 root audio 14, 12 2011-04-26 18:58 adsp
crw-rw----+ 1 root audio 14, 4 2011-04-26 18:58 audio
drwxr-xr-x 2 root root 620 2011-04-26 18:58 block
drwxr-xr-x 3 root root 60 2011-04-26 18:58 bus
lrwxrwxrwx 1 root root 3 2011-04-26 18:58 cdrom -> sr0
drwxr-xr-x 2 root root 3080 2011-04-26 18:58 char
crw------- 1 root root 5, 1 2011-04-26 18:58 console
lrwxrwxrwx 1 root root 11 2011-04-26 18:58 core -> /proc/kcore
crw-rw---- 1 root root 10, 60 2011-04-26 18:58 cpu_dma_latency
drwxr-xr-x 5 root root 100 2011-04-26 18:58 disk
drwxr-xr-x 2 root root 60 2011-04-26 18:58 dri
crw-rw----+ 1 root audio 14, 3 2011-04-26 18:58 dsp
lrwxrwxrwx 1 root root 3 2011-04-26 18:58 dvd -> sr0
crw-rw---- 1 root root 10, 63 2011-04-26 18:58 ecryptfs
lrwxrwxrwx 1 root root 13 2011-04-26 18:58 fd -> /proc/self/fd
crw-rw-rw- 1 root root 1, 7 2011-04-26 18:58 full
crw-rw-rw-+ 1 root fuse 10, 229 2011-04-26 18:58 fuse
crw-r--r-- 1 root root 250, 0 2011-04-26 20:45 globalmem
crw-rw---- 1 root root 251, 0 2011-04-26 18:58 hidraw0
crw-rw---- 1 root root 10, 228 2011-04-26 18:58 hpet
prw------- 1 root root 0 2011-04-26 18:58 initctl
........
7.查看读写是否成功
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# echo "hello world" >/dev/globalmem
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6# cat /dev/globalmem
hello world
root@lihacker-laptop:/home/lihacker/develop/svn/ldd6410-read-only/training/kernel/drivers/globalmem/ch6#
可以看到,可以写入和读出全局内存中的数据,证明还是成功的。。。。
阅读(1743) | 评论(0) | 转发(2) |