Was sind die Zeichengeräte unter Linux?
Zu den Linux-Zeichengeräten gehören: 1. Maus, ein externes Eingabegerät für den Computer und ein Indikator für die Positionierung der vertikalen und horizontalen Koordinaten des Computeranzeigesystems. 2. Tastatur, ein Befehls- und Dateneingabegerät 3. Serieller Anschluss, ein über einen seriellen Anschluss angeschlossenes Endgerät; 5. Konsole usw.
Die Betriebsumgebung dieses Tutorials: Linux7.3-System, Dell G3-Computer.
Linux-Zeichengerät
Das Zeichengerät ist eines der drei Hauptgeräte in Linux (die anderen beiden sind Blockgeräte und Netzwerkgeräte). Sie werden alle im /dev-Verzeichnis des Dateisystems in Form eines Dateiknotens angezeigt (crw--w---- 1 root tty 4, 0 July 11 09:11 tty0, wobei c den Zeichengerätetyp darstellt).
Zeichengerät bezieht sich auf ein Gerät, das ohne Pufferung direkt lesen und schreiben kann, z. B. eine Maus, eine Tastatur, ein Gerät mit serieller Schnittstelle, ein Modem usw. Der Unterschied zwischen ihm und einem Blockgerät besteht darin, dass die Grundeinheit der Zeichenoperation Byte ist.
Klassifizierung von Zeichengeräten
Zu Zeichengeräten gehören hauptsächlich Steuerungsterminalgeräte und serielle Endgeräte wie Konsolen und Tastaturen. Basierend auf Unterschieden in Funktionen und Hardware werden Zeichenterminalgeräte wie folgt klassifiziert:
Terminal mit serieller Schnittstelle (/dev/ttSn): ein Terminalgerät, das über eine serielle Schnittstelle eines Computers angeschlossen ist. Die Datenübertragungsmethode für serielle Geräte ist dieselbe 8 Bits werden in einer einzigen Zeile übertragen. Geben Sie echo 'hello world' > /dev/ttyS0 in die Befehlszeile ein, um die Eingabe auf das entsprechende Gerät zu schreiben.
Pseudo-Terminal (/dev/ttyp, /dev/ptyp): Da es auf der untersten Ebene kein echtes Hardwaregerät gibt, wird es verwendet, um eine Schnittstelle im Terminalstil für andere Programme bereitzustellen, z zwischen dem Netzwerkserver und dem Shell-Programm, wenn Sie sich über die Netzwerk-Terminalschnittstelle beim Host anmelden.
Steuerterminal (/dev/tty): Die Hauptgerätenummer ist 5. Das Prozesssteuerterminal ist dem Prozess zugeordnet. Der Login-Shell-Prozess verwendet beispielsweise das Terminal /dev/tty.
Console (/dev/ttyn, /dev/consol): Der Monitor für die Computereingabe und -ausgabe wird tty1 verwendet, während die grafische Benutzeroberfläche von Ubuntu tty7 verwendet.
Andere Typen: Aktuelles Linux verfügt über viele andere Arten von Gerätespezialdateien für viele verschiedene Geräte, wie zum Beispiel das /dev/ttyIn-Gerät des ISIDIN-Geräts.
Die Art und Eigenschaften von Zeichengeräten
Zeichengeräte sind eine Art Gerätedateisystem, das den logischen Gerätedateien entspricht, die von der zugrunde liegenden Hardware für die obere Schicht bereitgestellt werden, genau wie beim Verbinden Ein Datenport (Datenregister) mit Wenn eine Datei verbunden ist, arbeitet der Gerätetreiber direkt an der Datei, sodass er direkt Lese- und Schreibvorgänge am Port ausführt. Auch als Datei muss der Zeichengerätetreiber auch die grundlegenden Operationen von Dateien wie open(), close(), write(), read() usw. implementieren. Natürlich werden auch Terminalumleitungsoperationen unterstützt.
Zeichengerätedateidateien werden in Einzelbyte-Einheiten gelesen und geschrieben, und es ist nicht erforderlich, einen Hardwarepuffer einzurichten. Der Zugriff auf das Gerät erfolgt durch das Betriebssystem als Bytestream. Der Byte-Stream ähnelt dem Einrichten einer Übertragungspipe zwischen dem Hardware-Port und dem Dateisystem. Bytes werden einzeln durch die Pipe übertragen und sowohl Lesern als auch Schreibern präsentiert. Diese Streaming-Funktion ist im Treiber als Pufferwarteschlange implementiert. Beispiel: Die Lese- und Schreibpufferwarteschlange in der Struktur der Konsole
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辅助队列(存放规格化后的字符) };
Das Zeichengerät wird durch die Zeichengerätenummer identifiziert. Die Zeichengerätenummer besteht aus einer Hauptgerätenummer und einer Nebengerätenummer. Die Gerätenummer von /dev/ttyS0 ist beispielsweise (4, 64); Die Hauptgerätenummer muss eins zu eins mit dem Gerät und dem Treiber übereinstimmen. Im Allgemeinen wird die Nebengerätenummer vom Treiber für den intern verwendeten Code verwendet, um zwischen Gerätedetails zu unterscheiden des Kernels.
Wie sich Zeichengeräte auf der Anwendungsebene widerspiegeln
cat /proc/devices
Mit dem Befehl können alle Zeichengeräte angezeigt und Geräte im aktuellen System blockiert werden.
Unter Linux werden beim Verbinden von Dateien auch Geräte in Dateien abstrahiert. Die entsprechenden Dateien für Zeichengeräte und Blockgeräte können im Verzeichnis /dev/ eingesehen werden.
Dies sind beispielsweise zwei Gerätedateien für serielle Ports. Verwenden Sie ls -l, um die Details anzuzeigen.
Im Gegensatz zu gewöhnlichen Dateien haben Gerätedateien keine Größe, sondern werden durch Gerätenummern (Hauptgerätenummern und Nebengerätenummern) ersetzt. Die Gerätenummern können den Informationen in /proc/devices entsprechen.
Wie greife ich auf ein Gerät zu?
Da es in eine Datei abstrahiert ist, ist es selbstverständlich, Datei-E/A (Öffnen, Lesen, Schreiben usw.) zu verwenden, um darauf zuzugreifen.
设备号
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视频教程》
Das obige ist der detaillierte Inhalt vonWas sind die Zeichengeräte unter Linux?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



Linux eignet sich für Server, Entwicklungsumgebungen und eingebettete Systeme. 1. Als Serverbetriebssystem ist Linux stabil und effizient und wird häufig zur Bereitstellung von Anwendungen mit hoher Konreise verwendet. 2. Als Entwicklungsumgebung bietet Linux effiziente Befehlszeilen -Tools und Paketmanagementsysteme, um die Entwicklungseffizienz zu verbessern. 3. In eingebetteten Systemen ist Linux leicht und anpassbar und für Umgebungen mit begrenzten Ressourcen geeignet.

Die Schritte zum Starten von Apache sind wie folgt: Installieren Sie Apache (Befehl: sudo apt-Get-Get-Installieren Sie Apache2 oder laden Sie ihn von der offiziellen Website herunter). (Optional, Linux: sudo systemctl

Wenn der Port -80 -Port der Apache 80 besetzt ist, lautet die Lösung wie folgt: Finden Sie den Prozess, der den Port einnimmt, und schließen Sie ihn. Überprüfen Sie die Firewall -Einstellungen, um sicherzustellen, dass Apache nicht blockiert ist. Wenn die obige Methode nicht funktioniert, konfigurieren Sie Apache bitte so, dass Sie einen anderen Port verwenden. Starten Sie den Apache -Dienst neu.

In diesem Artikel wird beschrieben, wie die SSL -Leistung von NGINX -Servern auf Debian -Systemen effektiv überwacht wird. Wir werden Nginxexporter verwenden, um Nginx -Statusdaten in Prometheus zu exportieren und sie dann visuell über Grafana anzeigen. Schritt 1: Konfigurieren von Nginx Erstens müssen wir das Modul stub_status in der nginx -Konfigurationsdatei aktivieren, um die Statusinformationen von Nginx zu erhalten. Fügen Sie das folgende Snippet in Ihre Nginx -Konfigurationsdatei hinzu (normalerweise in /etc/nginx/nginx.conf oder deren inklusive Datei): location/nginx_status {stub_status

Die Schritte zum Starten eines Oracle -Listeners sind wie folgt: Überprüfen

In diesem Artikel werden zwei Methoden zur Konfiguration eines Recycling -Bin in einem Debian -System eingeführt: eine grafische Schnittstelle und eine Befehlszeile. Methode 1: Verwenden Sie die grafische Schnittstelle Nautilus, um den Dateimanager zu öffnen: Suchen und starten Sie den Nautilus -Dateimanager (normalerweise als "Datei") im Menü Desktop oder Anwendungen. Suchen Sie den Recycle Bin: Suchen Sie nach dem Ordner recycelner Behälter in der linken Navigationsleiste. Wenn es nicht gefunden wird, klicken Sie auf "Andere Speicherort" oder "Computer", um sie zu suchen. Konfigurieren Sie Recycle Bin-Eigenschaften: Klicken Sie mit der rechten Maustaste auf "Recycle Bin" und wählen Sie "Eigenschaften". Im Eigenschaftenfenster können Sie die folgenden Einstellungen einstellen: Maximale Größe: Begrenzen Sie den im Recycle -Behälter verfügbaren Speicherplatz. Aufbewahrungszeit: Legen Sie die Erhaltung fest, bevor die Datei automatisch im Recyclingbehälter gelöscht wird

Befolgen Sie die folgenden Schritte, um den Apache -Server neu zu starten: Linux/MacOS: Führen Sie sudo systemCTL RESTART APache2 aus. Windows: Net Stop Apache2.4 und dann Net Start Apache2.4 ausführen. Führen Sie Netstat -a | Findstr 80, um den Serverstatus zu überprüfen.

In Debian -Systemen werden Readdir -Systemaufrufe zum Lesen des Verzeichnisinhalts verwendet. Wenn seine Leistung nicht gut ist, probieren Sie die folgende Optimierungsstrategie aus: Vereinfachen Sie die Anzahl der Verzeichnisdateien: Teilen Sie große Verzeichnisse so weit wie möglich in mehrere kleine Verzeichnisse auf und reduzieren Sie die Anzahl der gemäß Readdir -Anrufe verarbeiteten Elemente. Aktivieren Sie den Verzeichnis -Inhalt Caching: Erstellen Sie einen Cache -Mechanismus, aktualisieren Sie den Cache regelmäßig oder bei Änderungen des Verzeichnisinhalts und reduzieren Sie häufige Aufrufe an Readdir. Speicher -Caches (wie Memcached oder Redis) oder lokale Caches (wie Dateien oder Datenbanken) können berücksichtigt werden. Nehmen Sie eine effiziente Datenstruktur an: Wenn Sie das Verzeichnis -Traversal selbst implementieren, wählen Sie effizientere Datenstrukturen (z.