Introduction Reading Writing scull. Linux Device Drivers - char driver

Similar documents
Character Device Drivers

Designing and developing device drivers. Coding drivers

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

REVISION HISTORY NUMBER DATE DESCRIPTION NAME

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

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

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

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

MP3: VIRTUAL MEMORY PAGE FAULT MEASUREMENT

CS 378 (Spring 2003)

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

Unix (Linux) Device Drivers

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

Loadable Kernel Module

Finish up OS topics Group plans

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

Introduction to Device Drivers Part-1

Character Device Drivers One Module - Multiple Devices

Interrupt handling. Interrupt handling. Deferred work. Interrupt handling. Remove an interrupt handler. 1. Link a struct work to a function

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

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

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

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

Concurrency and Race Conditions (Linux Device Drivers, 3rd Edition (

7.4 Simple example of Linux drivers

NPTEL Course Jan K. Gopinath Indian Institute of Science

Linux Device Driver in Action (LDDiA)

Linux drivers - Exercise

CPSC 8220 FINAL EXAM, SPRING 2016

CSE 333 SECTION 3. POSIX I/O Functions

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

Linux Kernel Modules & Device Drivers April 9, 2012

Linux Device Driver. Analog/Digital Signal Interfacing

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

Kernel Modules. Kartik Gopalan

Linux Device Drivers Interrupt Requests

Device Drivers. CS449 Fall 2017

Outline. OS Interface to Devices. System Input/Output. CSCI 4061 Introduction to Operating Systems. System I/O and Files. Instructor: Abhishek Chandra

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

Android 多核心嵌入式多媒體系統設計與實作

CSE 333 SECTION 3. POSIX I/O Functions

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

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

Operating systems for embedded systems. Embedded Operating Systems

Rights to copy. Dongkun Shin, SKKU

Linux Loadable Kernel Modules (LKM)

Operating System Labs. Yuanbin Wu

Operating systems for embedded systems

NPTEL Course Jan K. Gopinath Indian Institute of Science

BLOCK DEVICES. Philipp Dollst

Files. Eric McCreath

Final Step #7. Memory mapping For Sunday 15/05 23h59

CMPS 105 Systems Programming. Prof. Darrell Long E2.371

CptS 360 (System Programming) Unit 6: Files and Directories

Concurrency Aspects of Project 2

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

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

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

CS , Spring Sample Exam 3

Files and Directories Filesystems from a user s perspective

FAME Operatinf Systems - Modules

Outline. File Systems. File System Structure. CSCI 4061 Introduction to Operating Systems

Lecture files in /home/hwang/cs375/lecture05 on csserver.

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

CS 378 (Spring 2003)

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

File Descriptors and Piping

UNIX System Calls. Sys Calls versus Library Func

CS 378 (Spring 2003)

Hyo-bong Son Computer Systems Laboratory Sungkyunkwan University

Input & Output 1: File systems

Programming the GPMC driver

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

File Systems. Jinkyu Jeong Computer Systems Laboratory Sungkyunkwan University

POSIX Shared Memory. Linux/UNIX IPC Programming. Outline. Michael Kerrisk, man7.org c 2017 November 2017

Using persistent memory to

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

INSTRUMENTATION. using FREE/OPEN CODE

Driving Me Nuts Device Classes

Last Week: ! Efficiency read/write. ! The File. ! File pointer. ! File control/access. This Week: ! How to program with directories

Operating System Labs. Yuanbin Wu

Project 5 File System Protection

Dissecting a 17-year-old kernel bug

OS COMPONENTS OVERVIEW OF UNIX FILE I/O. CS124 Operating Systems Fall , Lecture 2

Basic OS Progamming Abstrac7ons

Files and the Filesystems. Linux Files

Basic OS Progamming Abstrac2ons

Inter-Process Communication

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

ECE 650 Systems Programming & Engineering. Spring 2018

Kprobes Presentation Overview

I/O OPERATIONS. UNIX Programming 2014 Fall by Euiseong Seo

INSTRUMENTATION. using FREE/OPEN CODE

RTEMS Filesystem Design Guide

I/O OPERATIONS. UNIX Programming 2014 Fall by Euiseong Seo

FUSD: A Linux Framework for User-Space Devices. Jeremy Elson.

Chp1 Introduction. Introduction. Objective. Logging In. Shell. Briefly describe services provided by various versions of the UNIX operating system.

[6 marks] All parts of this question assume the following C statement. Parts (b) through (e) assume a variable called ptrs.

libxcpc(3) Exception and resource handling in C libxcpc(3)

Transcription:

Overview 1 2 3 4 Major, minor File Operations The file Structure The inode structure Registraction

simplest driver, suitable for most simple devices, follow the book.

Jernej Figure: Vičič.

(Simple Character Utility for Loading Localities), character driver, uses part of the memory to simulate the device, device does not do anything useful, suitable only for demonstration, shows the interfaces between the kernel and the character driver, suitable as a template for your drivers, shows the actual installation and startup.

define capabilities, multiple types of devices.

Devices part of memory, global, persistent (keeps the values); user can use cp, cat,... 0, 1, 2, 3.

Devices, continue 4 FIFO devices, one process reads what the other wrote, pipe0, pipe1, pipe2, pipe3.

Devices, continue special version of memory buffer (similar to 0); single, only one process at once; priv, private for every console (tty); uid, only one user can access - device busy; wuid, only one use can access - blocking open.

Major, minor user can access these devices through file system; /dev; observe the c tag; in ls -l:

Device overview crw-rw-rw- 1 root root 1, 3 Apr 11 2002 null crw------- 1 root root 10, 1 Apr 11 2002 psaux crw------- 1 root root 4, 1 Oct 28 03:04 tty1 crw-rw-rw- 1 root tty 4, 64 Apr 11 2002 ttys0 crw-rw---- 1 root uucp 4, 65 Apr 11 2002 ttys1 crw--w---- 1 vcsa tty 7, 1 Apr 11 2002 vcs1 crw--w---- 1 vcsa tty 7, 129 Apr 11 2002 vcsa1 crw-rw-rw- 1 root root 1, 5 Apr 11 2002 zero

Explanation major numbers: 1, 4, 7, and 10; minor numbers: 1, 3, 5, 64, 65, 129; example: /dev/null and /dev/zero are controlled by the same driver (1);

Inner representation of device numbers type dev t, defined in <linux/types.h>; represents major and minor numbers; 32 bits: 12 bits fo major, 20 bits for minor; available macros for translation into dev t: MAJOR(dev_t dev); MINOR(dev_t dev); MKDEV(int major, int minor);

Allocation and release of device numbers int register_chrdev_region(dev_t first, unsigned int count, char *name); defined in <linux/fs.h>; first, start of region; count, number of requested numbers; name, name of device, shown in /proc/devices

Allocation and release of device numbers int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name); dev, allocate major number; firstminor, the smallest minor number; count, the number of numbers we request; name, the device name, will appear in /proc/devices

Allocation and release of device numbers void unregister_chrdev_region(dev_t first, unsigned int count); release number region;

Dynamic number allocation void unregister_chrdev_region(dev_t first, unsigned int count); better use alloc chrdev region; script:

Dynamic number allocation #!/bin/sh module="" device="" mode="664" # invoke insmod with all arguments we got # and use a pathname, as newer modutils don t look in. by default /sbin/insmod./$module.ko $* exit 1 # remove stale nodes rm -f /dev/${device}[0-3] major=$(awk "\\$2= =\"$module\" {print \\$1}" /proc/devices) 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 # give appropriate group/permissions, and change the group. # Not all distributions have staff, some have "wheel" instead. group="staff" grep -q ^staff: /etc/group group="wheel" chgrp $group /dev/${device}[0-3] chmod $mode /dev/${device}[0-3]

File Operations The file Structure The inode Structure

File Operations file operations, defined in <linux/fs.h>, usualy named fops, each field points to a function or to NULL,

File Operations - list struct module *owner loff t (*llseek) (struct file *, loff t, int); ssize t (*read) (struct file *, char user *, size t, loff t *); ssize t (*aio read)(struct kiocb *, char ssize t (*write) (struct file *, const char *); user *, size t, loff t); user *, size t, loff t ssize t (*aio write)(struct kiocb *, const char user *, size t, loff t *); int (*readdir) (struct file *, void *, filldir t);

File Operations - list continue unsigned int (*poll) (struct file *, struct poll table struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm area struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int);...

File Operations - struct file_operations _fops = {.owner = THIS_MODULE,.llseek = _llseek,.read = _read,.write = _write,.ioctl = _ioctl,.open = _open,.release = _release, };

The file Structure struct file, defined in <linux/fs.h>, no connection with FILE in userspace programs, represents an open file,

File Operations - list mode t f mode; loff t f pos; unsigned int f flags; struct file operations *f op; void *private data; struct dentry *f dentry;

The inode structure kernel uses to represent files, two important fields: dev t i rdev major number for inodes that represent devices, struct cdev *i cdev, character devices

The inode structure - macros unsigned int iminor(struct inode *inode); unsigned int imajor(struct inode *inode);

char devices are in presented to the kernel with struct cdev; defined in v <linux/cdev.h>; two ways of initialization: independent structure, part of private structures

Independent structure struct cdev *my_cdev = cdev_alloc( ); my_cdev->ops = &my_fops; instruct the kernel: int cdev_add(struct cdev *dev, dev_t num, unsigned int count);

Part of private structures used by ; use next initialization; void cdev_init(struct cdev *cdev, struct file_operations *fops); povemo jedru; int cdev_add(struct cdev *dev, dev_t num, unsigned int count);

Delete the device void cdev_del(struct cdev *dev);

Structure struct _dev { struct _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 uid and priv */ struct semaphore sem; /* mutual exclusion semaphore */ struct cdev cdev; /* Char device structure */ };

Initialization and structure add static void _setup_cdev(struct _dev *dev, int index) { int err, devno = MKDEV(_major, _minor + index); cdev_init(&dev->cdev, &_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &_fops; err = cdev_add (&dev->cdev, devno, 1); /* Fail gracefully if need be */ if (err) printk(kern_notice "Error %d adding %d", err, index); }

Method open ussually take care of: check for error in the device (device-not-ready,...); initialize the device if first open; change the f op pointer (if needed) alocate and fille the for filp->private data

Our example use macro container_of(pointer, container_type, container_field); struct _dev *dev; /* device information */ dev = container_of(inode->i_cdev, struct _dev, cdev); filp->private_data = dev; /* for other methods */

Our example, continue int _open(struct inode *inode, struct file *filp) { struct _dev *dev; /* device information */ dev = container_of(inode->i_cdev, struct _dev, cdev); filp->private_data = dev; /* for other methods */ /* now trim to 0 the length of the device if open was write-only */ if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) { _trim(dev); /* ignore errors */ } return 0; /* success */ }

The release method dealocation of everything open methoda allocated in filp > private data; closes the device at last close.

Our example int _release(struct inode *inode, struct file *filp) { return 0; }

How do we allocate memory? Example.

allocation <linux/slab.h> void *kmalloc(size_t size, int flags); void kfree(void *ptr); flags: simplest/most used GFP KERNEL

Parts of memory (quantum) Figure: quantum.

quantum struct _qset { void **data; struct _qset *next; };

quantum int _trim(struct _dev *dev) { struct _qset *next, *dptr; int qset = dev->qset; /* "dev" is not-null */ int i; for (dptr = dev->data; dptr; dptr = next) { /* all the list items */ if (dptr->data) { for (i = 0; i < qset; i++) kfree(dptr->data[i]); kfree(dptr->data); dptr->data = NULL; } next = dptr->next; kfree(dptr); } dev->size = 0; dev->quantum = _quantum;

ssize_t read(struct file *filp, char user *buff, size_t count, loff_t ssize_t write(struct file *filp, const char user *buff, size_t count, filp file pointer; count data size; buff pointer to data; offp pointer to long offset type object that defines file position; buff is in user space

Copy into and from 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);

Read implementation Figure: Implementacija branja.

ssize_t _read(struct file *filp, char user *buf, size_t count, loff_t *f_pos) { struct _dev *dev = filp->private_data; struct _qset *dptr; /* the first listitem */ int quantum = dev->quantum, qset = dev->qset; int itemsize = quantum * qset; /* how many bytes in the listitem */ int item, s_pos, q_pos, rest; ssize_t retval = 0; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; if (*f_pos >= dev->size) goto out; if (*f_pos + count > dev->size) count = dev->size - *f_pos;

/* find listitem, qset index, and offset in the quantum */ item = (long)*f_pos / itemsize; rest = (long)*f_pos % itemsize; s_pos = rest / quantum; q_pos = rest % quantum; /* follow the list up to the right position (defined elsewhere) */ dptr = _follow(dev, item); if (dptr = = NULL!dptr->data! dptr->data[s_pos]) goto out; /* don t fill holes */ /* read only up to the end of this quantum */ if (count > quantum - q_pos) count = quantum - q_pos; if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) { retval = -EFAULT; goto out; } *f_pos += count; retval = count; out: up(&dev->sem); return retval; }

ssize_t _write(struct file *filp, const char user *buf, size_t count, loff_t *f_pos) { struct _dev *dev = filp->private_data; struct _qset *dptr; int quantum = dev->quantum, qset = dev->qset; int itemsize = quantum * qset; int item, s_pos, q_pos, rest; ssize_t retval = -ENOMEM; /* value used in "goto out" statements */ if (down_interruptible(&dev->sem)) return -ERESTARTSYS; /* find listitem, qset index and offset in the quantum */ item = (long)*f_pos / itemsize; rest = (long)*f_pos % itemsize; s_pos = rest / quantum; q_pos = rest % quantum; /* follow the list up to the right position */ dptr = _follow(dev, item); if (dptr = = NULL) goto out;

if (!dptr->data) { dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL); if (!dptr->data) goto out; memset(dptr->data, 0, qset * sizeof(char *)); } if (!dptr->data[s_pos]) { dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL); if (!dptr->data[s_pos]) goto out; } /* write only up to the end of this quantum */ if (count > quantum - q_pos) count = quantum - q_pos; if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) { retval = -EFAULT; goto out; } *f_pos += count; retval = count; /* update the size */ if (dev->size < *f_pos) dev->size = *f_pos;