목차
linux 문자 장치
어플리케이션 계층에 캐릭터 디바이스가 반영되는 방식" >어플리케이션 계층에 캐릭터 디바이스가 반영되는 방식
设备号" >设备号
字符设备结构体 cdev" >字符设备结构体 cdev
struct file_operations" >struct file_operations
自动创建设备文件" >自动创建设备文件
IS_ERR 和 PTR_ERR" >IS_ERR 和 PTR_ERR
일반적인 문제 Linux의 문자 장치는 무엇입니까?

Linux의 문자 장치는 무엇입니까?

Mar 09, 2023 am 10:49 AM
linux 캐릭터 장치

Linux 문자 장치에는 다음이 포함됩니다. 1. 컴퓨터의 외부 입력 장치이자 컴퓨터 디스플레이 시스템의 수직 및 수평 좌표 위치를 지정하는 표시기인 마우스 2. 다음 작업에 사용되는 명령 및 데이터 입력 장치인 키보드 3. 직렬 포트 터미널, 컴퓨터 직렬 포트를 사용하여 연결된 터미널 장치 5. 콘솔 등

Linux의 문자 장치는 무엇입니까?

이 튜토리얼의 운영 환경: linux7.3 시스템, Dell G3 컴퓨터.

linux 문자 장치


문자 장치는 Linux의 세 가지 주요 장치 중 하나입니다(나머지 두 가지는 블록 장치와 네트워크 장치입니다). 이들은 모두 파일 노드의 형태로 파일 시스템의 /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/tty 터미널을 사용합니다.

  • 콘솔(/dev/ttyn, /dev/consol): 컴퓨터 입출력을 위한 모니터입니다. 콘솔에 로그인하면 tty1이 사용되고, ubuntu 그래픽 인터페이스는 tty7을 사용합니다.

  • 기타 유형: 현재 Linux에는 ISIDIN 장치의 /dev/ttyIn 장치와 같이 다양한 장치에 대한 다양한 유형의 장치 특수 파일이 있습니다.

캐릭터 디바이스의 본질과 특성

  • 캐릭터 디바이스는 디바이스 파일 시스템의 일종으로, 연결과 마찬가지로 상위 계층에 기본 하드웨어가 제공하는 논리적 디바이스 파일과 동일합니다. 데이터 포트(데이터 레지스터) 파일이 연결되면 장치 드라이버가 파일에 대해 직접 동작하므로 포트에 대한 읽기 및 쓰기 작업을 직접 수행합니다. 또한 파일로서 문자 장치 드라이버는 open(), close(), write(), read() 등과 같은 파일의 기본 작업도 구현해야 합니다. 물론 터미널 리디렉션 작업도 지원됩니다.

  • 캐릭터 디바이스 파일 파일은 싱글바이트 단위로 읽고 쓰기 때문에 하드웨어 버퍼를 설정할 필요가 없습니다. 장치는 운영 체제에서 바이트 스트림으로 액세스됩니다. 바이트 스트림은 하드웨어 포트와 파일 시스템 사이에 전송 파이프를 설정하는 것과 같습니다. 바이트는 파이프를 통해 하나씩 전송되어 판독기와 기록기 모두에게 제공됩니다. 이 스트리밍 기능은 드라이버에서 버퍼 대기열로 구현됩니다. 예: 콘솔 구조의 읽기-쓰기 버퍼 큐

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)이며, 커널은 해당 장치에 해당하는 드라이버를 식별합니다. 일반적으로 부 장치 번호는 장치와 드라이버를 일대일로 일치시키기 위해 드라이버에서 내부적으로 사용하는 코드로 사용되며 다른 부분에서는 사용되지 않습니다. 커널의.

어플리케이션 계층에 캐릭터 디바이스가 반영되는 방식

cat /proc/devices 명령을 사용하면 현재 시스템의 모든 캐릭터 디바이스와 블록 디바이스를 볼 수 있습니다.

Linux의 문자 장치는 무엇입니까?

Linux의 문자 장치는 무엇입니까?

Linux에서는 파일 연결 시 장치도 파일로 추상화됩니다. 문자 장치와 블록 장치에 해당하는 파일은 /dev/ 디렉터리에서 볼 수 있습니다.
예를 들어 다음은 두 개의 직렬 포트 장치 파일입니다. ls -l을 사용하여 세부 정보를 확인하세요.
일반 파일과 달리 장치 파일에는 크기가 없지만 장치 번호(주 장치 번호 및 보조 장치 번호)로 대체됩니다. 장치 번호는 /proc/devices의 정보에 해당할 수 있습니다.

Linux의 문자 장치는 무엇입니까?

기기에 액세스하는 방법은 무엇인가요?

파일로 추상화되어 있기 때문에 파일 IO(열기, 읽기, 쓰기 등)를 사용하여 접근하는 것이 당연합니다.

设备号

Linux의 문자 장치는 무엇입니까?

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 注册。

Linux의 문자 장치는 무엇입니까?

还有一个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/ 目录下生成一个新的文件夹,其中包含属于此类的设备文件夹。

5-Linux의 문자 장치는 무엇입니까?

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视频教程

위 내용은 Linux의 문자 장치는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 채팅 명령 및 사용 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Linux에서 Nginx를 시작하는 방법 Linux에서 Nginx를 시작하는 방법 Apr 14, 2025 pm 12:51 PM

Linux에서 Nginx를 시작하는 단계 : Nginx가 설치되어 있는지 확인하십시오. systemctl start nginx를 사용하여 nginx 서비스를 시작하십시오. SystemCTL을 사용하여 NGINX를 사용하여 시스템 시작시 NGINX의 자동 시작을 활성화하십시오. SystemCTL 상태 nginx를 사용하여 시작이 성공했는지 확인하십시오. 기본 환영 페이지를 보려면 웹 브라우저의 http : // localhost를 방문하십시오.

nginx가 시작되었는지 확인하는 방법 nginx가 시작되었는지 확인하는 방법 Apr 14, 2025 pm 01:03 PM

nginx가 시작되었는지 확인하는 방법 : 1. 명령 줄을 사용하십시오 : SystemCTL 상태 nginx (linux/unix), netstat -ano | Findstr 80 (Windows); 2. 포트 80이 열려 있는지 확인하십시오. 3. 시스템 로그에서 nginx 시작 메시지를 확인하십시오. 4. Nagios, Zabbix 및 Icinga와 같은 타사 도구를 사용하십시오.

nginx 서버를 시작하는 방법 nginx 서버를 시작하는 방법 Apr 14, 2025 pm 12:27 PM

Nginx 서버를 시작하려면 다른 운영 체제에 따라 다른 단계가 필요합니다. Linux/Unix System : Nginx 패키지 설치 (예 : APT-Get 또는 Yum 사용). SystemCTL을 사용하여 nginx 서비스를 시작하십시오 (예 : Sudo SystemCtl start nginx). Windows 시스템 : Windows 바이너리 파일을 다운로드하여 설치합니다. nginx.exe 실행 파일을 사용하여 nginx를 시작하십시오 (예 : nginx.exe -c conf \ nginx.conf). 어떤 운영 체제를 사용하든 서버 IP에 액세스 할 수 있습니다.

nginx403 오류를 해결하는 방법 nginx403 오류를 해결하는 방법 Apr 14, 2025 pm 12:54 PM

서버는 요청 된 리소스에 액세스 할 수있는 권한이 없으므로 Nginx 403 오류가 발생합니다. 솔루션에는 다음이 포함됩니다. 파일 권한 확인 권한을 확인하십시오. .htaccess 구성을 확인하십시오. nginx 구성을 확인하십시오. Selinux 권한을 구성하십시오. 방화벽 규칙을 확인하십시오. 브라우저 문제, 서버 장애 또는 기타 가능한 오류와 같은 다른 원인을 해결하십시오.

Nginx403을 해결하는 방법 Nginx403을 해결하는 방법 Apr 14, 2025 am 10:33 AM

Nginx 403 금지 된 오류를 수정하는 방법은 무엇입니까? 파일 또는 디렉토리 권한을 확인합니다. 2. 확인 파일을 확인하십시오. 3. nginx 구성 파일 확인; 4. nginx를 다시 시작하십시오. 다른 가능한 원인으로는 방화벽 규칙, Selinux 설정 또는 응용 프로그램 문제가 있습니다.

nginx304 오류를 해결하는 방법 nginx304 오류를 해결하는 방법 Apr 14, 2025 pm 12:45 PM

질문에 대한 답변 : 304 수정되지 않은 오류는 브라우저가 클라이언트 요청의 최신 리소스 버전을 캐시했음을 나타냅니다. 솔루션 : 1. 브라우저 캐시를 지우십시오. 2. 브라우저 캐시를 비활성화합니다. 3. 클라이언트 캐시를 허용하도록 nginx를 구성합니다. 4. 파일 권한을 확인하십시오. 5. 파일 해시를 확인하십시오. 6. CDN 또는 리버스 프록시 캐시를 비활성화합니다. 7. nginx를 다시 시작하십시오.

nginx가 시작되었는지 확인하는 방법은 무엇입니까? nginx가 시작되었는지 확인하는 방법은 무엇입니까? Apr 14, 2025 pm 12:48 PM

Linux에서는 다음 명령을 사용하여 nginx가 시작되었는지 확인하십시오. SystemCTL 상태 Nginx 판사 명령 출력에 따라 : "active : running"이 표시되면 Nginx가 시작됩니다. "Active : 비활성 (죽음)"이 표시되면 Nginx가 중지됩니다.

nginx 오류 로그를 청소하는 방법 nginx 오류 로그를 청소하는 방법 Apr 14, 2025 pm 12:21 PM

오류 로그는/var/log/nginx (linux) 또는/usr/local/var/log/nginx (macOS)에 있습니다. 명령 줄을 사용하여 단계를 정리하십시오. 1. 원래 로그를 백업하십시오. 2. 빈 파일을 새 로그로 만듭니다. 3. Nginx 서비스를 다시 시작하십시오. 자동 청소는 Logrotate 또는 구성과 같은 타사 도구와 함께 사용할 수도 있습니다.