Introduction to Device Drivers Part-1

Similar documents
Character Device Drivers

CS5460/6460: Operating Systems. Lecture 24: Device drivers. Anton Burtsev April, 2014

Unix (Linux) Device Drivers

Introduction Reading Writing scull. Linux Device Drivers - char driver

Designing and developing device drivers. Coding drivers

Linux Device Drivers. 3. Char Drivers. 1. Introduction 2. Kernel Modules 3. Char Drivers 4. Advanced Char Drivers 5. Interrupts

Virtual File System (VFS) Implementation in Linux. Tushar B. Kute,

Linux Device Drivers. 3. Char Drivers cont. 3. Char Drivers. 1. Introduction 2. Kernel Modules 3. Char Drivers 4. Advanced Char Drivers 5.

Linux Device Drivers

CS 378 (Spring 2003)

Linux Kernel Modules & Device Drivers April 9, 2012

REVISION HISTORY NUMBER DATE DESCRIPTION NAME

BLOCK DEVICES. Philipp Dollst

Linux drivers - Exercise

What is a Linux Device Driver? Kevin Dankwardt, Ph.D. VP Technology Open Source Careers

The device driver (DD) implements these user functions, which translate system calls into device-specific operations that act on real hardware

Linux Device Driver. Analog/Digital Signal Interfacing

Kernel Modules. Kartik Gopalan

Finish up OS topics Group plans

Character Device Drivers One Module - Multiple Devices

Device Drivers Demystified ESC 117. Doug Abbott, Principal Consultant Intellimetrix. Why device drivers? What s a device driver?

NPTEL Course Jan K. Gopinath Indian Institute of Science

MP3: VIRTUAL MEMORY PAGE FAULT MEASUREMENT

USB. Development of a USB device driver working on Linux and Control Interface. Takeshi Fukutani, Shoji Kodani and Tomokazu Takahashi

7.4 Simple example of Linux drivers

CSE 333 SECTION 3. POSIX I/O Functions

3 Character Drivers. 3.1 The Design of scullc. Linux Device Drivers in Assembly

UNIX System Calls. Sys Calls versus Library Func

Introduction to Linux Device Drivers Recreating Life One Driver At a Time

The course that gives CMU its Zip! I/O Nov 15, 2001

Logical disks. Bach 2.2.1

Rights to copy. Dongkun Shin, SKKU

Operating systems for embedded systems

RCU. ò Walk through two system calls in some detail. ò Open and read. ò Too much code to cover all FS system calls. ò 3 Cases for a dentry:

VFS, Continued. Don Porter CSE 506

Important Dates. October 27 th Homework 2 Due. October 29 th Midterm

Operating systems for embedded systems. Embedded Operating Systems

Step Motor. Step Motor Device Driver. Step Motor. Step Motor (2) Step Motor. Step Motor. source. open loop,

RF-IDs in the Kernel -- Episode III: I want to File Away

Design and Implementation of an Asymmetric Multiprocessor Environment Within an SMP System. Roberto Mijat, ARM Santa Clara, October 2, 2007

Device Drivers. CS449 Fall 2017

Workspace for '5-linux' Page 1 (row 1, column 1)

Hyo-bong Son Computer Systems Laboratory Sungkyunkwan University

Loadable Kernel Module

File Systems. Jinkyu Jeong Computer Systems Laboratory Sungkyunkwan University

ECE 7650 Scalable and Secure Internet Services and Architecture ---- A Systems Perspective. Part I: Operating system overview: Disk and File System

FILE SYSTEMS. Jo, Heeseung

Operating System Concepts Ch. 11: File System Implementation

File Systems Overview. Jin-Soo Kim ( Computer Systems Laboratory Sungkyunkwan University

Operating System Labs. Yuanbin Wu

we are here I/O & Storage Layers Recall: C Low level I/O Recall: C Low Level Operations CS162 Operating Systems and Systems Programming Lecture 18

TIP675-SW-82. Linux Device Driver. 48 TTL I/O Lines with Interrupts Version 1.2.x. User Manual. Issue November 2013

Contents. NOTICE & Programming Assignment #1. QnA about last exercise. File IO exercise

FAME Operatinf Systems - Modules

NPTEL Course Jan K. Gopinath Indian Institute of Science

File Systems: Consistency Issues

we are here Page 1 Recall: How do we Hide I/O Latency? I/O & Storage Layers Recall: C Low level I/O

CSE 333 SECTION 3. POSIX I/O Functions

File I/O. Dong-kun Shin Embedded Software Laboratory Sungkyunkwan University Embedded Software Lab.

Scrivere device driver su Linux. Better Embedded 2012 Andrea Righi

Linux Loadable Kernel Modules (LKM)

The Embedded I/O Company TIP700-SW-82 Linux Device Driver User Manual TEWS TECHNOLOGIES GmbH TEWS TECHNOLOGIES LLC

CSE 410: Systems Programming

Simple char driver. for Linux. my_first.c: headers. my_first.c: file structure. Calcolatori Elettronici e Sistemi Operativi.

File I/O. Jin-Soo Kim Computer Systems Laboratory Sungkyunkwan University

Files and Directories Filesystems from a user s perspective

CS 201. Files and I/O. Gerson Robboy Portland State University

All the scoring jobs will be done by script

Section 3: File I/O, JSON, Generics. Meghan Cowan

CS 471 Operating Systems. Yue Cheng. George Mason University Fall 2017

Contents. Programming Assignment 0 review & NOTICE. File IO & File IO exercise. What will be next project?

- Knowledge of basic computer architecture and organization, ECE 445

Driving Me Nuts Device Classes

Introduction to Operating Systems. Device Drivers. John Franco. Dept. of Electrical Engineering and Computing Systems University of Cincinnati

VIRTUAL FILE SYSTEM AND FILE SYSTEM CONCEPTS Operating Systems Design Euiseong Seo

Embedded Linux. Session 4: Introduction to the GPIO Kernel API. Martin Aebersold BFH-TI Dipl. El.-Ing. FH.

1 #include <linux/module.h> 2 #include <linux/sched.h> 3 #include <linux/interrupt.h> 4 #include <linux/init.h> 5 #include <linux/kernel.

Interprocess Communication. Originally multiple approaches Today more standard some differences between distributions still exist

Fall 2017 :: CSE 306. File Systems Basics. Nima Honarmand

Processes often need to communicate. CSCB09: Software Tools and Systems Programming. Solution: Pipes. Recall: I/O mechanisms in C

CSI3131 Operating Systems Tutorial 9 Winter 2015 File Systems

ECE 650 Systems Programming & Engineering. Spring 2018

SSE3052: Embedded Systems Practice

CSE 333 Midterm Exam 2/12/16. Name UW ID#

ECE 550D Fundamentals of Computer Systems and Engineering. Fall 2017

Input & Output 1: File systems

CS2028 -UNIX INTERNALS

Files. Eric McCreath

CS 453: Operating Systems Programming Project 5 (100 points) Linux Device Driver

Linux Device Driver in Action (LDDiA)

CS 378 (Spring 2003)

All the scoring jobs will be done by script

File Descriptors and Piping

TPMC860-SW-82. Linux Device Driver. 4 Channel Isolated Serial Interface RS232 Version 1.4.x. User Manual. Issue 1.4.

Introduction to the Linux Kernel. Hao-Ran Liu

/dev/hello_world: A Simple Introduction to Device Drivers under Linux

Lecture 1. Virtualization, Linux kernel (modules and networking) and Netfilter Winter 15/16. Roei Ben-Harush 2015

Lecture on Storage Systems

PRINCIPLES OF OPERATING SYSTEMS

The Linux driver for the Rome PCI-AER board

Transcription:

Introduction to Device Drivers Part-1 Introduction to Device Drivers-1

Objectives GNU/Linux Learn how to access the hardware similar to the sysfs method but faster Understand the basic techniques of how to write simple Linux device drivers Using device files, major and minor numbers Communication between user space programs and drivers via file operations Learn how to process interrupt Learn how to synchronize device drivers with user space applications Introduction to Device Drivers-2

Device Drivers Part-1 Topics: Devices, Major and Minor Numbers revisited File Operations, Driver Registration Block and Character Devices Example Driver Null-Driver Exercise BBB-BFH-CAPE single LED driver Introduction to Device Drivers-3

Linux kernel overview GNU/Linux In Linux a driver is broadly classified into 3 categories: Network Device Drivers Block-oriented Device Drivers Byte-oriented or Character Device Drivers Introduction to Device Drivers-4

GNU/Linux Device Driver Design Principles (1) Writing a device driver requires an in-depth understanding of how the hardware and the software works for a given platform function. Driver development may follow an outside-in design Describe the interface between the driver and the hardware IO-ports Memory mapped IO Describe the interface between the driver and the user process (via device special files) File system calls like open(),close(),read(),write(), etc. Access modes: blocked vs. Non-blocked Introduction to Device Drivers-5

Device Driver Design Principles (2) Design the driver functions using those interfaces Built-in drivers versus driver modules Building process for driver modules Driver registration / un-registration with the kernel Testing drivers Introduction to Device Drivers-6

A Warning! It is very easy to crash the system when you are writing and testing LKMs. It is always possible that such a system crash could corrupt your file system - it is unlikely, but it is possible. Introduction to Device Drivers-7

Device Files Device Number Major Number Minor Number Introduction to Device Drivers-8

Device Files, Major/Minor Numbers Device drivers have an associated major and minor number Example: /dev directory on the BBB Board (some lines deleted) major number minor number crw------- 1 root root 10, 57 Jan 1 00:01 alarm drwxr-xr-x 2 root root 580 Jan 1 00:01 block brw-rw---- 1 root disk 179, 0 Jan 1 2000 mmcblk0 brw-rw---- 1 root disk 179, 1 Jan 1 2000 mmcblk0p1 crw------- 1 root root 5, 1 Jan 1 00:01 console crw------- 1 root root 10, 56 Jan 1 00:01 cpu_dma_latency crw-rw---t 1 root audio 14, 3 Jan 1 00:01 dsp crw-rw---t 1 root video 29, 0 Jan 1 00:01 fb0 lrwxrwxrwx 1 root root 13 Jan 1 00:01 fd -> /proc/self/fd c = charater device b = block device Major number 10 Minor Number 57 Introduction to Device Drivers-9

Major & minor number (1) Current assignment see: Documentation/devices.txt Connection between the application and the device file is based on the name of the device file. The connection between the device file and the device driver is based on the number of the device file, not the name. Can be dynamically assigned. Use the mknod <arg> command to create a device file. $ mknod /dev/mytty c major minor /proc/devices shows the currently assigned devices. Introduction to Device Drivers-10

GNU/Linux Major & minor number (2) $ cat /proc/devices on the BBB-BFH-Cape Character devices: 1 mem 4 /dev/vc/0 5 /dev/tty 5 /dev/console 7 vcs 10 misc 13 input 14 sound 29 fb 81 video4linux 89 i2c 90 mtd : Block devices: 1 ramdisk 259 blkext 7 loop 8 sd 31 mtdblock 65 sd 66 sd : 135 sd 179 mmc 254 device-mapper Introduction to Device Drivers-11

System Call File Operations Driver Registration Introduction to Device Drivers-12

System Architecture for BBB user program 1 user program N System Call Interface (POSIX) Linux Kernel File System I/O Sub-System Device Control Char Device Drivers Hardware Abstraction Interface Memory Console GPIO Switches LEDs Introduction to Device Drivers-13

The Virtual Filesystem Virtual File System (VFS) or Virtual Filesystem Switch is an abstraction layer on top of a more concrete file system. The purpose of a VFS is to allow for client applications to access different types of concrete file systems in a uniform way Architectural View of VFS Introduction to Device Drivers-14

The central idea for VFS operation VFS substitutes the generic system call like read and write with the native function for that particular file-system Each specific file-system implementation must translate its physical organization into VFS s common file model. Introduction to Device Drivers-15

Driver API Unix Philosophy: Everything is a file devices are used like files On the user side: Operations (system calls) are: open(), close(), read(), write(), ioctl(), etc. Simple example (error handling omitted): char *str = "Hello World\n"; fd = open("/dev/tty1", O_RDWR) count = write(fd, str, strlen(str)); close(fd); Information see manual pages section 2 (system calls) Introduction to Device Drivers-16

File Operations GNU/Linux struct file_operations { file operations (simplified) 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 *); 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 (*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 *); }; Character devices are accessed as files. Drivers should provide implementations of some of these functions. Thus one opens a device, reads/writes from/to it, and closes it, using the same file I/O semantics used for regular files. Introduction to Device Drivers-17

The Inode Object The inode object represents all the information needed by the kernel to manipulate a file The inode object is represented by struct inode and is defined in /* <linux/fs.h> in-core inode, some fields omitted */ struct inode {... unsigned long i_ino; /* i-number */ atomic_t i_count; /* #of processes that refer */ unsigned int i_nlink; /* hard link count */ uid_t i_uid; /* owner */ gid_t i_gid; /* group */ dev_t i_rdev; /* used if file represents device */ loff_t i_size; /* file size */ umode_t i_mode; /* type and permissions */... } Introduction to Device Drivers-18

The File Object The file object is used to represent a file opened by a process The file object is represented by struct file and is defined in <linux/fs.h> /* Process specific information of an open file, some fields omitted */ struct file { struct path f_path; /* File path, has struct *dentry */ const struct file_operations f_op; /* File ops, open() read(), write() */ spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */ atomic_long_t f_count; /* use count */ unsigned int f_flags; /* Flags specified by open() */ fmode_t f_mode; /* File access mode in open call */ loff_t f_pos; /* File position */ int f_error; /* Error code */ } Introduction to Device Drivers-19

File Operations (1) Operations in user space (tty1) Corresponding actions in the kernel at open: GNU/Linux 1. find and cache the struct inode object that corresponds with the specified path. 2. create a struct file object associated with fd. 3. call the (*open) function in the driver Actions in the (*open) function in the driver char *str = Hello World\n ; fd = open( /dev/tty1, O_RDWR) count = write(fd, str, strlen(str)); close(fd); Check if access is permitted Introduction to Device Drivers-20

File Operations (2) Operations in user space (tty1) char *str = Hello World\n ; fd = open( /dev/tty1, O_RDWR) count = write(fd, str, strlen(str)); close(fd); GNU/Linux Corresponding actions in the kernel at write: call the (*write) function of the driver using the file object, buf points to str (in user space) count contains strlen(str), ofs is not used. Actions in the (*write)function in the driver Copy the string from the user space in a kernel space buffer Send the characters of the string to the terminal device Introduction to Device Drivers-21

File Operations (3) Operations in user space (tty1) GNU/Linux Corresponding actions in the kernel at close: call the (*release) function of the driver using the file object, and the inode object. Actions in the (*release) function in the driver char *str = Hello World\n ; fd = open( /dev/tty1, O_RDWR) count = write(fd, str, strlen(str)); cose(fd); Cleanup: release resources. Introduction to Device Drivers-22

File Operations (4) GNU/Linux Initialization of file operations for the tty1 device driver /* This is a Designated Initializer, syntax added for C99 */ static struct file_operations tty1_fops = {.owner = THIS_MODULE,.open = tty1_open, Pointers to the functions that.release = tty1_close, serve as operation handlers.read = tty1_read, for various user space file.write = tty1_write operations like open(), read() etc... }; Initialize the character device structure using cdev_init() /* The character device */ static struct cdev char_dev; /* Initializes cdev, remembering fops, add it to the system */ cdev_init(&char_dev, &tty1_fops); Introduction to Device Drivers-23

Block Data Transfer from/to User Space unsigned long copy_to_user(void user *to, const void *from, unsigned long count); unsigned long copy_from_user(void *to, const void user *from, unsigned long count); return values: number of byte NOT copied The functions behave like C style memcpy() Introduction to Device Drivers-24

Single Value Transfer from/to User Space Macro: put_user(datum, ptr); Transfer up to 8 bytes depending on type of pointer ptr argument to the user space. Macro: get_user(local, ptr); Retrieve up to 8 bytes depending on type of pointer ptr argument from the user space and store it in local kernel variable. return value (both): 0: OK -EFAULT: bad address, address out of range Introduction to Device Drivers-25

Driver Registration/Unregistration (1) Device Number, Major Number and Minor Number Traditional Unix: 16 bit device number containing major and minor number Linux Kernel 2.6 Device Numbers: 32 bit dev_t A driver can request a block of device numbers Useful Macros Form a dev_t given the minor and the major number MKDEV(int major, int minor) Obtain major and minor number given the device number major = MAJOR(dev_t dev) minor = MINOR(dev_t dev) Introduction to Device Drivers-26

Driver Registration/Unregistration (2) Allocating/Freeing a Range of Consecutive Device Numbers. These functions are normally called in the init_module() cleanup_module() functions of a driver module. int register_chrdev_region(dev_t first, unsigned int count, char *name); void unregister_chrdev_region(dev_t first, unsigned count); first: beginning device number, often the result of the MKDEV() macro count: the number of consecutive device numbers required name: the name of the device or driver, appears in /proc/devices return value: 0 means OK; <0 means error Introduction to Device Drivers-27

Driver Registration/Unregistration (3) Allocates a range of char device numbers dynamically. This is useful if you do not know the device number in advance. int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name); *dev: the first device number in the dynamically allocated range firstminor: the first requested minor number, often 0 count: the total number of contiguous dev numbers name: the name associated to this device return value:=0 means OK; <0 means error Introduction to Device Drivers-28

Driver Registration/Unregistration (4) Create a struct class pointer to be used in device_create() Note, the pointer created here is to be destroyed when finished by making a call to class_destroy(). /* Create a struct class pointer to be used in device_create() */ if (IS_ERR(dev_class = class_create(this_module, MODULE_NAME))) { unregister_chrdev_region(first_dev, HOW_MANY_MINORS); return PTR_ERR(dev_class); } Introduction to Device Drivers-29

Driver Registration/Unregistration (5) With a class established, device_create() performs the actual instantiation of our device. It is at this stage that a "device" gets created in /dev, using the parameter provided for the name. The struct class passed to this function must have previously been created with a call to class_create(). struct device *device_create( struct class *class, /* Pointer to struct class that this device should be registered to */ struct device *parent,/* Pointer to parent struct device of this new device, if any */ dev_t devt, /* The dev_t for the char device to be added */ void *drvdata, /* The data to be added to the device for callbacks */ const char *fmt, /* String for the device's name */...); /* Variable arguments */ device_create(dev_class, NULL, MKDEV(MAJOR(first_dev), MINOR(first_dev)), NULL, DEV_NODE_NAME))) Introduction to Device Drivers-30

Driver Registration/Unregistration (6) Initializes cdev, remembering fops, making it ready to add to the system with cdev_add() void cdev_init(struct cdev *cdev, const struct file_operations *fops); ARGUMENTS cdev: the structure to initialize fops: the file_operations for this device Introduction to Device Drivers-31

Driver Registration/Unregistration (7) cdev_add() adds the device represented by p to the system, making it live immediately. A negative error code is returned on failure. int cdev_add(struct cdev *p, /* The cdev structure for the device */ dev_t dev, /* First dev nr for which this device is responsible */ unsigned count /* Number of consecutive minor numbers */ ); cdev_del() removes p from the system, possibly freeing the structure itself. void cdev_del ( struct cdev *p); /* The cdev structure to be removed */ Introduction to Device Drivers-32

GNU/Linux Driver Registration/Unregistration (8) /* Allocates a range of char device numbers */ alloc_chrdev_region(); /* Create a struct class pointer to be used in device_create() */ class_create(); /* Create device in sysfs and register it to the specified class */ device_create(); /* Initializes cdev, remembering fops, making it ready to add to the system */ cdev_init(); /* Adds the device represented by char_dev to the system */ cdev_add(); /* Remove char_dev from the system */ cdev_del(&char_dev); /* Unregisters and cleans up devices created with a call to device_create */ device_destroy(dev_class, MKDEV(MAJOR(first_dev), MINOR(first_dev))); /* Destroy an existing class */ class_destroy(dev_class); /* Unregister a range of device numbers */ unregister_chrdev_region(first_dev, HOW_MANY_MINORS); Introduction to Device Drivers-33

Driver Registration GNU/Linux Introduction to Device Drivers-34

Driver Registration / Unregistration: blkdev Registration / unregistration for a block device extern int register_blkdev(unsigned int major_nr, const char *driver_name); extern int unregister_blkdev(unsigned int maj_nr, const char *drive_name); Example: My block device mj_nr = register_blkdev(241, MY_BLK_DRV_NAM); Introduction to Device Drivers-35

Aspects of Block Devices Random access Block transfer Data transfer unit is a multiple of the physical block size of the device (normally 512 bytes for disks) Block size can be set by software On disks: physical block is a sector Caching by the kernel: not every access to a block device leads to a data transfer between device and kernel Introduction to Device Drivers-36

BBB-BFH-Cape with Beagle Bone Black Driver Example Introduction to Device Drivers-37

Driver to Set a Single LED (L1) on and off Introduction to Device Drivers-38

Char Device Example (1) GNU/Linux LED-1 on the BFH Cape Specification User space support Driver access via /dev/led0 device file Supported I/O system calls open: Connect an application with the driver, return a file descriptor (fd) close: Disconnect the application with the driver given the file descriptor (fd) read: Show the status (on/off) of the LED write: Write string on or off to the LED device to set the LED appropriately ioctl: not supported Introduction to Device Drivers-39

Char Device Example (2) LED Driver Specification Module Initialization Module Name: led_driver_single.ko Driver Name: led_driver_single Command to load the driver (as root). # modprobe led_driver_single Introduction to Device Drivers-40

Char Device Example (3) Driver Design: Constants #define DEV_NODE_NAME "led%d" GNU/Linux #define MOD_LICENSE "GPL" #define MOD_AUTHOR "AOM1 <martin.aebersold@bfh.ch>" #define MOD_DESCRIPTION "Your first Linux driver" #define MODULE_NAME "led_driver_single" #define LED_DRIVER_VER "1.0" #define FIRTS_MINOR_NR 0 #define HOW_MANY_MINORS 1 #define MAX_MSG_SIZE 32 #define LED_1 61 #define ON 0 #define OFF 1 Introduction to Device Drivers-41

Char Device Example (4) GNU/Linux Driver Design: Variables uint16_t leds[how_many_minors] = { LED_1 }; static dev_t first_dev; /* First device number */ static struct cdev char_dev; /* The character device */ static struct class *dev_class; /* The device class */ Introduction to Device Drivers-42

Char Device Example (5) Driver Design: Driver functions (only visible in the driver) /* File operation functions: go to led_ops */ static int led_open(struct inode *inode, struct file *file_ptr) static int led_close(struct inode *inode, struct file *file_ptr) static ssize_t led_read(struct file *file_ptr, char user *user_buffer, size_t count, loff_t *f_pos) static ssize_t led_write(struct file *file_ptr, const char user *user_buffer, size_t size, loff_t *pos) Introduction to Device Drivers-43

Char Device Example (6) Driver Implementation File operations implemented by this driver This is a Designated Initializer, syntax added for C99 static struct file_operations led_fops = {.owner = THIS_MODULE,.open = led_open,.release = led_close,.read = led_read,.write = led_write }; Introduction to Device Drivers-44

GNU/Linux Char Device Example (7) Driver Implementation (no error handling) Module initialization init led_init() static int init led_init(void) { struct device *dev_ret; /* Try to request gpio for LED1 and it ist as output */ gpio_request(led_1, "LED1") gpio_direction_output(led_1, OFF) /* Allocates a range of char device numbers */ alloc_chrdev_region(&first_dev, FIRTS_MINOR_NR, HOW_MANY_MINORS, MODULE_NAME) /* Create a struct class pointer to be used in device_create() */ dev_class = class_create(this_module, MODULE_NAME) /* Create device in sysfs and register it to the specified class */ dev_ret = device_create(dev_class, NULL, MKDEV(MAJOR(first_dev), MINOR(first_dev)), NULL, DEV_NODE_NAME))) /* Initializes cdev, remembering fops, making it ready to add to the system */ cdev_init(&char_dev, &led_fops); /* Adds the device represented by char_dev to the system */ cdev_add(&char_dev, first_dev, HOW_MANY_MINORS) Return 0; } Introduction to Device Drivers-45

Char Device Example (8) Driver Implementation (no error handling) Module exit led_exit() and cleanup static void exit led_exit(void) { /* Remove char_dev from the system */ cdev_del(&char_dev); /* Unregisters and cleans up devices created with a call to device_create */ device_destroy(dev_class, MKDEV(MAJOR(first_dev), MINOR(first_dev))); /* Destroy an existing class */ class_destroy(dev_class); /* Unregister a range of device numbers */ unregister_chrdev_region(first_dev, HOW_MANY_MINORS); /* Release previously requested gpios */ gpio_free(led1); } module_init(led_init); Introduction to Device Drivers-46

Char Device Example (9) Driver Implementation (no error handling) Open function Get major and minor number. static int led_open(struct inode *inode, struct file *file_ptr) { int major, minor; major = imajor(inode); minor = iminor(inode); printk(kern_info "Open device node at major %d minor %d\n", major, minor); return 0; } Introduction to Device Drivers-47

Char Device Example (10) Driver Implementation (no error handling) Close (release) function - Get major and minor number. static int led_close(struct inode *inode, struct file *file_ptr) { int major, minor; /* Get major and minor number */ major = imajor(inode); minor = iminor(inode); printk(kern_info "Closing device node at major %d minor %d\n", major, minor); return 0; } Introduction to Device Drivers-48

Char Device Example (11) Driver Implementation (no error handling) Read function led_read() static ssize_t led_read(struct file *file_ptr, char user *user_buffer, size_t count, loff_t *f_pos) { size_t len = count, status_length; ssize_t retval = 0; unsigned long ret = 0; int major, minor; char led_value, *onoff; /* Get major and minor number */ major = MAJOR(file_ptr->f_path.dentry->d_inode->i_rdev); minor = MINOR(file_ptr->f_path.dentry->d_inode->i_rdev); /* Get led status */ led_value = gpio_get_value(led_1); if (!led_value) onoff = "on\n"; else onoff = "off\n"; status_length = strlen(onoff); /* Copy message to user */ ret = copy_to_user(user_buffer, onoff, len); return retval; } Introduction to Device Drivers-49

GNU/Linux Char Device Example (12) Driver Implementation (no error handling) Write function led_write() static ssize_t led_write(struct file *file_ptr, const char user *user_buffer, size_t size, loff_t *pos) { int major, minor; char led_value, msgbuffer[max_msg_size] /* Get major and minor number */ major = MAJOR(file_ptr->f_path.dentry->d_inode->i_rdev); minor = MINOR(file_ptr->f_path.dentry->d_inode->i_rdev); /* Get command for the leds from the user */ copy_from_user(msgbuffer, user_buffer, size); if (strncmp(msgbuffer, "on", strlen("on")) == 0) led_value = ON; else if (strncmp(msgbuffer, "off", strlen("off")) == 0) led_value = OFF; else return size; /* Turn led on or off */ gpio_set_value(led_1, led_value); return size ; } Introduction to Device Drivers-50

GNU/Linux Char Device Example (13) Driver Implementation (no error handling) led_ioctl() function (currently not used) static int led_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rc = -ENOSYS; switch(cmd) { /* Implement future control function commands here */ default: break; } return(rc); } Introduction to Device Drivers-51

GNU/Linux Char Device Example (14) Driver Implementation: Choosing ioctl command codes Avoid equal command codes for different devices: calling a valid command on the wrong device may cause undesired effects Use four bit fields in a 32-bit command code type: a magic number number: an 8 bit ordinal number (the command number) direction: used if the command involves a data transfer size: the size of user data The kernel header <linux/ioctl.h> defines useful macros: _IO(type,number): a command that has no argument _IOR(type,number,datatype): a command to read data from the device _IOW(type,number,datatype): a command to write data to the device _IOWR(type,number,datatype): a command for bidirectional transfer Introduction to Device Drivers-52

Char Device Example (15) Driver Implementation Choosing ioctl command codes, cont. Example: get/set direction register in the LED driver #include <linux/ioctl.h> #define LED_IOC_MAGIC ('L') /* dev's magic # */ /* Command that reads/writes an int vaule */ #define LED_READ_INT _IOR(LED_IOC_MAGIC, 1, int) #define LED_WRITE_INT _IOW(LED_IOC_MAGIC, 2, int) Introduction to Device Drivers-53

Char Device Example (16) Communication between User Space (userland) and driver The driver uses text strings to communicate with the user space application. This technique allows you to use well known utilities like cat and echo to communicate with the driver. Write a text string on or off to device /dev/led0 to control LED-1 For example: echo on > /dev/led0 sets LED-1 on echo off > /dev/led0 sets LED-1 off cat /dev/led0 show status of LED-1 (on or off) Introduction to Device Drivers-54

User Space App GNU/Linux int main(int argc, char **argv) /* No error handling */ { int fd, rc; char inbuf[buf_len], outbuf[8]; static const char *ON = "on", *OFF = "off"; } /* Open device special file */ fd = open(led_device, O_RDWR); while (1) { /* Turn LED-1 on */ strncpy(outbuf, ON, BUF_LEN-1); rc = write(fd, outbuf, strlen(outbuf)); sleep(1); /* Turn LED-1 off */ strncpy(outbuf, OFF, BUF_LEN-1); rc = write(fd, outbuf, strlen(outbuf)); sleep(1); } /* Close file descriptor and exit program */ close(fd); return 0; Introduction to Device Drivers-55

References Jonathan Corbet, Alessadro Rubini, Greg Kroah-Hartman: Linux Device Drivers, O'Reilly, 2005, ISBN 0-596-00590-3 Juergen Quade, Eva-Katharina Kunst: Linux Treiber entwickeln, 2. Auflage, dpunkt verlag 2006, ISBN 3-89864-392-1 Daniel Bovet, Marco Cesati: Understanding the Linux Kernel, 3rd Ed. O'Reilly, 2006, ISBN 0-596-00565-2 Wolfgang Mauerer: Linux Kernelarchitektur, Hanser 2004 Kernel Documentation: gpio.txt Introduction to Device Drivers-56