鏈接:https://pan.baidu.com/s/1V0E9IHSoLbpiWJsncmFgdA?pwd=1688
提取碼:1688
教學內容:
1、內核模塊的簡單框架:
__init __exit執(zhí)行完后就釋放空間
簡單框架:包含三個部分
1)模塊初始化和模塊退出函數(shù)
2)注冊模塊函數(shù)
3)模塊許可
//***************************************************
#include <linux/module.h>?? ?/*module_init()*/
#include <linux/kernel.h>??????? /* printk() */
#include <linux/init.h>??????????? /* __init __exit */
static int __init myModule_init(void) ? //紅色名可自定義,使用static保證只能在本文件中調用
{
?????? /* Module init code */
?????? PRINTK("myModule_init\n");
?????? return 0;
}
static void __exit myModule_exit(void)????????? //紅色名可自定義
{
?????? /* Module exit code */
?????? PRINTK("myModule_exit\n");
?????? return;
}
module_init(myModule_init);??? //注冊模塊函數(shù)
module_exit(myModule_exit);?? //注冊
MODULE_AUTHOR("zhangda");?????? /*模塊作者,可選*/
MODULE_LICENSE("GPL"); ????????????????? /*模塊許可證明,描述內核模塊的許可權限,必須*/
MODULE_DESCRIPTION("A simple Hello World Module"); /*模塊說明,可選*/
//******************************************
makefile的編寫
驅動有兩種方式,一為內核樹之內,一為內核樹以外,前者有點復雜,涉及到將驅動放到合適的內核樹目錄,修改相應的Makefile以及Kconfig文件,不過,天下無難易之事,為之,難亦不難了;后者所做的勞動就不用那么多了。這個Makfile只適合于后者。此外,內核的Makefile跟一般的應用程序的Makefile不太一樣,就像驅動程序跟應用程序,內核頭文件跟應用程序頭文件等等,沒必然關系,或者說是兩碼事,兩者不能混為一談。再有一點,驅動是跟內核打交道的,你的系統(tǒng)中必須有一個內核源代碼。
//*******************************************
obj-m := module_test.o ?? //目標文件
ifneq ($(KERNELRELEASE),)
KERNELDIR = $(KERNELRELEASE)
else
KERNELDIR = /home/zhangda/linux_kernel/linux-2.6.34??? //內核源代碼地址
endif
$(PWD) := $(shell pwd)
default:
?????? $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
?????? rm -rf *.o *.mod.c *.order *.symvers
clean:
?????? rm -rf *.ko
//***************************************************
2、模塊間符號的相互引用
?????? 在模塊編程或內核編程中經常會遇到需要調用其它模塊中符號的情況,在內核中專門有一張表來管理這些符號,可以通過 cat/proc/kallsyms查看該內核符號表我們也可以自己編寫一個模塊,并導出其符號供其它模塊使用。
//****************************************
//****************************************
上圖1,通過EXPORT_SYMBOL導出模塊符號,方便圖2使用符號函數(shù)。由于是給文件外函數(shù)使用,所以不能使用static修飾函數(shù)。
3、linux字符設備驅動結構
描述字符設備的結構體(詳細參考內核和宋寶華的設備驅動書)
//**************************
struct cdev {
?????? struct kobject kobj;???? //內嵌kobject 對象
?????? struct module *owner;????? //所屬模塊
?????? const struct file_operations *ops;??? //文件操作結構
?????? struct list_head list;???
?????? dev_t dev;??? //設備號
?????? unsigned int count;
};
//*****************************
設備號為32位,高12位為主設備號,低20位為次設備號;
此結構體描述了字符設備的信息,其中struct file_operations *ops結構體是向用戶提高SPI接口函數(shù)的重要結構體。
file_operations :
//*******************************************
#include <linux/fs.h>
struct file_operations {
?????? struct module *owner;
// 指向擁有該結構的模塊的指針,避免正在操作時被卸載,一般為初始化為THIS_MODULES
?????? loff_t (*llseek) (struct file *, loff_t, int);
?????? ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//讀接口
?????? ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//寫接口
?????? ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
?????? ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
?????? int (*readdir) (struct file *, void *, filldir_t);
?????? unsigned int (*poll) (struct file *, struct poll_table_struct *);
?????? int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);//io控制接口
?????? long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
?????? long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
?????? int (*mmap) (struct file *, struct vm_area_struct *);
?????? int (*open) (struct inode *, struct file *);//打開接口
?????? int (*flush) (struct file *, fl_owner_t id);
?????? int (*release) (struct inode *, struct file *);//關閉接口
?????? int (*fsync) (struct file *, struct dentry *, int datasync);
?????? int (*aio_fsync) (struct kiocb *, int datasync);
?????? int (*fasync) (int, struct file *, int);
?????? int (*lock) (struct file *, int, struct file_lock *);
?????? ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
?????? unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
?????? int (*check_flags)(int);
?????? int (*flock) (struct file *, int, struct file_lock *);
?????? ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
?????? ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
?????? int (*setlease)(struct file *, long, struct file_lock **);
};
//****************************************
字符驅動設備的注冊:
int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
(內聯(lián)函數(shù))
第一個參數(shù):主設備號,int型,0為內核自動分配
第二個參數(shù):設備名
第三個參數(shù):file_operations的結構體地址
返回分配的主設備號,大于0,錯誤返回負值。
void unregister_chrdev(MAJOR_NR, DRIVER_NAME);(內聯(lián)函數(shù))
第一個參數(shù):分配的主設備號
第二個參數(shù):設備名
//*********************
MAJOR_NR = register_chrdev(MAJOR_NR, DRIVER_NAME, &GPG_fops);
if(MAJOR_NR < 0)
{
?????? PRINTK("register char device fail!\n");
?????? return MAJOR_NR;
}
unregister_chrdev(MAJOR_NR, DRIVER_NAME);
//*****************************
自動創(chuàng)建節(jié)點:
#include<linux/device.h>
static struct class *my_class;
my_class= class_create(THIS_MODULE, "my_class");
device_create(my_class,NULL,dev_n,NULL,"hello");
注意:dev_n = MKDEV(MAJOR_NR, MINOR_NR);
設備卸載刪除類和設備節(jié)點
device_destroy(my_class,dev_n);
class_destroy(my_class);
//******************************
my_class=class_create(THIS_MODULE,"udev_gpg");
device_create(my_class,NULL, MKDEV(MAJOR_NR, MINOR_NR), NULL,DRIVER_NAME);
device_destroy(my_class,MKDEV(MAJOR_NR, MINOR_NR));
class_destroy(my_class);
//******************************
用戶態(tài)與內核態(tài)數(shù)據的交互:
用戶應用程序與驅動程序分屬于不同的進程空間,因此二者之間的數(shù)據應當采用以下函數(shù)進行交換
#include <asm/uaccess.h>
copy_to_user(user_buffer, kernel_buffer, n)
//從內核空間拷貝n字節(jié)數(shù)據到用戶空間
copy_from_user(kernel_buffer, user_buffer, n)
//從用戶空間拷貝n字節(jié)數(shù)據到內核空間
put_user(kernel_value, user_buffer)
//從內核空間拷貝一數(shù)據變量到用戶空間
get_user(kernel_value, user_buffer)
//從用戶空間拷貝一數(shù)據變量到內核空間
(內核空間數(shù)據可是任意類型)
字符設備驅動的流程:
1)、建立__init和__exit函數(shù);并注冊這2個函數(shù)module_init,module_exit,聲明MODULE_LICENSE;
2)、創(chuàng)建file_operations結構體,并指明函數(shù)地址;
3)、字符設備驅動的注冊,在__init函數(shù)里面注冊,在__exit注銷;
4)、在__init函數(shù)里面完成節(jié)點創(chuàng)建,在__exit注銷節(jié)點;
5)、編寫file_operations結構體中的函數(shù),具體功能可以結合裸機驅動編寫功能
例如:
//***********************************************
#include <linux/module.h>???????????? /*module_init()*/
#include <linux/kernel.h> /* printk() */
#include <linux/init.h>????? /* __init __exit */
#include <linux/fs.h>??????? /* file_operation */
#include <asm/uaccess.h> /* copy_to_user, copy_from_user */??????
#include <linux/device.h>? /*class ,class_create ,device_create 等*/
#define GPGCON????? (*(volatile unsigned long *)S3C2410_GPGCON) //虛擬地址
#define GPGDAT???? (*(volatile unsigned long *)S3C2410_GPGDAT)
#define GPGUP????? (*(volatile unsigned long *)S3C2410_GPGUP)
#include "my_ioctl.h"
#define MAJOR_NAME "my_ioctl_drv"
static int MAJOR_NR = 0;
static int MINOR_NR = 0;
struct class *myclass;
static int io_open(struct inode *inode, struct file *filp)
{???? }
static int io_release(struct inode *inode, struct file *filp)
{???? }
static ssize_t io_read(struct file *filp, char *buf,size_t count, loff_t *f_pos)
{???? }
static ssize_t io_write(struct file *filp, const char *buf,size_t count, loff_t *f_pos)
{???? }
static int io_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)
{???? }
static struct file_operations ioctl_file_opt = {
?????? .owner = THIS_MODULE,
?????? .write = io_write,
?????? .read = io_read,
?????? .ioctl = io_ioctl,
?????? .open = io_open,
?????? .release = io_release,
};
static int __init my_inctl_init(void)
{
?????? PRINTK("come in init\n");
?????? MAJOR_NR = register_chrdev(MAJOR_NR, DRIVER_NAME, &ioctl_file_opt);
?????? if(MAJOR_NR < 0)
?????? {
???????????? PRINTK("register char device fail!\n");
???????????? return MAJOR_NR;
?????? }
?????? myclass=class_create(THIS_MODULE,"my_ioctl");
?????? device_create(myclass,NULL, MKDEV(MAJOR_NR, MINOR_NR), NULL,"my_ioctl");
?????? return 0;
}
static void __exit my_inctl_exit(void)
{
?????? if(MAJOR_NR > 0)
?????? {
???????????? unregister_chrdev(MAJOR_NR, DRIVER_NAME);
???????????? device_destroy(myclass,MKDEV(MAJOR_NR, MINOR_NR));
???????????? class_destroy(myclass);
?????? }
?????? PRINTK("exit ioctl\n");
?????? return;
}
module_init(my_inctl_init);
module_exit(my_inctl_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("HB");
//***************************************************
配置s3c2410的文件
cp arch/arm/configs/s3c2410_defconfig .config文章來源:http://www.zghlxwxcb.cn/news/detail-831672.html
make menuconfig(執(zhí)行s3c2410配置)文章來源地址http://www.zghlxwxcb.cn/news/detail-831672.html
到了這里,關于嵌入式培訓機構四個月實訓課程筆記(完整版)-Linux ARM驅動編程第五天-ARM Linux編程之字符設備驅動(物聯(lián)技術666)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!