linux device drivers
play

Linux Device Drivers Linux Device Drivers Dr. Wolfgang Koch 1. - PowerPoint PPT Presentation

Linux Device Drivers Linux Device Drivers Dr. Wolfgang Koch 1. Introduction Friedrich Schiller University Jena 2. Kernel Modules Department of Mathematics and 3. Char Drivers Computer Science 4. Advanced Char Drivers Jena, Germany 5.


  1. Linux Device Drivers Linux Device Drivers Dr. Wolfgang Koch 1. Introduction Friedrich Schiller University Jena 2. Kernel Modules Department of Mathematics and 3. Char Drivers Computer Science 4. Advanced Char Drivers Jena, Germany 5. Interrupts wolfgang.koch@uni-jena.de 3. Char Drivers 3. Char Drivers – cont. � File Operations � read( ), put_user( ) � Device Files, Major & Minor Numbers � open( ), release( ), Usage Count � file_operations Structure � file Structure, llseek( ) � register_chardev, Choice of Major Number � write( ), get_user( ) � mknod � Race conditions, Atomic Variables � register_chardev_region – the new way � Spinlocks, Semaphores

  2. File Operations File Operations classes of devices (drivers) – in UNIX (Linux) input/output devices are treated very much like � Character (char) devices: ordinary files (remember – can be accessed as a stream of bytes (characters) file descriptor 0: standard input , fd 1: standard output ) � Block devices: in this way easy redirection of input and output is possible read/write from/to the hardware – whole blocks (e.g. 2 KBytes) fast access to the hardware (using DMA) – applications use the same system calls: filesystems, storage devices open(), read(), write(), ioctl(), ... close() but usually the user can use the same (unblocked) system calls: open(), read(), write(), ... (buffered in/output) both (files and devices) can be accessed as a stream of bytes both are represented as nodes in the file system both types are accessed through a filesystem node 5 6 File Operations File Operations applications use the same system calls to access devices as with char devices, block devices ordinary files ( #include <unistd.h>, <fcntl.h> ): 3rd type: open() ( see 'man 2 open' etc. read() closer descriptions are given Network interfaces write() in the following chapters ) different from char or block drivers ioctl() (data packages instead of streams, lseek() different system calls, no filesystem nodes ) ... close() in this tutorial we only deal with char drivers to every supported function there is a counterpart (a method) (they are relatively simple, but usually sufficient, in the driver (not all functions are always supported: most drivers are char drivers ) lseek() not in serial input) 7 8

  3. Device Files Device Files input/output devices are treated very much like ordinary files ordinary files, ls -l : both are represented as nodes in the filesystem -rw-r--r-- 1 nwk users 130 2007-06-13 12:04 Makefile ordinary files, ls -l : -rw-r----- 1 nwk users 1630 2007-05-27 13:59 rwko1.c -rw-r--r-- 1 nwk users 130 2007-06-13 12:04 Makefile file size -rw-r----- 1 nwk users 1630 2007-05-27 13:59 rwko1.c -r--r--r-- 1 nwk users 1928 2007-05-30 13:52 rwko1.o special files, device files, ls -l /dev/ : -rw-r----- 1 nwk users 2051 2007-05-27 14:51 rwko2.c brw------- 1 nwk disk 2, 0 2007-03-14 14:07 /dev/fd0 crw--w--w- 1 nwk tty 4, 0 2007-08-21 14:14 /dev/tty0 special files, device files, ls -l /dev/ : crw-rw---- 1 root tty 4, 1 2007-08-25 09:25 /dev/tty1 brw------- 1 nwk disk 2, 0 2007-03-14 14:07 /dev/fd0 crw--w--w- 1 nwk tty 4, 0 2007-08-21 14:14 /dev/tty0 major, minor number crw-rw---- 1 root tty 4, 1 2007-08-25 09:25 /dev/tty1 c – char device crw-rw---- 1 root root 13,32 2007-03-14 14:07 /dev/mouse b – block device fd0, tty1, ... “device files“ 9 10 Major & Minor Number Major & Minor Number crw--w--w- 1 nwk tty 4, 0 2007-08-21 14:14 /dev/tty0 crw--w--w- 1 nwk tty 4, 0 2007-08-21 14:14 /dev/tty0 crw-rw---- 1 root tty 4, 1 2007-08-25 09:25 /dev/tty1 crw-rw---- 1 root tty 4, 1 2007-08-25 09:25 /dev/tty1 major, minor number major, minor number the major number identifies the driver associated with the device the major number identifies the driver associated with the device, different devices may have the same major number – they are the major number is a small integer (0 .. 255 in version 2.4), managed by the same driver (may be in a different way according currently used numbers can be found in /proc/devices to the minor number) – ( 255 – a very limited number → 12 bit in kernel 2.6) modern kernels allow multiple drivers to share a major number device files are created by the mknod command: an application identifies the device by its device file name, # mknod devfilename c major minor the kernel uses the major number at open time to dispatch (mknod /dev/mydev c 253 0) execution to the appropriate driver they can be removed by # rm devfilename 11 12

  4. file_operations Structure file_operations Structure #include <linux/fs.h> applications use system calls to access devices: open(), read(), write(), ... ssize_t device_read (struct file *filp, char *buffer, size_t len, loff_t *offs); to every supported function there is a counterpart int device_open (struct inode *, struct file *); (a method – like OOP, polymorphy) in the driver int device_release (struct inode *, struct file *); (not all functions are supported in every driver) static struct file_operations fops = { the kernel uses the file_operations structure (defined in read: device_read, <linux/fs.h> ) to access the driver's functions open: device_open, release: device_release, for every possible function (system call) it contains a pointer owner: THIS_MODULE to the function in the driver that implements this operation – }; or NULL for unsupported operations (maybe defaults) 13 14 file_operations Structure register_chardev static struct file_operations fops = { the old way (still available in kernel 2.6 – emulated) read: device_read, open: device_open, static int major = 240; release: device_release, static char dev_name[]="my_dev"; owner: THIS_MODULE // appears in /proc/devices }; int rwko_init(void) { the tagged initialization of a structure (extension in gcc), int res; order doesn’t matter, all the rest of the fields are set to NULL res = register_chrdev (major, dev_name, &fops); → portable (the definition of the structure often has changed) if (res<0) { print_x(...); return res; } owner field: used to maintain the usage count return 0; 15 16 }

  5. register_chardev register_chardev res = register_chrdev (major, dev_name, &fops); removing the driver, releasing the major number: if (res<0) { print_x(...); return res; } void rwko_exit(void) { #include <linux/fs.h> int k = unregister_chrdev (major, dev_name); int register_chrdev( if (k < 0) { unsigned int major, sprintf(me,“exit error %d \r\n“, k); const char *name, print_x(me); struct file_operations *fops } ); } return value: negative on failure major and dev_name must match, later release of the if major=0 – dynamic allocation of a major number (-> res) major number (after failing here) will be difficult, exit() has no return value – issue a warning ! 17 18 Choice of Major Number Choice of Major Number the major number identifies the driver associated with the device if we call register_chrdev(major, dev_name, &fops) with major=0 – we get a dynamically allocated major number the major number is a small integer (0 .. 255 in version 2.4), int rwko_init(void) list of most common devices in Documentation/devices.txt → 240-254 local/experimental use { major = register_chrdev(0, dev_name, &fops); if (major<0) { print_x(); return major; } currently used numbers in /proc/devices sprintf(me,“ Major: %d \r\n“, major); if we call register_chrdev(major, dev_name, &fops); print_x(me); return 0; with major=0 – } we get a dynamically allocated major number drawback: we cannot run mknod in advance 19 20

  6. mknod mknod # insmod rwko1.o ==> Major: 253 dynamically allocated major number – we cannot run mknod in advance > less /proc/devices Character devices: in rwko1.c : ... major = register_chrdev(0, "rw1dev", &fops); 253 rw1dev sprintf(me,“ Major: %d \r\n“, major); 254 pcmcia print_x(me); ... # mknod /dev/mydev c 253 0 # insmod rwko1.ko ==> Major: 253 >ls -l /dev/my* crw-r--r-- 1 root root 253, 0 2007-08-21 15:10 /dev/mydev > less /proc/devices Character devices: # chmod 666 /dev/mydev (if necessary) ... 253 rw1dev <=== # rm /dev/mydev 254 pcmcia 21 22 mknod mknod this can be done with the help of a shell script (owner root) dynamically allocated major number – using awk: we cannot run mknod in advance #!/bin/sh module="rwko1" 1. run insmod file.ko devnam="rw1dev" 2. retrieve major ( /proc/devices ) device="mydev" 3. run mknod /dev/name c major 0 insmod ./$module.ko $* || exit 1 4. run chmod (if necessary) 5. check ls -l /dev/ major=`awk "\\$2==\"$devnam\" {print \\$1}" \ /proc/devices` this can be done with the help of a shell script using awk # echo major = $major mknod /dev/$device c $major 0 23 24

Recommend


More recommend