Mr Dk.'s BlogMr Dk.'s Blog
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🐧 Linux Kernel Comments
    • Chapter 2 - 微型计算机组成结构

      • Chapter 2 - 微型计算机组成结构
    • Chapter 3 - 内核编程语言和环境

      • Chapter 3 - 内核编程语言和环境
    • Chapter 4 - 80X86 保护模式及其编程

      • Chapter 4.1-4.2 - 80X86 系统寄存器和系统指令 & 保护模式内存管理
      • Chapter 4.3 - 分段机制
      • Chapter 4.4 - 分页机制
      • Chapter 4.5 - 保护
      • Chapter 4.6 - 中断和异常处理
      • Chapter 4.7 - 任务管理
      • Chapter 4.8 - 保护模式编程初始化
      • Chapter 4.9 - 一个简单的多任务内核实例
    • Chapter 5 - Linux 内核体系结构

      • Chapter 5.1-5.2 - Linux 内核模式 & 体系结构
      • Chapter 5.3 - Linux 内核对内存的管理和使用
      • Chapter 5.4-5.6 - 中断机制 & 系统调用 & 系统时间和定时
      • Chapter 5.7-5.9 - Linux 进程控制 & 堆栈使用 & 文件系统
    • Chapter 6 - 引导启动程序 (boot)

      • Chapter 6 - 引导启动程序 (boot)
    • Chapter 7 - 初始化程序 (init)

      • Chapter 7 - 初始化程序 (init)
    • Chapter 8 - 内核代码

      • Chapter 8.1 - 内核代码总体功能
      • Chapter 8.2 - asm.s 程序
      • Chapter 8.3 - traps.c 程序
      • Chapter 8.4 - sys_call.s 程序
      • Chapter 8.5 - mktime.c 程序
      • Chapter 8.6 - sched.c 程序
      • Chapter 8.7 - signal.c 程序
      • Chapter 8.8 - exit.c 程序
      • Chapter 8.9 - fork.c 程序
      • Chapter 8.10 - sys.c 程序
    • Chapter 9 - 块设备驱动程序

      • Chapter 9.1 - 块设备驱动程序 总体功能
      • Chapter 9.2 - blk.h 文件
      • Chapter 9.3 - hd.c 程序
      • Chapter 9.4 - ll_rw_blk.c 程序
      • Chapter 9.5 - ramdisk.c 程序
    • Chapter 10 - 字符设备驱动程序

      • Chapter 10.1 - 字符设备驱动程序 总体功能
      • Chapter 10.2 - keyboard.S 程序
      • Chapter 10.3 - console.c 程序
      • Chapter 10.4 - serial.c 程序
      • Chapter 10.5 - rs_io.s 程序
      • Chapter 10.6 - tty_io.c 程序
      • Chapter 10.7 - tty_ioctl.c 程序
    • Chapter 12 - 文件系统

      • Chapter 12.1 - 文件系统 总体功能
      • Chapter 12.2 - buffer.c 程序
      • Chapter 12.3 - bitmap.c 程序
      • Chapter 12.4 - truncate.c 程序
      • Chapter 12.5 - inode.c 程序
      • Chapter 12.6 - super.c 程序
      • Chapter 12.7 - namei.c 程序
      • Chapter 12.9 - block_dev.c 程序
      • Chapter 12.10 - file_dev.c 程序
      • Chapter 12.11 - pipe.c 程序
      • Chapter 12.12 - char_dev.c 程序
      • Chapter 12.13 - read_write.c 程序
      • Chapter 12.14 - open.c 程序
      • Chapter 12.15 - exec.c 程序
      • Chapter 12.16 - stat.c 程序
      • Chapter 12.17 - fcntl.c 程序
      • Chapter 12.18 - ioctl.c 程序
      • Chapter 12.19 - select.c 程序

Chapter 12.12 - char_dev.c 程序

Created by : Mr Dk.

2019 / 09 / 15 20:13

Nanjing, Jiangsu, China


12.12 char_dev.c 程序

12.12.1 功能描述

包含各个字符设备文件的访问函数,另还有一个设备读写函数指针表。

12.12.2 代码注释

rw_ttyx() - 串口终端读写操作函数

static int rw_ttyx(int rw, unsigned minor, char * buf, int count, off_t * pos)
{
    return ((rw == READ) ?
            tty_read(minor, buf, count) :
            tty_write(minor, buf, count));
}

rw_tty() - 控制台终端读写操作函数

基本同上,但需要对进程是否有 控制终端 进行检测。

static int rw_tty(int rw, unsigned minor, char * buf, int count, off_t * pos)
{
    if (current->tty < 0)
        return -EPERM;
    return rw_ttyx(rw, current->tty, buf, count, pos);
}

rw_ram() - 内存数据读写函数 - 未实现

rw_mem() - 物理内存数据读写函数 - 未实现

rw_kmem() - 内核虚拟内存数据读写函数 - 未实现

rw_port() - 端口读写操作函数

pos 为端口地址

static int rw_port(int rw, char * buf, int count, off_t * pos)
{
    int i = *pos;
    
    // 端口地址小于 64k
    // 还有数据需要操作
    while (count-- > 0 && i < 65536) {
        if (rw == READ)
            put_fs_byte(inb(i), buf++);
        else
            outb(get_fs_byte(buf++), i);
        i++; // ??
    }
    
    i -= *pos; // i 为读/写的字节数
    *pos += i;
    return i;
}

rw_memory() - 内存读写操作函数

static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos)
{
    // 内存主设备号为 1
    // 根据内存设备的子设备号
    // 调用不同的内存读写函数
    switch(minor) {
        case 0: // /dev/ram0 或 /dev/ramdisk
            return rw_ram(rw, buf, count, pos);
        case 1: // /dev/ram1 或 /dev/mem 或 ram
            return rw_mem(rw, buf, count, pos);
        case 2: // /dev/ram2 或 /dev/kmem
            return rw_kmem(rw, buf, count, pos);
        case 3: // /dev/null
            return (rw == READ) ? 0 : count;
        case 4: // /dev/port
            return rw_port(rw, buf, count, pos);
        default:
            return -EIO;
    }
}

rw_char() - 字符设备读写操作函数

根据设备的主设备号,分别调用对应的 字符设备读写函数指针表 中的函数。字符设备读写函数指针的定义:

typedef (*crw_ptr) (int rw, unsigned minor, char * buf, int count, off_t * pos);

字符设备读写函数指针表:

static crw_ptr crw_table[] = {
    NULL, // /dev/null
    rw_memory, // /dev/mem
    NULL, // /dev/fd
    NULL, // /dev/hd
    rw_ttyx, // /dev/ttyx
    rw_tty, // /dev/tty
    NULL, // /dev/lp
    NULL // 未命名管道
};

系统中的设备种数:

#define NRDEVS ((sizeof(crw_table)) / (sizeof(crw_ptr)))

字符设备读写操作函数:

int rw_char(int rw, int dev, char * buf, int count, off_t * pos)
{
    crw_ptr call_addr;
    
    if (MAJOR(dev) >= NRDEVS)
        // 设备号超出系统设备数
        return -ENODEV;
    if (!(call_addr = crw_table[MAJOR(dev)]))
        // 设备没有读写函数
        return -ENODEV;
    return call_addr(rw, MINOR(dev), buf, count, pos);
}

Summary

从层次上来看,在对字符设备的上层调用中,需要提供设备号。接口函数根据设备的 主设备号,找到对应设备的读写函数指针,然后将 子设备号 传入各类设备的读写子函数中,在读写子函数中进入不同的分支逻辑。

Edit this page on GitHub
Prev
Chapter 12.11 - pipe.c 程序
Next
Chapter 12.13 - read_write.c 程序