Linux でのキャラクター デバイスとは何ですか?
Linux キャラクター デバイスには次のものが含まれます: 1. マウスはコンピュータの外部入力デバイスであり、コンピュータ ディスプレイ システムの垂直および水平座標を配置するためのインジケータです; 2. キーボードは、コンピュータを操作するために使用される命令です。コンピュータ装置およびデータ入力装置 3. シリアルポート端末、コンピュータのシリアルポートを使用して接続される端末装置 4. 制御端末 5. コンソールなど
#このチュートリアルの動作環境: linux7.3 システム、Dell G3 コンピューター。
linux キャラクター デバイス
キャラクター デバイスは、Linux の 3 つの主要なデバイスの 1 つです (他の 2 つはブロック デバイスとネットワーク デバイスです)。これらはすべて、ファイル ノードの形式でファイル システムの /dev ディレクトリに表示されます (crw--w---- 1 root tty 4, 0 July 11 09:11 tty0 ここで、c はキャラクター デバイス タイプを表します)。
キャラクターデバイスとは、マウス、キーボード、シリアルポートデバイス、モデムなど、バッファリングせずに直接読み書きできるデバイスを指します。ブロックデバイスとの違いは、基本ユニットであることです。文字の操作はバイトです。
#キャラクターデバイスの分類
キャラクターデバイスには、主にコンソールやキーボードなどの制御端末機器やシリアル端末機器が含まれます。キャラクタ端末装置は、機能やハードウェアの違いにより次のように分類されます。- シリアルポート端末 (/dev/ttSn): コンピュータのシリアルポート、シリアルポートを使用して接続される端末装置。デバイスのデータ送信方式は同一文字の 8 ビット単行送信で、コマンドラインに echo 'hello world' > /dev/ttyS0 と入力して、入力を対応するデバイスに書き込みます。
- 疑似端末 (/dev/ttyp、/dev/ptyp): 最下層には実際のハードウェア デバイスがないことに対応し、端末を提供するために使用されます。ホストへのネットワーク ログインなど、他のプログラム用のスタイル インターフェイス ネットワーク サーバーとシェル プログラム間の端末インターフェイス。
- 制御端末 (/dev/tty): メイン デバイス番号は 5 です。プロセス制御端末はプロセスに関連付けられています。たとえば、ログイン シェル プロセスは端末 /dev を使用します。 /てぃ。
- コンソール (/dev/ttyn,/dev/consol): コンピューターの入出力用のモニターです。コンソールにログインすると tty1 が使用され、ubuntu グラフィカル インターフェイスでは tty1 が使用されます。 tty7 。
- その他のタイプ: 現在の Linux には、ISIDIN デバイスの /dev/ttyIn デバイスなど、さまざまなデバイス用の他のタイプのデバイス特殊ファイルが多数あります。
#キャラクター デバイスの性質と特性
- キャラクター デバイスはデバイスの一部ですファイルシステム 基盤となるハードウェアが上位層に提供する論理的なデバイスファイルに相当します データポート(データレジスタ)をファイルに接続するようなものです デバイスドライバはファイルを直接操作するため、直接読み取りや読み取りを実行しますポート上での書き込み操作。また、キャラクター デバイス ドライバーは、ファイルとして、open()、close()、write()、read() などのファイルの基本操作も実装する必要があります。もちろん、ターミナル リダイレクト操作もサポートされています。
- キャラクタデバイスファイルファイルはシングルバイト単位で読み書きされるため、ハードウェアバッファを設定する必要はありません。デバイスは、オペレーティング システムによってバイト ストリームとしてアクセスされます。バイト ストリームは、ハードウェア ポートとファイル システムの間に送信パイプを設定するようなもので、バイトはパイプを通じて 1 つずつ送信され、リーダーとライターの両方に提供されます。このストリーミング機能はドライバーにバッファー キューとして実装されます。例: コンソール構造
-
struct tty_struct { struct termios termios; int pgrp; int stopped; void (*write)(struct tty_struct * tty); struct tty_queue read_q; //读队列 struct tty_queue write_q; //写队列 struct tty_queue secondary; //tty辅助队列(存放规格化后的字符) };
ログイン後にコピー
- キャラクターデバイス内の読み取り/書き込みバッファーキューは、キャラクターデバイス番号によって識別されます。キャラクタ デバイス番号は、メジャー デバイス番号とマイナー デバイス番号で構成されます。たとえば、/dev/ttyS0 のデバイス番号は (4, 64) です。メジャー デバイス番号は、デバイスに対応するドライバを識別し、カーネルはデバイスとドライバーを 1 対 1 で照合するメジャー デバイス番号。一般に、マイナー デバイス番号は、ドライバーがデバイスの詳細を区別するために内部で使用するコードに使用されます。他の部分では使用されません。カーネルの。
#キャラクター デバイスがアプリケーション層に反映される方法 cat /proc/devices
コマンドは、現在のシステム内のすべてのキャラクター デバイスとブロック デバイスを表示できます。Linux では、ファイルを接続するときにデバイスもファイルに抽象化され、キャラクター デバイスとブロックに対応するファイルを表示できます。デバイス。 たとえば、これらは 2 つのシリアル ポート デバイス ファイルです。詳細情報を表示するには、ls -l を使用します。
デバイスにアクセスするにはどうすればよいですか?
设备号
dev_t dev = MKDEV(major,minor)
major = MAJOR(dev)
minor = MINOR(dev)
设备号由major和minor 组成,总共32位,高12位为major,低20位为minor。每一个设备号都唯一对应着一个cdev结构体。
注册字符设备首先要申请设备号,可以一次批量的申请多个设备号(相同的major,依次递增的minor)。
如果没有指定主设备号的话就使用如下函数来申请设备号:int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
baseminor:起始的minor值。
count:一共申请几个设备号。申请到的设备号在(MKDEV(major,baseminor) ~ MKDEV(major,baseminor+count)) 范围内。
(自动申请设备号的原理,其实是传递一个major = 0,然后由内核分配一个空闲的设备号返回)
如果给定了设备的主设备号和次设备号就使用如下所示函数来注册设备号即可:int register_chrdev_region(dev_t from, unsigned count, const char *name)
释放设备号:void unregister_chrdev_region(dev_t from, unsigned count)
字符设备结构体 cdev
//include/linux/cdev.h struct cdev { struct kobject kobj; struct module *owner; const struct file_operations *ops; struct list_head list; dev_t dev; unsigned int count; };
常用
申请一个cdev 内存:struct cdev *cdev_alloc(void);
初始化cdev->ops,即cdev->ops = &xxx_file_operation; :void cdev_init(struct cdev *, const struct file_operations *);
将填充好的cdev 实例,添加到cdev 链表。意味着向内核注册一个字符设备:int cdev_add(struct cdev *, dev_t, unsigned);
//dev_t:添加cdev时必须要,传递一个dev_t,并且它与cdev是唯一对应的。
cdev_add 添加过程中会绑定cdev 与dev_t。
从内核删除一个字符设备:void cdev_del(struct cdev *);
不常用
增加cdev 调用计数:void cdev_put(struct cdev *p);
总结:注册字符设备的主要流程就是,申请设备号dev_t,创建一个cdev、初始化cdev (cdev->ops)、向内核添加 cdev(同时会绑定cdev 与dev_t)。
如果你嫌这些步骤太麻烦的话,内核还提供了一个函数可以一步到位的注册字符设备——__register_chrdev
它会申请多个设备号,创建cdev并初始化它,然后用这多个设备号绑定同一个cdev 注册。
还有一个register_chrdev
,它是对__register_chrdev 的封装,次设备号从基值0开始,直接申请了256 个次设备号。static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops) { return __register_chrdev(major, 0, 256, name, fops); }
struct file_operations
字符设备在/dev/ 目录下创建设备文件,并通过struct file_operations 向应用层提供控制接口。应用层对应的open、read 等函数会调用到file_operations 对应的函数。
//include/linux/fs.h struct file_operations { struct module *owner; 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 (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); int (*iterate) (struct file *, struct dir_context *); unsigned int (*poll) (struct file *, struct poll_table_struct *); 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 (*mremap)(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 *, loff_t, loff_t, 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 **, void **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); void (*show_fdinfo)(struct seq_file *m, struct file *f); #ifndef CONFIG_MMU unsigned (*mmap_capabilities)(struct file *); #endif };
copy_to_user() 与 copy_from_user()
为了安全考虑,应用进程不能直接访问内核数据,需要借助这两个函数拷贝:static inline int copy_to_user(void __user volatile *to, const void *from, unsigned long n)
static inline int copy_from_user(void *to, const void __user volatile *from, unsigned long n)
返回非0 表示错误。
自动创建设备文件
自动创建设备节点的工作是在驱动程序的入口函数中完成的,一般在 cdev_add 函数后面添加自动创建设备节点相关代码。首先要创建一个 class 类, class 是个结构体,定义在文件include/linux/device.h 里面。
使用 class_create 创建一个类:
extern struct class * __must_check __class_create(struct module *owner, const char *name, struct lock_class_key *key); #define class_create(owner, name) \ ({ \ static struct lock_class_key __key; \ __class_create(owner, name, &__key); \ })
使用class_destroy 摧毁一个类:extern void class_destroy(struct class *cls);
struct class { const char *name; struct module *owner; struct class_attribute *class_attrs; const struct attribute_group **dev_groups; struct kobject *dev_kobj; int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); char *(*devnode)(struct device *dev, umode_t *mode); void (*class_release)(struct class *class); void (*dev_release)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); const struct kobj_ns_type_operations *ns_type; const void *(*namespace)(struct device *dev); const struct dev_pm_ops *pm; struct subsys_private *p; };
在创建完类后,要创建一个设备,使用 device_create创建一个设备:struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
摧毁一个设备:extern void device_destroy(struct class *cls, dev_t devt);
创建类会在/sys/class/ 目录下生成一个新的文件夹,其中包含属于此类的设备文件夹。
IS_ERR 和 PTR_ERR
IS_ERR 可以判断一个指针是否为空,PTR_ERR 将指针转化为数值返回。
static inline long __must_check PTR_ERR(const void *ptr) { return (long) ptr; } static inline long __must_check IS_ERR(const void *ptr) { return IS_ERR_VALUE((unsigned long)ptr); }
#include <linux/fs.h> //file_operations声明 #include <linux/module.h> //module_init module_exit声明 #include <linux/init.h> //__init __exit 宏定义声明 #include <linux/device.h> //class devise声明 #include <linux/uaccess.h> //copy_from_user 的头文件 #include <linux/types.h> //设备号 dev_t 类型声明 #include <asm/io.h> //ioremap iounmap的头文件 #define DEVICE_CNT 0 //设备号个数 struct led_device{ dev_t devid; //设备号 int major; //主设备号 int minor; //次设备号 char* name = "led"; //驱动名 struct cdev led_dev; //cdev 结构体 struct class *class; /* 类 */ struct device* device; //设备 }; struct led_device led; static int led_open(struct inode *inode, struct file *filp) { return 0; } static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { return 0; } static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { return 0; } /* 设备操作函数 */ static struct file_operations led_fo = { .owner = THIS_MODULE, .open = led_open, .read = led_read, .write = led_write, }; static int _init led_init() { /*注册字符设备驱动*/ /*1.注册设备号*/ led.major = 0; //由内核自动分配主设备号 if(led.major) //如果分配了的话就注册 { led.devid = MKDEV(led.major,0); register_chrdev_region(led.devid,DEVICE_CNT,led.name); //将驱动注册到内核中 } else{ //如果没有分配的话 //从0号(次设备号)开始申请 alloc_chrdev_region(&led.devid,0,DEVICE_CNT,led.name); //申请设备号 led.major = MAJOR(led.devid); //获取主设备号 led.minor = MANOR(led.devid); //获取次设备号 } printk("newcheled major=%d,minor=%d\r\n",newchrled.major, newchrled.minor); /*2.初始化 cdev 结构体*/ led.led_dev.woner = THIS_MODULE; cdev_init(&led.led_dev,&led_fo); //将操作函数初始化到cdev结构体 /*3.应该是向链表中添cdev*/ cdev_add(&led.led_dev,led.devid,DEVICE_CNT); /*4.创建节点*/ led.class = class_create(THIS_MODULE,led.name); //先创建一个类 led.device = device_create(led.class,NULL,led.devid,NULL); //创建设备 return 0; } static void _exit led_exit() { /* 注销字符设备驱动 */ cdev_del(&newchrled.cdev);/* 删除cdev */ unregister_chrdev_region(newchrled.devid, NEWCHRLED_CNT); /* 注销设备号 */ device_destroy(newchrled.class, newchrled.devid); class_destroy(newchrled.class); } /*注册字符设备入口与卸载入口*/ module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("zhoujianghong");
应用open到file_operations->open 的调用原理
相关推荐:《Linux视频教程》
以上がLinux でのキャラクター デバイスとは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









言語のマルチスレッドは、プログラムの効率を大幅に改善できます。 C言語でマルチスレッドを実装する4つの主な方法があります。独立したプロセスを作成します。独立して実行される複数のプロセスを作成します。各プロセスには独自のメモリスペースがあります。擬似マルチスレッド:同じメモリ空間を共有して交互に実行するプロセスで複数の実行ストリームを作成します。マルチスレッドライブラリ:pthreadsなどのマルチスレッドライブラリを使用して、スレッドを作成および管理し、リッチスレッド操作機能を提供します。 Coroutine:タスクを小さなサブタスクに分割し、順番に実行する軽量のマルチスレッド実装。

web.xmlファイルを開くには、次の方法を使用できます。テキストエディター(メモ帳やテキストエディットなど)を使用して、統合開発環境(EclipseやNetBeansなど)を使用してコマンドを編集できます(Windows:Notepad web.xml; Mac/Linux:Open -A Textedit Web.xml)

Linux Systemsに付属するPythonインタープリターを削除する問題に関して、多くのLinuxディストリビューションは、インストール時にPythonインタープリターをプリインストールし、パッケージマネージャーを使用しません...

Linuxは、サーバー管理、組み込みシステム、デスクトップ環境として最適です。 1)サーバー管理では、LinuxはWebサイト、データベース、アプリケーションをホストするために使用され、安定性と信頼性を提供します。 2)組み込みシステムでは、Linuxは柔軟性と安定性のため、スマートホームおよび自動車電子システムで広く使用されています。 3)デスクトップ環境では、Linuxは豊富なアプリケーションと効率的なパフォーマンスを提供します。

DebianLinuxは、その安定性とセキュリティで知られており、サーバー、開発、デスクトップ環境で広く使用されています。現在、DebianとHadoopとの直接的な互換性に関する公式の指示が不足していますが、この記事では、DebianシステムにHadoopを展開する方法について説明します。 Debianシステムの要件:Hadoop構成を開始する前に、DebianシステムがHadoopの最小動作要件を満たしていることを確認してください。これには、必要なJavaランタイム環境(JRE)とHadoopパッケージのインストールが含まれます。 Hadoop展開手順:Hadoopをダウンロードして解凍:公式ApachehadoopのWebサイトから必要なHadoopバージョンをダウンロードして解決します

「DebianStrings」は標準的な用語ではなく、その特定の意味はまだ不明です。この記事は、ブラウザの互換性について直接コメントすることはできません。ただし、「DebianStrings」がDebianシステムで実行されているWebアプリケーションを指す場合、そのブラウザの互換性はアプリケーション自体の技術アーキテクチャに依存します。ほとんどの最新のWebアプリケーションは、クロスブラウザーの互換性に取り組んでいます。これは、次のWeb標準と、適切に互換性のあるフロントエンドテクノロジー(HTML、CSS、JavaScriptなど)およびバックエンドテクノロジー(PHP、Python、Node.jsなど)を使用することに依存しています。アプリケーションが複数のブラウザと互換性があることを確認するには、開発者がクロスブラウザーテストを実施し、応答性を使用する必要があることがよくあります

GOを使用してOracleデータベースに接続するときにOracleクライアントをインストールする必要がありますか? GOで開発するとき、Oracleデータベースに接続することは一般的な要件です...