chapter 3-Char Device Driver

Slides:



Advertisements
Similar presentations
DEVICE DRIVER VINOD KAMATH CS691X PROJECT WORK. Introduction How to write/install device drivers Systems, Kernel Programming Character, Block and Network.
Advertisements

Linux device-driver issues
Device Drivers. Linux Device Drivers Linux supports three types of hardware device: character, block and network –character devices: R/W without buffering.
RT_FIFO, Device driver.
Sogang University Advanced Operating Systems (Linux Device Drivers) Advanced Operating Systems (Linux Device Drivers) Sang Gue Oh, Ph.D.
Lecture for Lab 3, Exp1 of EE505 (Developing Device Driver) T.A. Chulmin Kim CoreLab. Mar, 11, 2011 [XenSchedulerPaper_Hotcloud-commits] r21 - /
Computer System Laboratory
R4 Dynamically loading processes. Overview R4 is closely related to R3, much of what you have written for R3 applies to R4 In R3, we executed procedures.
CSCC69: Operating Systems
Building and Running Modules Sarah Diesburg COP 5641.
Using VMX within Linux We explore the feasibility of executing ROM-BIOS code within the Linux x86_64 kernel.
Essential System Administration 3rd Edition Chapter 2 The Unix Way(Cont.) University Of Palestine.
Embedded Systems Programming Writing Device Drivers.
63 UQC152H3 Advanced OS Writing a Device Driver. 64 The SCULL Device Driver Simple Character Utility for Loading Localities 6 devices types –Scull-03.
More Shell Basics CS465 - Unix. Unix shells User’s default shell - specified in /etc/passwd file To show which shell you are currently using: $ echo $SHELL.
Dynamic Allocation and Linked Lists. Dynamic memory allocation in C C uses the functions malloc() and free() to implement dynamic allocation. malloc is.
Char Drivers Linux Kernel Programming CIS 4930/COP 5641.
Data Structures in the Kernel Sarah Diesburg COP 5641.
Char Drivers Sarah Diesburg COP5641. Resources LDD Chapter 3 Red font in slides where up-to-date code diverges from book LDD module source code for 3.2.x.
Loadable Kernel Modules Dzintars Lepešs The University of Latvia.
Operating System Program 5 I/O System DMA Device Driver.
Linux Installation and Administration – Lesson 5 Tutor: George Papamarkos Topic: Devices in Linux.
Filesystem Hierarchy Standard (FHS) –Standard of outlining the location of set files and directories on a Linux system –Gives Linux software developers.
Lesson 7-Creating and Changing Directories. Overview Using directories to create order. Managing files in directories. Using pathnames to manage files.
Chapter Nine Advanced Shell Scripting1 System Programming Advanced Shell Scripting.
File Permissions. What are the three categories of users that apply to file permissions? Owner (or user) Group All others (public, world, others)
Lecture 2: Linux devices Roei Ben-Harush Agenda 1 1 Linux Devices About next Assignment Roei Ben-Harush 2015 Reminder.
Agenda Link of the week Use of Virtual Machine Review week one lab assignment This week’s expected outcomes Review next lab assignments Break Out Problems.
Kernel Modules. Kernel Module Pieces of code that can be loaded and unloaded into the kernel upon demand. Compiled as an independent program With appropriate.
Using the /proc File System with “scull” Sarah Diesburg COP 5641.
CPS4200 Unix Systems Programming Chapter 2. Programs, Processes and Threads A program is a prepared sequence of instructions to accomplish a defined task.
Files and Directories File types stat functions for file information
LIN Unix Lecture 5 Unix Shell Scripts. LIN Command Coordination ; && || command1 ; command2 Interpretation: Do command 1. Then do command.
©Colin Jamison 2004 Shell scripting in Linux Colin Jamison.
LOGO System Call. Introduction System call is the mechanism used by an application program to request service from the OS. Users use it to communicate.
What is a Process? u A process is an executable “cradle” in which a program may run u This “cradle” provides an environment in which the program can run,
Linux Device Driver 2009/04/08. Reference Book Another Reference Book Embedded Linux Primer: A Practical, Real-World Approach By Christopher Hallinan.
Week Two Agenda Announcements Link of the week Use of Virtual Machine Review week one lab assignment This week’s expected outcomes Next lab assignments.
Interfacing Device Drivers with the Kernel
B LOCK L AYER S UBSYSTEM Linux Kernel Programming CIS 4930/COP 5641.
Ted Baker  Andy Wang COP 5641 / CIS 4930
Lab 12 Department of Computer Science and Information Engineering National Taiwan University Lab12 – Driver 2014/12/16 1 /21.
COMP 3438 – Part I - Lecture 5 Character Device Drivers
C++ Functions A bit of review (things we’ve covered so far)
Lecture 3 Module Programming and Device Driver (Homework#1 included) Kyu Ho Park Sept. 15, 2015.
INTRODUCTION TO SHELL SCRIPTING By Byamukama Frank
Getting Started with Linux
Memory Management.
Linux Device Model A device model after 2.5
Chapter 11 Command-Line Master Class
Lecture 3 Module Programming and Device Driver (Homework#1 included)
Linux Kernel Module Programming
Computer System Laboratory
The Linux Operating System
Linux Kernel Driver.
Want to play a game? – Linux Kernel Modules
Scull device 사용 예 강서일( ) 최정욱( ).
C Basics.
What is Bash Shell Scripting?
Circular Buffers, Linked Lists
Introduction to Linux Device Drivers
Intro to Kernel Modules and /proc
Classes and Objects.
Shell Programming.
Linux Shell Script Programming
Implementation of Embedded OS
Computer System Laboratory
Software I: Utilities and Internals
Loadable Kernel Modules
Review.
Presentation transcript:

chapter 3-Char Device Driver chenbo2008@ustc.edu.cn 中国科学技术大学软件学院

ls -l /dev

Example from the text You can download example for the text at http://examples.oreilly.com/linuxdrive3/ 加载 卸载

The script to load the built modules scull_load Remember: make it executable first. Runs it with superuser’s privilege. #!/bin/sh # $Id: scull_load,v 1.4 2004/11/03 06:19:49 rubini Exp $ module="scull" device="scull" mode="664" # Group: since distributions do it differently, look for wheel or use staff if grep -q '^staff:' /etc/group; then group="staff" else group="wheel" fi simple character utility for loading localities shell编程是以"#"为注释,但对"#!/bin/sh"却不是。"#!/bin/sh"是对shell的声明,说明你所用的是那种类型的shell及其路径所在。如果没有声明,则脚本将在默认的shell中执行,默认shell是由用户所在的系统定义为执行shell脚本的shell.如果脚本被编写为在Kornshell ksh中运行,而默认运行shell脚本的为C shell csh,则脚本在执行过程中很可能失败。

The script to load the built modules # invoke insmod with all arguments we got # and use a pathname, as insmod doesn't look in . by default /sbin/insmod ./$module.ko $* || exit 1 # retrieve major number major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices) # Remove stale nodes and replace them, then give gid and perms # Usually the script is shorter, it's scull that has several devices in it. rm -f /dev/${device}[0-3] mknod /dev/${device}0 c $major 0 mknod /dev/${device}1 c $major 1 mknod /dev/${device}2 c $major 2 mknod /dev/${device}3 c $major 3 ln -sf ${device}0 /dev/${device} chgrp $group /dev/${device}[0-3] chmod $mode /dev/${device}[0-3] rm -f /dev/${device}pipe[0-3] mknod /dev/${device}pipe0 c $major 4 mknod /dev/${device}pipe1 c $major 5 mknod /dev/${device}pipe2 c $major 6 mknod /dev/${device}pipe3 c $major 7 ln -sf ${device}pipe0 /dev/${device}pipe chgrp $group /dev/${device}pipe[0-3] chmod $mode /dev/${device}pipe[0-3] Scull_load /sbin/insmod ./$module.ko $* || exit 1 ?

The script to load the built modules rm -f /dev/${device}single mknod /dev/${device}single c $major 8 chgrp $group /dev/${device}single chmod $mode /dev/${device}single rm -f /dev/${device}uid mknod /dev/${device}uid c $major 9 chgrp $group /dev/${device}uid chmod $mode /dev/${device}uid rm -f /dev/${device}wuid mknod /dev/${device}wuid c $major 10 chgrp $group /dev/${device}wuid chmod $mode /dev/${device}wuid rm -f /dev/${device}priv mknod /dev/${device}priv c $major 11 chgrp $group /dev/${device}priv chmod $mode /dev/${device}priv Scull_load

The script to load the built modules lrwxrwxrwx 1 root root 6 2007-03-27 06:52 scull -> scull0 crw-rw-r-- 1 root wheel 254, 0 2007-03-27 06:52 scull0 crw-rw-r-- 1 root wheel 254, 1 2007-03-27 06:52 scull1 crw-rw-r-- 1 root wheel 254, 2 2007-03-27 06:52 scull2 crw-rw-r-- 1 root wheel 254, 3 2007-03-27 06:52 scull3 lrwxrwxrwx 1 root root 10 2007-03-27 06:52 scullpipe -> scullpipe0 crw-rw-r-- 1 root wheel 254, 4 2007-03-27 06:52 scullpipe0 crw-rw-r-- 1 root wheel 254, 5 2007-03-27 06:52 scullpipe1 crw-rw-r-- 1 root wheel 254, 6 2007-03-27 06:52 scullpipe2 crw-rw-r-- 1 root wheel 254, 7 2007-03-27 06:52 scullpipe3 crw-rw-r-- 1 root wheel 254, 11 2007-03-27 06:52 scullpriv crw-rw-r-- 1 root wheel 254, 8 2007-03-27 06:52 scullsingle crw-rw-r-- 1 root wheel 254, 9 2007-03-27 06:52 sculluid crw-rw-r-- 1 root wheel 254, 10 2007-03-27 06:52 scullwuid

The script to load/unload the built modules scull_unload Again, make it executable and run as superuser. #!/bin/sh module="scull" device="scull" # invoke rmmod with all arguments we got /sbin/rmmod $module $* || exit 1 # Remove stale nodes rm -f /dev/${device} /dev/${device}[0-3] rm -f /dev/${device}priv rm -f /dev/${device}pipe /dev/${device}pipe[0-3] rm -f /dev/${device}single rm -f /dev/${device}uid rm -f /dev/${device}wuid

The script to load the built modules Being a character device, you can read/write character string to it. #echo “This is a test” > /dev/scull #cat < /dev/scull The text use the example scull to illustrate all necessary ingredients in developing character device driver. How to create an character device and hook it up the a device file? Involves two passes of operation To the kernel, initiates the device and get/announce the major-minor number. To the user program, creates a file inside the directory /dev.

dev_t Within the kernel, device numbers is of dev_t type(defined in <include/linux/types.h> ). As of Version 2.6.0 of the kernel, dev_t is a 32-bit quantity with 12 bits set aside for the major number and 20 bits for the minor number. A prior to 2.6.x, size of major and minor are both 8bits.

Device Number type dev_t Macros in retrieving device numbers: MAJOR(dev_t dev); MINOR(dev_t dev); Macros in wraping device numbers: MKDEV(int major, int minor); Defined in <linux/kdev_t.h>. <linux/kdev_t.h> 3 #ifdef __KERNEL__ 4 #define MINORBITS 20 5 #define MINORMASK ((1U << MINORBITS) - 1) 6 7 #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) 8 #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) 9 #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))

Allocating and Freeing Device Numbers Adding a driver to the system you will have to first register it to the kernel.dev_t is required for registration. How to get the value? Statically and dynamically. Using following functions: Defined as function in: fs/char_dev.c Defined as function prototype in: include/linux/fs.h * fs/char_dev.c */ 1289 extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *); 1290 extern int register_chrdev_region(dev_t, unsigned, const char *); 1291 extern int register_chrdev(unsigned int, const char *, 1292 struct file_operations *); 1293 extern int unregister_chrdev(unsigned int, const char *); 1294 extern void unregister_chrdev_region(dev_t, unsigned);

Allocating and Freeing Device Numbers Having a static device number, you can assign the major number during the module’s initialization. using register_chrdev() or register_chrdev_region() int register_chrdev(unsigned int major, const * char name ,operation *fops); major -The major number for the driver. name -The name of the driver (as seen in /proc/devices). fops -The &file_operations structure pointer. Noticed, no minor number is required. int register_chrdev_region(dev_t first,unsigned int count, char *name); first : the beginning device number of the range. count : the requesting number of contiguous devices. name : the name of the device (will appear in /proc/devices and sysfs.) Return 0 if successful. register_chrdev_region(dev_num,2,"my_dev")

for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major > major || ((*cp)->major == major && ( ((*cp)->baseminor >= baseminor) || ((*cp)->baseminor + (*cp)->minorct > baseminor)) )) break; /* Check for overlapping minor ranges. */ if (*cp && (*cp)->major == major) { int old_min = (*cp)->baseminor; int old_max = (*cp)->baseminor + (*cp)->minorct - 1; int new_min = baseminor; int new_max = baseminor + minorct - 1; /* New driver overlaps from the left. */ if (new_max >= old_min && new_max <= old_max) { ret = -EBUSY; goto out; } /* New driver overlaps from the right. */ if (new_min <= old_max && new_min >= old_min) { cd->next = *cp; *cp = cd; mutex_unlock(&chrdevs_lock); return cd; out: kfree(cd); return ERR_PTR(ret); static struct char_device_struct * __register_chrdev_region(unsigned int major, unsigned int baseminor, int minorct, const char *name) { struct char_device_struct *cd, **cp; int ret = 0; int i; cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); if (cd == NULL) return ERR_PTR(-ENOMEM); mutex_lock(&chrdevs_lock); if (major == 0) { for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) if (chrdevs[i] == NULL) break; if (i == 0) { ret = -EBUSY; goto out; } major = i; ret = major; cd->major = major; cd->baseminor = baseminor; cd->minorct = minorct; strncpy(cd->name,name, 64); i = major_to_index(major);

Allocating and Freeing Device Numbers Linux kernel dynamically allocates a major number using function: alloc_chrdev_region() alloc_chrdev_region() int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name); dev: return the first number in your allocated range on successful completion. firstminor: the requested first minor number to use; it is usually 0. count and name: work like those given to register_chrdev_region. int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name) { struct char_device_struct *cd; cd = __register_chrdev_region(0, baseminor, count, name); if (IS_ERR(cd)) return PTR_ERR(cd); *dev = MKDEV(cd->major, cd->baseminor); return 0; }

Allocating and Freeing Device Numbers Device numbers are freed by: unregister_chrdev_region()or unregister_chrdev(). Call these functions in your module’s cleanup function. int unregister_chrdev (unsigned int major, const char * name); major : major number for the driver. name : name of the driver (as seen in /proc/devices). void unregister_chrdev(unsigned int major, const char *name) { struct char_device_struct *cd; cd = __unregister_chrdev_region(major, 0, 256); if (cd && cd->cdev) cdev_del(cd->cdev); kfree(cd); }

Allocating and Freeing Device Numbers unregister_chrdev_region(). int unregister_chrdev_region(dev_t from, unsigned count, const char *name) from: the requested first minor number to use, it is usually 0. count and name: work like those given to register_chrdev_region. void unregister_chrdev_region(dev_t from, unsigned count) { dev_t to = from + count; dev_t n, next; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n)+1, 0); if (next > to) next = to; kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); }

__unregister_chrdev_region static struct char_device_struct * __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) { struct char_device_struct *cd = NULL, **cp; int i = major_to_index(major); mutex_lock(&chrdevs_lock); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major == major && (*cp)->baseminor == baseminor && (*cp)->minorct == minorct) break; if (*cp) { cd = *cp; *cp = cd->next; } mutex_unlock(&chrdevs_lock); return cd;

Installation of a driver with dynamic allocated majornumbers The problem: since it is dynamical-allocated, the major number assigned to the module is unknown and unable to create the device nodes (files) in advance. Using information inside of /proc/devices However, since once the number has been assigned, it is registered in the /proc/devices. Consequently, using a simple shell script can retrieving the major number, and create the corresponding nodes in /dev. Take script scull_load for example.

Installation of a driver with dynamic allocated majornumbers

Installation of a driver with dynamic allocated majornumbers The script to creates nodes in /dev #!/bin/sh module="scull" device="scull" mode="664" # invoke insmod with all arguments we got # and use a pathname, as newer modutils don't look in . by default # this will generate new entries in /proc/devices. The $* is the positional # parameter to pass command line parameters to insmod. /sbin/insmod ./$module.ko $* || exit 1 # remove stale nodes rm -f /dev/${device}[0-3]

Installation of a driver with dynamic allocated majornumbers The script to creates nodes in /dev # Retrieve major number form /proc/devices using awk # Noticed that the script form the text has bugs, i.e. it should be \$2 instead of # \\$2, same to the # entry \$1. The awk scan /proc/devices for pattern “\$module\”, # if it find it, the first item of the scanned line is “printed.” major=$(awk "\$2= =\"$module\" {print \$1}" /proc/devices) # Use mknod to create corresponding devices in /dev. # Since a total of 4 scull character “c” devices are created, mknod is invoked 4 times. mknod /dev/${device}0 c $major 0 mknod /dev/${device}1 c $major 1 mknod /dev/${device}2 c $major 2 mknod /dev/${device}3 c $major 3

Installation of a driver with dynamic allocated majornumbers The script to creates nodes in /dev # give appropriate group/permissions, and change the group. # Not all distributions have staff, some have "wheel" instead. # It doesn’t have to be staff or whell, it could be anything you want. group="staff“ # If “staff” is un-defined, use wheel instead. grep -q '^staff:' /etc/group || group="wheel“ # File name expansion of class [0-3] is performed here. chgrp $group /dev/${device}[0-3] chmod $mode /dev/${device}[0-3]

The scull do it both ways The scull provides both ways: the major –minor number can be either – Dynamically allocated or load/compile time assigned In line 615 of main.c int scull_init_module(void) : if (scull_major) { /*value of scull_major is assigned at scull.h to be 0 dev = MKDEV(scull_major, scull_minor); result = register_chrdev_region(dev, scull_nr_devs, "scull"); } else { result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull"); scull_major = MAJOR(dev); }

The scull do it both ways By setting the major number in scull.h Compile time In line 615 of main.c int scull_init_module(void) : if (scull_major) { /*value of scull_major is assigned at scull.h to be 0 dev = MKDEV(scull_major, scull_minor); result = register_chrdev_region(dev, scull_nr_devs, "scull"); } else { result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull"); scull_major = MAJOR(dev); } In scull.h line 47-49 #ifndef SCULL_MAJOR #define SCULL_MAJOR 0 /* dynamic major by default */ #endif

The scull do it both ways By setting the major number in scull.h Compile time In line 42 of main.c int scull_major = SCULL_MAJOR; : In line 615 of main.c int scull_init_module(void) if (scull_major) { /*value of scull_major is assigned at scull.h to be 0 dev = MKDEV(scull_major, scull_minor); result = register_chrdev_region(dev, scull_nr_devs, "scull"); } else { result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull"); scull_major = MAJOR(dev); } In scull.h line 47-49 #ifndef SCULL_MAJOR #define SCULL_MAJOR 0 /* dynamic major by default */ #endif

The scull do it both ways load time : scull_load scull_major=10 By setting the major number an module parameter in main.c In line 615 of main.c int scull_init_module(void) : if (scull_major) { /*value of scull_major is assigned at scull.h to be 0 dev = MKDEV(scull_major, scull_minor); result = register_chrdev_region(dev, scull_nr_devs, "scull"); } else { result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull"); scull_major = MAJOR(dev); } In main.c 47-51 module_param(scull_major, int, S_IRUGO); module_param(scull_minor, int, S_IRUGO); module_param(scull_nr_devs, int, S_IRUGO); module_param(scull_quantum, int, S_IRUGO); module_param(scull_qset, int, S_IRUGO);

Some Important Data Structures Most of the fundamental driver operations involve some important kernel data structures, called file_operations, file, and inode. cdev

File Operations The file_operations structure sets up operations that applies to the reserved device numbers. It is defined in <linux/fs.h>, a collection of function pointers. 关联设备(号)及在其设备上的操作。这些操作主要用来实现系统调用,命名为open、read 等。

Example from the text Each opened file is associated with its own set of functions (by including a field called f_op that points to a file_operations structure).

File Operations

File Operations The scull device driver implements only the most important device operations. Its file_operations structure is as follows: Not all operations given in file have to be supported. struct file_operations scull_fops = { .owner = THIS_MODULE, .llseek = scull_llseek, .read = scull_read, .write = scull_write, .ioctl = scull_ioctl, .open = scull_open, .release = scull_release, };

Difference between structure definition

The cdev The functions hook the device’s file_operations to the cdev when adding the character device structure. 5 struct cdev { 6 struct kobject kobj; 7 struct module * owner; 8 struct file_operations * ops; 9 struct list_head list; 10 dev_t dev; 11 unsigned int count; 12 };

The initialization of the module struct scull_qset { void **data; struct scull_qset *next; }; struct scull_dev { struct scull_qset *data; /* Pointer to first quantum set */ int quantum; /* the current quantum size */ int qset; /* the current array size */ unsigned long size; /* amount of data stored here */ unsigned int access_key; /* used by sculluid and scullpriv */ struct semaphore sem; /* mutual exclusion semaphore */ struct cdev cdev; /* Char device structure */

The initialization of the module

thank you !