Try   HackMD

Embedded Linux System, Boot, Linux VFS, System Call, SPI, GPIO, I²C, 課程基礎原理

tags: embedded linux overview VFS

Author: CrazyMonkey
email: kccddb@gmail.com
Date: 20230915
Copyright: CC BY-NC-SA

財團法人台灣兒童暨家庭扶助基金會

因為有同學問了 system programming 與 embedded Linux system 的問題, 因此增加一些內容, 希望同學了解運作原理

A. Linux System Programming 優良書本:

因有同學需要 , 特地加上一本很好的巨著, 相信很有幫助!

(1). 對於想了解 Linux System Call 想更清楚的同學, 下面有上下冊兩本 (有範例, 有中文版)可以當程式設計者深入的參考閱讀

The Linux Programming Interface 國際中文版 (上冊, 下冊) 全書約 1500 頁
The Linux Programming Interface: A Linux and UNIX System Programming Handbook

作者: Michael Kerrisk
譯者: 廖明沂, 楊竹星

(2) 比較簡短(很好的書)
Linux System Programming, R, Love

對 IoT 有興趣可以考慮 ESP8266 (有 Wi-Fi, 可用Arduino Ide 開發 )

B. 增加 SPI 觀念與連結(也記得 OOP)

c 物件導向 可以嗎? 還是一定要用 C++ 或 JAVA?

c language: function pointer, callback and event-driven

這網站有很多軟體的 cross referece, linux kernel source, busybox, QEMU,
向 全世界的軟體設計者學習如何寫軟體
https://elixir.bootlin.com/linux/latest/source

Futher Reading:

Udev (userspace /dev) is a Linux sub-system for dynamic device detection and management, since kernel 2.6.x.

Udev: Introduction to Device Management In Modern Linux System

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

[CC BY-SA 3.0], via Wikimedia Commons

systemd

D-Bus

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Netlink socket

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


Linux 與 C是未來業界非常重要的知識, C 更是科技業單晶片與 Embedded System 的程式語言, 希望有興趣科技的同學加油!

D. 因很多 GPIO 3.3V 因此 若要控制 5V or 12V 可能 需要 NPN or PNP Tranzistor 或 使用 solid state relay (SSR)
特別注意 Ic 電流大小 (看 datasheet) 複習 電子學(安排電阻值, 自己計算負載所需的電流) 電資學院應該要懂一些基本的

e.g., TIP122 NPN 可達 5A 可用, 就不須 SSR

以前我學弟在美國, 有次請他們研發人員設計一電路, 隔一星期, 對方說 沒給電路圖 無法 用 SPICE!

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

這課程很花時間, 可以練 吐納養氣腹式呼吸

必學!吐納養氣腹式呼吸,啟動身體自癒力!健康2.0 20161224

李鳳山師父平甩功十分鐘練習【梅門官方】


這單元主要是 Linux Embedded System 課程基礎原理

  1. Boot Loader, Linux OS, 系統程式 與網路核心運作原理簡介
  2. Linux System Call, VFS, init 運作原理
  3. Embedded Linux 系統運作原理

PART I

General Embedded Linux Systems

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


Start up

power on>hardware (CPU+ROM code (or Flash), Memory, Flash, ..)
ROM code UP and RUN
ROM code -Choose Available Boot Loader (e.g., U-Boot)

​​​​    Boot Loader UP and RUN-->Check and Choose Linux kernel image (e.g., bzimage) and Root File System (rootfs)
​​​​           Load image, maybe,  from flash, serial port, network, ...
​​​​    Linux kernel image UP (first part)--decompress Linux (main part) to memory
​​​​    RUN Linux main part --->
​​​​     START all initial codes
​​​​      ......
​​​​     mount rootfs   / <<<root
​​​​     RUN init (in rootfs)  
​​​​            init RUN all apps and INSERT all pre-defined kernel modules 
​​​​     START shell, ...
​​​​     $>

PC 使用的 GRUB (GRand Unified Bootloader):
Details of GRUB on the PC

Linux kernel 啟動部分:
以 Linux 2.4.0 為例:

https://lxr.linux.no/linux-old+v2.4.0/init/main.c

520asmlinkage void __init start_kernel(void) 521{ 522 char * command_line; 523 unsigned long mempages; 524 extern char saved_command_line[]; 525/* 526 * Interrupts are still disabled. Do necessary setups, then 527 * enable them 528 */ 529 lock_kernel(); 530 printk(linux_banner); 531 setup_arch(&command_line); 532 printk("Kernel command line: %s\n", saved_command_line); 533 parse_options(command_line); 534 trap_init(); 535 init_IRQ(); 536 sched_init(); 537 time_init(); 538 softirq_init(); 539 540 /* 541 * HACK ALERT! This is early. We're enabling the console before 542 * we've done PCI setups etc, and console_init() must be aware of 543 * this. But we do want output early, in case something goes wrong. 544 */ 545 console_init(); 546#ifdef CONFIG_MODULES 547 init_modules(); 548#endif 549 if (prof_shift) { 550 unsigned int size; 551 /* only text is profiled */ 552 prof_len = (unsigned long) &_etext - (unsigned long) &_stext; 553 prof_len >>= prof_shift; 554 555 size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1; 556 prof_buffer = (unsigned int *) alloc_bootmem(size); 557 } 558 559 kmem_cache_init(); 560 sti(); 561 calibrate_delay(); 562#ifdef CONFIG_BLK_DEV_INITRD 563 if (initrd_start && !initrd_below_start_ok && 564 initrd_start < min_low_pfn << PAGE_SHIFT) { 565 printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " 566 "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT); 567 initrd_start = 0; 568 } 569#endif 570 mem_init(); 571 kmem_cache_sizes_init(); 572#ifdef CONFIG_3215_CONSOLE 573 con3215_activate(); 574#endif 575#ifdef CONFIG_PROC_FS 576 proc_root_init(); 577#endif 578 mempages = num_physpages; 579 580 fork_init(mempages); 581 proc_caches_init(); 582 vfs_caches_init(mempages); 583 buffer_init(mempages); 584 page_cache_init(mempages); 585 kiobuf_setup(); 586 signals_init(); 587 bdev_init(); 588 inode_init(mempages); 589#if defined(CONFIG_SYSVIPC) 590 ipc_init(); 591#endif 592#if defined(CONFIG_QUOTA) 593 dquot_init_hash(); 594#endif 595 check_bugs(); 596 printk("POSIX conformance testing by UNIFIX\n"); 597 598 /* 599 * We count on the initial thread going ok 600 * Like idlers init is an unlocked kernel thread, which will 601 * make syscalls (and thus be locked). 602 */ 603 smp_init(); 604 kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); 605 unlock_kernel(); 606 current->need_resched = 1; 607 cpu_idle(); 608}

604 kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);

static int init(void * unused) 762{ 763 lock_kernel(); 764 do_basic_setup(); 765 766 /* 767 * Ok, we have completed the initial bootup, and 768 * we're essentially up and running. Get rid of the 769 * initmem segments and start the user-mode stuff.. 770 */ 771 free_initmem(); 772 unlock_kernel(); 773 774 if (open("/dev/console", O_RDWR, 0) < 0) 775 printk("Warning: unable to open an initial console.\n"); 776 777 (void) dup(0); 778 (void) dup(0); 779 780 /* 781 * We try each of these until one succeeds. 782 * 783 * The Bourne shell can be used instead of init if we are 784 * trying to recover a really broken machine. 785 */ 786 787 if (execute_command) 788 execve(execute_command,argv_init,envp_init); 789 execve("/sbin/init",argv_init,envp_init); 790 execve("/etc/init",argv_init,envp_init); 791 execve("/bin/init",argv_init,envp_init); 792 execve("/bin/sh",argv_init,envp_init); 793 panic("No init found. Try passing init= option to kernel."); 794}

dup, dup2, dup3 - duplicate a file descriptor
execve - execute program
How to Set Environment Variables in Linux



In general, "init" is the leading process with pid (process id)=0

You can look the result of pstree:
laikc@laikc-VirtualBox:~/course$ pstree
init─┬─NetworkManager─┬─dhclient
│ ├─dnsmasq
│ └─2*[{NetworkManager}]
├─accounts-daemon───{accounts-daemon}
├─atd
├─bluetoothd
├─console-kit-dae───64*[{console-kit-dae}]
├─cron
├─cupsd
├─2*[dbus-daemon]
├─6*[getty]
├─gvfs-fuse-daemo───3*[{gvfs-fuse-daemo}]
├─gvfsd
├─lightdm─┬─Xorg
│ ├─lightdm─┬─lightdm-greeter───lightdm-gtk-gre───{lightdm-gtk-gre}
│ │ └─{lightdm}
│ ├─lightdm
│ └─2*[{lightdm}]
├─modem-manager
├─named───3*[{named}]
├─ntpd
├─polkitd───{polkitd}
├─rsyslogd───3*[{rsyslogd}]
├─samba───4*[samba]
├─smbd───smbd
├─sshd─┬─sshd───sshd───bash───bash───pstree
│ └─sshd───sshd───bash
├─udevd───2*[udevd]
├─upowerd───2*[{upowerd}]
├─upstart-socket-
└─upstart-udev-br

Linux VFS & System Call

See also syscalls

PART II

PEX Boot ( SEE http://www.syslinux.org/wiki/index.php?title=PXELINUX )

Start up
power>hardware (CPU+Network ROM code, Memory, Flash, ..)
ROM code UP and RUN
ROM code -PXE Loader (in Netwok ROM,Flash)
Choose Available Boot Loader (e.g., PXELINUX ) (Need DHCP server)
Load pxe-loader via TFTP (from TFTP server)

​​​​    Boot Loader UP and RUN-->Check and Choose Linux kernel image (e.g., bzimage) and Root File System (rootfs)

Linux kernel image UP (first part)decompress Linux (main part) to memory

Linux main part ->RUN
START all initial codes

mount rootfs / <<<root
RUN "init" in rootfs
init RUN all apps and INSERT all pre-defined kernel modules
START shell
$>

This is the op principle of network thin client!

How to Mount an NFS Share in Linux

Linux 檔案系統掛載(mount)使用教學與範例, by G. T. Wang

Busybox中httpd、ftpd、telnetd、tftpd、ntpd的用法

Install tftp server:

sudo apt install tftpd-hpa

Now, check whether the tftpd-hpa service is running with the following command:
sudo systemctl status tftpd-hpa

Modify tftpd-hpa
nano /etc/default/tftpd-hpa

改自 /tftpboot

Restart:
sudo systemctl restart tftpd-hpa

kclai@ubuntu16:/tmp$ tftp localhost
tftp> get net.sh
Received 171 bytes in 0.1 seconds
tftp> quit
kclai@ubuntu16:/tmp$

Linux unix-like monolithic architecture+loadable modules

Multiplexing and Resource Sharing

Linux: VFS & System Call

Anatomy of the Linux file system (dentry, inode)

Abstract List (亦可用 Doubly Linked List)

Register Object (register_filesystem) and Use Object


devfs


procfs


Linux v2.4.31 net/socket.c

114static struct file_operations socket_file_ops = { 115 llseek: no_llseek, 116 read: sock_read, 117 write: sock_write, 118 poll: sock_poll, 119 ioctl: sock_ioctl, 120 mmap: sock_mmap, 121 open: sock_no_open, /* special open code to disallow open via /proc */ 122 release: sock_close, 123 fasync: sock_fasync, 124 readv: sock_readv, 125 writev: sock_writev, 126 sendpage: sock_sendpage 127};

與 Linux VFS 溝通

socket(AF_INET, SOCK_STREAM, 0)

net/ipv4/af_inet.c

945struct proto_ops inet_stream_ops = { 946 family: PF_INET, 947 948 release: inet_release, 949 bind: inet_bind, 950 connect: inet_stream_connect, 951 socketpair: sock_no_socketpair, 952 accept: inet_accept, 953 getname: inet_getname, 954 poll: tcp_poll, 955 ioctl: inet_ioctl, 956 listen: inet_listen, 957 shutdown: inet_shutdown, 958 setsockopt: inet_setsockopt, 959 getsockopt: inet_getsockopt, 960 sendmsg: inet_sendmsg, 961 recvmsg: inet_recvmsg, 962 mmap: sock_no_mmap, 963 sendpage: tcp_sendpage 964}; 965

GPIO
因同學有來問, 因此增加說明
這對Embedded Linux 設計很重要的基礎
[Day 7]-【STM32系列】淺入淺出之 General Purpose Input/Output 介紹 (上)

GPIO: You can control GPIO from user space
e.g. control /sys/class/gpio/gpio49/value

/sys/class/gpio/gpio49#> ls
active_low direction edge power subsystem uevent value
#> echo out > direction
#> echo 1 > value
#> echo 0 > value
注意 優缺點! 有些應用不適宜! 此外 debounce 也須處理!!! Appendix A.

SPI
/dev/spidevxx.yy 其中 xx 可能 0, yy 可能 0,1,.. yy 代表 chip select (哪一個 SPI)
user space
fd=open("/dev/spidevxx.yy ",
ioctl (fd, chip mode)

read/write /ioctl
close

對一般的應用 可更進一步參考:
http://www.raspberry-projects.com/pi/programming-in-c/spi/using-the-spi-interface

其中 int SpiWriteAndRead 是重要的做法,還有 memset(&spi[i], 0, sizeof (spi[i])); 也類似我於課程中提的問題! 小心! 很多人忘記這個動作!

用 ioctl 來取代 read/write 有內部設計的原因 , I2C, USB 都有類似的用法


想像

​​​​   user app<<<==================>>> SPI device

SPI interface (CS, CLK, MISO, MOSI) bit frame <-> device

​​​​   client   <<<  Network  programming   >>> server 

兩者觀念一樣!! 也是

​​​​                        螺絲<-----螺紋---->螺帽

的關係


特別提醒
如果使用 GPIO, SPI 等裝置要注意 TIMING 的問題, 若使用 USER SPACE 可能有精準度的問題!

Benchmarking Raspberry Pi GPIO Speed

有關SPI, I²C, NAND Flash, NOR Flash, 可參考

Essential Linux Device Drivers, by Sreekrishnan Venkateswaran

I2C Introduction – Part 1 (Basics)
I2C Protocol Introduction – Part 2 (Advanced Topics)

We will focus on socket layer in this course (network programming).

Remark.

For example, "printf" is not a system call. Try run "strace your_hello_program" , you find it's "write" not printf!

Moreover, fopen, fprintf, strcmp, strcpy, are not system calls. They are functions in dynamic lib libcso.

Try "ldd your_hello_program" ! You can print the shared objects (shared libraries) ! This is an important method to build your new root file system with .shared libraries. See example "man ldd".

// user name is laikc
vdso (virtual dynamic shared object, see man 7 vdso)
Why does the vDSO exist at all? There are some system calls the
kernel provides that user-space code ends up using frequently, to
the point that such calls can dominate overall performance. This
is due both to the frequency of the call as well as the context-
switch overhead that results from exiting user space and entering the kernel.

In x86 32-bit systems, you can
trigger a software interrupt (int $0x80) to tell the kernel you
wish to make a system call.

e.g., gettimeofday

laikc@laikc-VirtualBox:/tmp/demo/laikc/course$ ldd ./ex1_1
linux-vdso.so.1 => (0x00007fff31d0d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff323de0000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff3241b5000)
laikc@laikc-VirtualBox:/tmp/demo/laikc/course$


Performance issue: "copy_to_ user" & "copy_from_ user"

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);

e.g.,

User space <> Kernel space
read(fd, buf, count)/recv <> read(fd, buf,)/recv
<<<<-copy_to_ user

write(fd, buf,count)/send <-> write(fd, buf, )/send
copy from user->>>>>

Virtual Device:

Then we can use the remote devices. For example, mouse, keyboard, sound, memory, disk, display

Network programming is an important skill!"


This is the operation principle of network thin client!
You can, also, boot Windows OS via PXE.

願意再學請看以下:

作者 Greg Kroah-Hartman 提供

Linux Kernel in a Nutshell
This is the web site for the book, Linux Kernel in a Nutshell, by Greg Kroah-Hartman, published by O'Reilly.

License
This book is available under the terms of the Creative Commons Attribution-ShareAlike 2.5 license. That means that you are free to download and redistribute it. The development of the book was made possible, however, by those who purchase a copy from O'Reilly or elsewhere.

http://www.kroah.com/lkn/

請需要的讀者參考


第一步:

對於一般學生 可以進一步學習 x86 Linux

利用 載入 Linux kernel source code
重新 編譯 並可開重新多重開機, 網路有很多善心人士提供許多資料, 我就不寫了.
小心 kernel : 重新編譯 重要事項:
(1) make menuconfig 與你CPU 有關, 因此 Google 時 請加 VM VirtualBox 或你 VMware 的名稱
最好用 VM 來測試你的 kernel, 才不會麻煩
(2) 不要用太新的版本, 學習用舊的即可, 尤其x86 很雜, 安全性很麻煩, 因練習用就儘可不用, 日後正式 用途需要考慮!

如果用量不是很大, Embedded Linux Board也夠用! 省電安全!
樹莓派或 TI BeagleBoard 夠一般 web server, 一般控制, NAS, 等 用了!
(但要 DIY, 請把本課程學好, 才做的好)

:::

後面給進階的使用者


Appendix: System Call

Kernel Part: Depend on kernel version and arch
User Part: Depend on gcc version
Basic file: Check unistd.h, syscall.h,
For example,

#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7

Important command strace:

strace: trace system calls and signals


In general, user space: read() >[sys call](3, ) >kernel [sys call] (__NR_read )

"strace" command help u to see your running system calls and using files, e.g.,"#> strace ./ex1"
If your network program has "gethostname (or gethostname2)", try to see using files.

Be careful, "gethostname" is not thread-safe. If you need not this function, don't use it.


You can add your new system call to kernel source (depends on kernel version)

Remarks.
I am sorry, I can not give u a unique answer.
If you need this future, please see your kernel source.
In practice, you need not this future. This is a good excise for understanding system calls.


Advanced Users

I2C Introduction – Part 1 (Basics)


Appendix: Build a new Linux kernel and Rootfs
x86:
please google!

other ARCH: (Linux architecture)
step 1. toolchain
step 2. linux kernel
step 3. root file system (you can use busybox)
step 4. create your init

usual command (mount, umount, dd, losetup, mke2fs, ..)

mount:

如何mount 特殊 file system 請 google 查詢

dd:

有用的command, 必需小心的危險command, 用錯會哭哭!!
請看 https://en.wikipedia.org/wiki/Dd_(Unix)
例如
dd if=/dev/zero bs=1024 count=1000000 of=file_1GB

複製至 of=/tmp/zero_copy

dd if=file_1GB of=/tmp/zero_copy

dd if=/dev/zero of=/tmp/rootimg bs=1k count=2000 通常用來產生 2MB rootimg 但原因是很多人不知道!


事實上很多人 rootfs 愈來愈大就是沒真正了解學過知識的重點! 其實就是~~全為0 的檔案, 再複製你真正的檔案, 這要 gzip 才壓縮更多!! 否則一堆檔案垃圾 當壓縮檔愈來愈大


Now making it look like a block device instead of just a regular file (See man 8 losetup)

$ losetup /dev/loop0 rootimg

Creating an ext2 file system with the loop device

$ mke2fs -c /dev/loop0

You can mount in /mnt/rootfs (mkdir /mnt/rootfs)

$ mount -t ext2 /dev/loop0 /mnt/rootfs

You can use /mnt/rootfs as your new root file system

prepare your filesdirty work

Finally, unmount and detach

$ umount /dev/loop0
$ losetup -d /dev/loop0

ARM Arch!

一步步教你:如何用Qemu來模擬ARM系統

Using VM:
Lubuntu 12.04: Compile QEMU 2.0.0
Create USB linux (using syslinux):
還有 4M Linux

Use QEMU:
QEMU (ARM Arch) (含 toolchain, kernel, rootfs 產生) (若初級使用 請 google, 有很多!)

Special File System: device files system, sys file system, proc file system

device files system

$:> ls -al /dev
major minor
total 724

lrwxrwxrwx 1 root root 9 Oct 14 22:51 cdrom -> /dev/scd1
lrwxrwxrwx 1 root root 9 Oct 14 22:52 cdrom1 -> /dev/scd0
crw- 1 root tty 5, 1 Jan 19 20:47 console

crww 1 root video 29, 1 Mar 15 2002 fb0autodetect

brw-rw 1 root disk 3, 64 Mar 15 2002 hdb
brw-rw 1 root disk 22, 0 Mar 15 2002 hdc
brw-rw 1 root disk 22, 64 Mar 15 2002 hdd

crw-r- 1 root kmem 1, 1 Sep 28 18:06 mem

crw-rw-rw- 1 root root 1, 3 Sep 28 18:06 null

brw-rw 1 root disk 8, 0 Mar 15 2002 sda //major number=8, minor number=0
brw-rw 1 root disk 8, 1 Mar 15 2002 sda1
brw-rw 1 root disk 8, 2 Mar 15 2002 sda2
brw-rw 1 root disk 8, 3 Mar 15 2002 sda3
brw-rw 1 root disk 8, 4 Mar 15 2002 sda4
brw-rw 1 root disk 8, 16 Mar 15 2002 sdb
brw-rw 1 root disk 8, 17 Mar 15 2002 sdb1
brw-rw 1 root disk 8, 18 Mar 15 2002 sdb2
brw-rw 1 root disk 8, 19 Mar 15 2002 sdb3
brw-rw 1 root disk 8, 20 Mar 15 2002 sdb4

lrwxrwxrwx 1 root root 4 Sep 28 18:05 stderr -> fd/2
lrwxrwxrwx 1 root root 4 Sep 28 18:05 stdin -> fd/0
lrwxrwxrwx 1 root root 4 Sep 28 18:05 stdout -> fd/1
crw-rw-rw- 1 root tty 5, 0 Sep 28 18:06 tty
crw- 1 root root 4, 0 Sep 28 18:06 tty0
crw- 1 root root 4, 1 Jan 19 14:59 tty1

crw-rw 1 root dialout 4, 64 Mar 15 2002 ttyS0
crw-rw 1 root dialout 4, 65 Mar 15 2002 ttyS1
crw-rw 1 root dialout 4, 66 Mar 15 2002 ttyS2
crw-rw 1 root dialout 4, 67 Mar 15 2002 ttyS3
crw-rw 1 root dialout 188, 0 Mar 15 2002 ttyUSB0 //不一定在這裡
crw-rw 1 root dialout 188, 1 Mar 15 2002 ttyUSB1
crrr 1 root root 1, 9 Jan 19 20:46 urandom
drwxr-xr-x 2 root root 4096 Sep 28 18:05 usb

crw-rw-rw- 1 root root 1, 5 Sep 28 18:06 zero

//下面這個是 自己寫的 device (假設的)
crw-rw-rw- 1 root root 100, 0 Sep 28 18:06 mydev

crw-rw c 表示 char device
b??? b 表示 block device


//問題來了
(1) /dev/mydev 如何產生 ? major number=100, minor number=0 如何產生?
(2) user space 如何使用?

(1)

引 用寫的很好的 Writing a Linux Kernel Module — Part 2: A Character Device
的file_operations 資料:

struct file_operations { struct module *owner; // Pointer to the LKM that owns the structure loff_t (*llseek) (struct file *, loff_t, int); // Change current read/write position in a file ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); // Used to retrieve data from the device ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); // Used to send data to the device ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); // Asynchronous read ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); // Asynchronous write ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); // possibly asynchronous read ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); // possibly asynchronous write int (*iterate) (struct file *, struct dir_context *); // called when VFS needs to read the directory contents unsigned int (*poll) (struct file *, struct poll_table_struct *); // Does a read or write block? long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); // Called by the ioctl system call long (*compat_ioctl) (struct file *, unsigned int, unsigned long); // Called by the ioctl system call int (*mmap) (struct file *, struct vm_area_struct *); // Called by mmap system call int (*mremap)(struct file *, struct vm_area_struct *); // Called by memory remap system call int (*open) (struct inode *, struct file *); // first operation performed on a device file int (*flush) (struct file *, fl_owner_t id); // called when a process closes its copy of the descriptor int (*release) (struct inode *, struct file *); // called when a file structure is being released int (*fsync) (struct file *, loff_t, loff_t, int datasync); // notify device of change in its FASYNC flag int (*aio_fsync) (struct kiocb *, int datasync); // synchronous notify device of change in its FASYNC flag int (*fasync) (int, struct file *, int); // asynchronous notify device of change in its FASYNC flag int (*lock) (struct file *, int, struct file_lock *); // used to implement file locking};

基本想法: Object Model (簡化說明)

(a)
Write a kernel module mydev.c ->gcc (You Need Makefile, Kernel Source and strip)->mydev.ko

kernel module mydev.c (完整寫法可參考http://derekmolloy.ie/writing-a-linux-kernel-module-part-2-a-character-device/ , 他的好例子複雜一點, register_chrdev(100,"mydev",&myfp); 可以取代register_chrdev(0, DEVICE_NAME, &fops);但必須確保 major 100 可用!)

一般而言, 作者 register_chrdev(0, DEVICE_NAME, &fops) 是比較好的方式~ 這裡 要讓讀者練習與了解 mknod

​​​​(a.1) write myfp ===>file_operations  // 模擬檔案操作

​​​​(a.2) you must register a char device

​​​​    register_chrdev(100,"mydev",&myfp);   

#!> insmod mydev
/* become a virtual char device /
#!> mknod /dev/mydev c 100 0
/
make a device node for user space app*/

Then you can write your app hellodev.c

user space (open, read, write, close, ioctl, ...) <===> kernel space fd= open ("/dev/mydev",...) <===> file_operations open ioctl(fd, <===>file_operations ioctl (unlocked_ioctl or compat_ioctl) read(fd,...)/write <===> file_operations read /write close(fd) <===> file_operations read /release select(fd, ... <===> file_operations poll

Appendix A.

虛擬程式: square wave

​​​​    loop:
​​​​        echo 1 > /sys/class/gpio/gpio49/value

​​​​           sleep_msec 1
​​​​           echo  0 > /sys/class/gpio/gpio49/value
​​​​           sleep_msec 1
​​​​      goto loop

會如何? 請思考可能的問題! 我上課會說! 事實上這虛擬程式有限制

mmap:

https://jasonblog.github.io/note/linux_driver/mmap_driver_implementation.html


Linux的二號功臣 Alan Cox

How to Write Linux Mouse Drivers, by Alan Cox

Kernel Korner - Sleeping in the Kernel