led设备驱动(s3c_led.c)
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 *);//注銷設備,通常發生在驅動模塊的卸載函數中
?
<2>內核提供專門的函數用于訪問用戶空間的指針
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);? //將設備號和設備掛鉤 ? devno是設備號 //在驅動程序準備好處理設備上的操作時,調用該函數 <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 ? ? //點亮第一個燈
轉載于:https://www.cnblogs.com/zhoutian220/p/3965100.html
總結
以上是生活随笔為你收集整理的led设备驱动(s3c_led.c)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Java基础]接口基础
- 下一篇: 腾讯游戏《妖精的尾巴 力量觉醒》宣布将于