3-文字デバイスフレーム_デバイスファイルの作成
13430 ワード
文字デバイスフレーム:文字デバイスクラスには、同じ種類の文字デバイスが含まれています./sys/class 各デバイスにはstruct cdevが記述されている:
ユーザースペースアプリケーション(使用デバイスファイル名-mknod"/dev/デバイスファイル名"cプライマリデバイス番号セカンダリデバイス番号) カーネルスペース
関数のロード1、申請設備番号——dev_t devno = mar_num << 20 | min_numまたは呼び出しMKDEP(プライマリ・デバイス番号、セカンダリ・デバイス番号) 2、登録デバイス番号*静的登録:register_chrdev_region(devno、登録する必要があるデバイスの数、デバイスファイル名);動的登録:alloc_chrdev_region(devno、開始次デバイス番号、次デバイス番号個数、デバイスファイル名);静的登録の利点は、デバイスの起動に要する時間が短いことであるが、デバイス番号と競合しやすい*cdev=kzalloc(sizeof(struct cdev)、GFP_KERNEL); 4、初期化文字デバイスcdev_init(&cdev,&op); 5、文字デバイスをカーネルに追加cdev_add(&cdev,devno,1);
アンインストール関数 6、cdev_del(&cdev); 7、設備番号の抹消 unregister_chrdev_region(devno、ログアウトされた文字デバイスの数);
著作権の回避
デバイスノード記述を自動的に作成すると、デバイスノードがデバイスファイルになります.デバイスノードの自動作成について説明する前に、sysfsというファイルシステムのデフォルトが/sysディレクトリにマウントされていることを理解する必要があります.カーネル内の情報(デバイス番号など)をユーザ空間に導出、モジュール名で命名された/ueventファイルに/sys/module/ディレクトリ名(モジュール名で命名された)/ueventファイルに情報を格納インタフェースをユーザ空間とカーネル空間に提供する役割を果たす.ユーザースペースにはudevという小さなプログラムがあり、電源を入れるたびにすべてのueventファイルを巡り、デバイス番号を抽出して/dev/ディレクトリの下でデバイスファイルを作成します.作成が完了するとudevがブロックされ、ドライバを新しくロードするとsysfsは新しいロードされたドライバ情報をユーザースペースにエクスポートし、新しいueventファイルを生成します.ueventファイルが生成されるとudevが起動します.
デバイスファイルインタフェースの作成機能:/devディレクトリの下でデバイスファイル を自動的に作成するパラメータ1:クラス構造体ポインタcls パラメータ2:親デバイスのデバイスポインタ、NULL を書く必要がない場合パラメータ3:デバイス番号 パラメータ4:NULL を書かない場合、いくつかのプライベートデータパラメータ5:デバイスファイル名ですが、必ずしも完全なデバイスファイル名ではありません.6番目のパラメータを使用しない場合、5番目のパラメータは完全なデバイスファイル名です. が6番目のパラメータを使用する場合、デバイスファイル名は5番目と6番目の2つのパラメータから構成される.
パラメータ6: を省略する必要はない.
ユーザースペースシステム呼び出しインタフェースopen上位層のopenは、システム呼び出し番号によってシステム呼び出しソースコード に一致する.
カーネルスペースシステムコール カーネル内: 1、 2、 3、
アプリケーション層も下層のいわゆる読み書きも,アプリケーション層の観点から見られる.読み:カーネル空間からユーザ空間 へデータが流れる.書き込み:反対 読み取り:機能:カーネル空間のデータをユーザ空間 にコピーするパラメータ1:最初のパラメータカーネルが作成されます. パラメータ2:ユーザ空間アドレス パラメータ3:カーネル空間からユーザ空間に伝達するデータサイズ パラメータ4:オフセット 戻り値:正常に0、失敗した戻りエラーコード パラメータ1:ユーザ空間のアドレス パラメータ2:カーネル空間のアドレス パラメータ3:ユーザ空間へのコピーが必要なバイト数 戻り値:正常に0、失敗した戻りエラーコード パラメータ1:カーネル空間のアドレス パラメータ2:ユーザ空間のあるアドレス パラメータ3:ユーザ空間がカーネル空間に伝達するデータのバイト数 アプリケーション層: パラメータ1:ファイル記述子 パラメータ2:コマンド パラメータ3:必要でなければ省略し、必要であれば通常変数でもアドレスでも可能 パラメータ3が構造を渡す必要がある場合、このとき、この構造のヘッダアドレスを渡す必要があります.また、駆動層がデータを取得するにはcopy_を呼び出す必要があります.from_userまたはcopy_to_user パラメータ3が基本タイプのデータを伝達するだけである場合、駆動層は、第3のパラメータによってアプリケーション層のデータを直接受信する.
駆動層: パラメータ2:コマンド パラメータ3:受信アプリケーションから送信されたデータ
仮想アドレス=ioremap(物理アドレス、物理アドレス占有バイト数)
練習:
Makefile
head.h
led.c
led.c
struct file_operations *ops = &hello_op
cdev_init(&cdev,&hello_op)
dev_t *dev = &devno
cdev_add(&cdev,devno,1)
ユーザースペース
|
vfs (struct cdev struct file_operations)
|
= MKDEV( , );
//struct cdev cdev;
struct cdev *cdev;
3、 file_operations
struct file_operations op = {
.owner = THIS_MODULE,// ,
.open = hello_open
};
関数のロード
アンインストール関数
著作権の回避
デバイスノード記述を自動的に作成すると、デバイスノードがデバイスファイルになります.
struct class *cls;
cls = class_create(THIS_MODULE,"hello");
hello , /sys/class hello, hello
デバイスファイルインタフェースの作成
struct device *devs;
devs = device_create( , ,);
struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
sturct inode
{
umode_t i_mode
struct cdev *i_cdev cdev
}
inode , , 。inode 。
struct file {
const struct file_operations *f_op; file_operations
}
, struct file
int (*open) (struct inode *, struct file *);
open : , , ,
ユーザースペース
カーネルスペース
vi arch/arm/include/uapi/asm/unistd.h
33 #define __NR_open (__NR_SYSCALL_BASE+ 5)
5
__Nr_open
713 __SYSCALL(__NR_open, sys_open)
sys_open
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
return do_sys_open(AT_FDCWD, filename, flags, mode);
||
\/
struct file *f = do_filp_open(dfd, tmp, &op);
||
\/
filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
||
\/
3181 error = do_last(nd, &path, file, op, &opened, pathname);
||
\/
2882 goto finish_open;
||
\/
794 error = do_dentry_open(file, open, current_cred());
||
\/
727 open = f->f_op->open;
f->f_op->open; , .open = hello_open
アプリケーション層も下層のいわゆる読み書きも,アプリケーション層の観点から見られる.
size_t read(struct file *,char __user *,size_t ,loff_t *)
{
copy_to_user();
}
static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n);
size_t write(struct file *,const char __user *,size_t ,loff_t *)
{
copy_from_user();
}
static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
int ioctl(int fd,int cmd,...);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
cmd 32 , 4
8 8 2 14
( , )
仮想アドレス=ioremap(物理アドレス、物理アドレス占有バイト数)
練習:
Makefile
ifeq ($(KERNELRELEASE),)
#KERNELDIR ?= /lib/modules/$(shell uname -r)/build
KERNELDIR ?= /home/linux/linux-3.14/
PWD ?= $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
cp *.ko /rootfs
app:
arm-none-linux-gnueabi-gcc test.c -o test
cp test /rootfs
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
.PHONY: modules clean
else
obj-m += led.o
endif
head.h
#ifndef __HEAD_H_
#define __HEAD_H_
#define MAGIC 'l'
#define LED2_ON _IO(MAGIC,0)
#define LED2_OFF _IO(MAGIC,1)
#define LED3_ON _IO(MAGIC,2)
#define LED3_OFF _IO(MAGIC,3)
#define LED4_ON _IO(MAGIC,4)
#define LED4_OFF _IO(MAGIC,5)
#define LED5_ON _IO(MAGIC,6)
#define LED5_OFF _IO(MAGIC,7)
#define LEDALL_ON _IO(MAGIC,8)
#define LEDALL_OFF _IO(MAGIC,9)
#endif
led.c
#include
#include
#include
#include
#include
#include
#include
#include "head.h"
#define LED_MAJOR 505
#define LED_MINOR 0
#define LED_NUM 1
#define LED_NAME "ledx"
#define CLS_NAME "led_cls"
#define DEV_NAME "led"
#define GPX2CON 0x11000c40
#define GPX1CON 0x11000c20
#define GPF3CON 0x114001e0
volatile unsigned int * gpx2con;
volatile unsigned int * gpx1con;
volatile unsigned int * gpf3con;
volatile unsigned int * gpx2dat;
volatile unsigned int * gpx1dat;
volatile unsigned int * gpf3dat;
dev_t devno;
struct cdev led_cdev;
struct class * cls;
int led_open (struct inode *inode, struct file *file)
{
printk(" led_open!!!
");
return 0;
}
int led_release (struct inode *inode, struct file *file)
{
printk(" led_release!!!
");
return 0;
}
long led_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
{
printk(" led_ioctl !!!
");
switch (cmd)
{
case LED2_ON:
*gpx2dat = (*gpx2dat)|(0x1 << 7);
*gpx1dat = (*gpx1dat)&~(0x1 << 0);
*gpf3dat = (*gpf3dat)&~(0x3 << 4);
break;
case LED2_OFF:
*gpx2dat = (*gpx2dat)&~(0x1 << 7);
*gpx1dat = (*gpx1dat)&~(0x1 << 0);
*gpf3dat = (*gpf3dat)&~(0x3 << 4);
break;
case LED3_ON:
*gpx2dat = (*gpx2dat)&~(0x1 << 7);
*gpx1dat = (*gpx1dat)|(0x1 << 0);
*gpf3dat = (*gpf3dat)&~(0x3 << 4);
break;
case LED3_OFF:
*gpx2dat = (*gpx2dat)&~(0x1 << 7);
*gpx1dat = (*gpx1dat)&~(0x1 << 0);
*gpf3dat = (*gpf3dat)&~(0x3 << 4);
break;
case LED4_ON:
*gpx2dat = (*gpx2dat)&~(0x1 << 7);
*gpx1dat = (*gpx1dat)&~(0x1 << 0);
*gpf3dat = (*gpf3dat)|(0x1 << 4);
*gpf3dat = (*gpf3dat)&~(0x1 << 5);
break;
case LED4_OFF:
*gpx2dat = (*gpx2dat)&~(0x1 << 7);
*gpx1dat = (*gpx1dat)&~(0x1 << 0);
*gpf3dat = (*gpf3dat)&~(0x3 << 4);
break;
case LED5_ON:
*gpx2dat = (*gpx2dat)&~(0x1 << 7);
*gpx1dat = (*gpx1dat)&~(0x1 << 0);
*gpf3dat = (*gpf3dat)|(0x1 << 5);
*gpf3dat = (*gpf3dat)&~(0x1 << 4);
break;
case LED5_OFF:
*gpx2dat = (*gpx2dat)&~(0x1 << 7);
*gpx1dat = (*gpx1dat)&~(0x1 << 0);
*gpf3dat = (*gpf3dat)&~(0x3 << 4);
break;
case LEDALL_ON:
*gpx2dat = (*gpx2dat)|(0x1 << 7);
*gpx1dat = (*gpx1dat)|(0x1 << 0);
*gpf3dat = (*gpf3dat)|(0x3 << 4);
break;
case LEDALL_OFF:
*gpx2dat = (*gpx2dat)&~(0x1 << 7);
*gpx1dat = (*gpx1dat)&~(0x1 << 0);
*gpf3dat = (*gpf3dat)&~(0x3 << 4);
break;
default:
printk(" fault cmd!!!
");
return -EFAULT;
break;
}
return 0;
}
struct file_operations led_fops={
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.unlocked_ioctl = led_ioctl,
};
int __init led_init(void)
{
int ret;
printk(" led_init!!!
");
devno = MKDEV(LED_MAJOR,LED_MINOR);
ret = register_chrdev_region(devno,LED_NUM,LED_NAME);
if (ret < 0)
{
printk(" register_chrdev_region fail!!!
");
return -EFAULT;
}
printk(" register_chrdev_region success!!!
");
printk(" major=%d,minor=%d
",MAJOR(devno),MINOR(devno));
cdev_init(&led_cdev,&led_fops);
led_cdev.owner = THIS_MODULE;
cdev_add(&led_cdev,devno,LED_NUM);
cls = class_create(THIS_MODULE,CLS_NAME);
if (IS_ERR(cls))
{
printk(" class_create fail!!!
");
return -EFAULT;
}
device_create(cls,NULL,devno,NULL,DEV_NAME);
gpx2con = ioremap(GPX2CON,0x4);
if (NULL == gpx2con)
{
printk(" gpx2con ioremap fail!!!
");
return -EFAULT;
}
gpx1con = ioremap(GPX1CON,0x4);
if (NULL == gpx1con )
{
printk(" gpx1con ioremap fail!!!
");
return -EFAULT;
}
gpf3con = ioremap(GPF3CON,0x4);
if (NULL == gpf3con)
{
printk(" gpf3con ioremap fail!!!
");
return -EFAULT;
}
gpx2dat = gpx2con + 1;
//gpx2dat = ioremap(0x1100c44,0x4);
gpx1dat = gpx1con + 1;
gpf3dat = gpf3con + 1;
*gpx2con = ((*gpx2con)&~(0xf << 28))|(0x1 << 28);
*gpx1con = ((*gpx1con)&~(0xf << 0))|(0x1 << 0);
*gpf3con = ((*gpf3con)&~(0xff <<16))|(0x11 << 16);
*gpx2dat =(*gpx2dat)|(0x1 << 7);
*gpx1dat =(*gpx1dat)|(0x1 << 0);
*gpf3dat =(*gpf3dat)|(0x3 << 4);
return 0;
}
module_init(led_init);
void __exit led_exit(void)
{
printk(" led_exit!!!
");
iounmap(gpf3con);
iounmap(gpx1con);
iounmap(gpx2con);
device_destroy(cls,devno);
class_destroy(cls);
cdev_del(&led_cdev);
unregister_chrdev_region(devno,LED_NUM);
}
module_exit(led_exit);
MODULE_LICENSE("GPL");
led.c
#include
#include
#include
#include "head.h"
int main(int argc, char *argv[])
{
int fd;
fd = open("/dev/led",O_RDWR);
if (fd < 0)
{
printf(" open fail!!!
");
return -1;
}
for(;;)
{
ioctl(fd,LED2_ON);
sleep(1);
ioctl(fd,LED3_ON);
sleep(1);
ioctl(fd,LED4_ON);
sleep(1);
ioctl(fd,LED5_ON);
sleep(1);
ioctl(fd,LEDALL_ON);
sleep(1);
}
close(fd);
return 0;
}