标签:style blog http io os 使用 ar strong 文件
s3c_led.c分析:http://blog.csdn.net/hurry_liu/article/details/8770206
1,注册设备号
int register_chrdev_region(dev_t from, unsigned count, const char *name)
动态分配设备号
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
// 无法再安装驱动前创建设备文件,因为安装前没有分配设备号;安装驱动后,从/proc/devices中查询设备号
释放设备号
void unregister_chrdev_region(dev_t from, unsigned count)
2,重要的结构体
<1>struct file <linux/fs.h>
//系统中每个打开的文件在内核空间都有一个关联的struct file。打开文件时创建,关闭时创建
重要成员:
loff_t f_pos //文件读写位置
struct file_operations *f_op
void *private_data;
<2>struct file_operations
<linux/fs.h>
//操作函数指针的集合,每个指针表示用户空间能对设备文件进行的操作(其中的各函数是最主要的工作)
重要成员:
int (*open)(struct inode *, struct file *) //初始化设备和标明次设备号
void (*release)(struct inode *,struct file *) //关闭设备
ssize_t (*read)(sruct file *flip, char __user *buff, size_t count, loff_t *offp)
//从设备中读取数据到用户空间,offp文件当前的访问位置
//buff指向数据缓存, 是指向用户空间,不能被内核代码直接引用 count传输的数据量 (这两个参数由用户空间提供)
ssize_t (*write)(sruct file *, const char __user *buff, size_t, loff_t *) //将数据传递给驱动程序
int (*ioctl)(struct inode *, srtuct file *, unsigned int, unsigned long) //控制设备
off_t (*llseek)(struct file *, loff_t, int)
<3>struct inode结构
//记录文件的物理上的信息,一个文件只有一个inode结构
重要成员:
dev_t i_rdev; //设备号(对于表示设备文件的inode)
struct *cdev *i_cdev; //当inode指向字符设备文件时
可以从inode中获取主次设备号
MAJOR(dev_t dev)
MINOR(dev_t dev)
MKDEV(int major,int minor) //通过主次设备号来生成dev_t
<4>struct cdev结构 <linux/cdev.h>
//内核使用cdev结构体描述字符设备
重要成员:
struct module *owner; //所属模块
const struct file_operations *ops;
dev_t dev; //设备号
3,一些函数
<1>用来对cdev结构操作的函数:
void cdev_init(struct cdev *, const struct file_operations *);
//初始化,建立cdev和file_operation 之间的连接
struct cdev *cdev_alloc(void); //动态申请一个cdev内存
void cdev_put(struct cdev *p); //释放
int cdev_add(struct cdev *, dev_t, unsigned); //注册设备,通常发生在驱动模块的加载函数中
void cdev_del(struct cdev *);//注销设备,通常发生在驱动模块的卸载函数中
int copy_from_user(void *to, const void __user *from,int n) write()
int copt_to_user(void __user *to, const void *from, int n) read()
<3>宏定义request_mem_region和ioremap include/linux/ioport.h
request_mem_region(S3C_GPB_BASE, S3C_GPB_LEN,DEV_NAME))
/* 申请内存。注意:这里的内存是FL2440中实际的物理内存,他对应了与LED的相关的寄存器
占用起始物理地址S3C_GPB_BASE之后的连续S3C_GPB_LEN字节大小空间
该函数并没有做实际性的映射工作,只是告诉内核要使用一块内存地址,声明占有,也方便内核管理这些资源。*/
fl2440_gpb_membase=ioremap(S3C_GPB_BASE, S3C_GPB_LEN) ioremap()在mm/ioremap.c中定义,返回void型指针
//主要是检查传入地址的合法性,建立页表(包括访问权限),完成物理地址到虚拟地址的转换。
release_mem_region(S3C_GPB_BASE, S3C_GPB_LEN)
void iounmap(fl2440_gpb_membase);
//一些宏定义
__raw_writel((val),(reg)+s3c_gpb_membase)
__raw_readll((reg)+s3c_gpb_membase) //读操作和写操作寄存器
4,led字符设备
//字符设备用struct cdev来描述;struct cdev *led_cdev;
加载模块int __init s3c_led_init():
<1>硬件初始化:s3c_hw_init():
申请内存request_mem_region()--> 建立物理内存到虚拟内存的映射ioremap()-->初始化硬件设备
<2>申请设备号:
<3>为cdev分配内存(定义为指针式需要)
led_cdev = cdev_alloc();
//可以将cdev结构嵌入到自己的设备特定结构中
<4>初始化cdev
led_cdev->owner = THIS_MODULE;
cdev_init(led_cdev, &led_fops); //将led_cdev和file_operations挂钩
<5>,添加cdev
result = cdev_add(led_dev, devno, dev_count);
//将设备号和设备挂钩
//在驱动程序准备好处理设备上的操作时,调用该函数
<6>出错处理[函数]
卸载模块s3c_led_exit():
<1>调用s3c_hw_term() :
关闭led-->释放内存release_mem_region()-->解除映射关系iounmap()
<2>注销设备:cdev_del()
<3>释放设备号:unregister_chrdev_region()
设备操作的实现
定义struct file_operations led_fops =
{
.owner = THIS_MODULE;
.open = led_open;
.release = led_release;
.unlocked_ioctl = led_ioctl;
};
三,arm开发板上
tftp -gr s3c_hello.ko 192.168.1.3
insmod,rmmod //加载和卸载模块命令(root权限)
lsmod //列举内核模块及引用计数 cat /proc/modules
insmod s3c_led.ko
cat /proc/drivers
cd dev/
mknod -m666 c led0 252 0
mknod -m666 c led1 252 1
mknod -m666 c led2 252 2
mknod -m666 c led3 252 3
./test_led /dev/led0 1 //点亮第一个灯
led设备驱动(s3c_led.c)
标签:style blog http io os 使用 ar strong 文件
原文地址:http://www.cnblogs.com/zhoutian220/p/3965100.html