device driver (1)

16
Device Drivers In Linux  © Gregory Ke sden 2000 15-412 Fall 2000

Upload: prabhatravi

Post on 04-Apr-2018

214 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 1/16

Device Drivers In Linux

 © Gregory Kesden 2000

15-412 Fall 2000

Page 2: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 2/16

Device Types

• Block devices

Random access devices (buffering) For example a file system

can only be mounted on a block device, because it requires

random access.

For example, disks are commonly implemented as block 

devices.

• Character devices

Sequential access (no buffering). Examples might include

 printers, scanners, sound boards, &c.

The same device may have both block and character oriented

interfaces (In other UNIX this would actually require separatedrivers. A block device driver and a raw device driver.)

Page 3: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 3/16

Major and Minor Numbers

•Major number 

Each device driver is identified by a unique major number.

This number is assigned by the Linux Device Registrar (A

human – currently [email protected]). This number is the

index into an array that contains the information about the

driver (the device_struct)

• Minor number 

This uniquely identifies a particular instance of a device. For 

example, a system may have multiple IDE hard disks each

would have a major number of 3, but a different minor number.

• mknod /dev/name type major minor 

Tin UNIX, the interface to devices is via the file system. To create a

file representing a device, you use mknod and supply the filename

and the device’s type (c for character or b for block) and the

device’s major and minor number.

Page 4: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 4/16

The file_operation structure

•The file operation structure for a device contains pointers to all of the functions for a device. This is what maps the functions in the

generic interface into the specific device’s behaviors.. 

• The mappings are maintained in two arrays:

static struct device_struct chrdevs[MAX_CHRDEV]

static struct device_struct blkdevs[MAX_BLKDEV]

• The same device can have both character and block interfaces, so

it can have mappings in both arrays.

Page 5: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 5/16

struct file_operations {

loff_t (*llseek) (struct file *, loff_t, int);

ssize_t (*read) (struct file *, char *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char *, size_t, loff_t *);

int (*readdir) (struct file *, void *, filldir_t);

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 (*fasync) (int, struct file *, int);

int (*check_media_change) (kdev_t dev);

int (*revalidate) (kdev_t dev);

int (*lock) (struct file *, int, struct file_lock *);

};

Page 6: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 6/16

Setup Function - Overview

IntroductionSetup functions are not necessary. They allow parameters to a driver tobe supplied as boot parameters. They should do nothing more than setglobal variable – the init() function should do all of the real work.

•Boot parameters

When the kernel boots, it may be initialized with parameters destined for 

a particular device driver. The paramaters passed to the kernel generallytake the form:

name=param1,parms2,parm3,…,parmn name=parm1,…parmn 

•parseoption()

The parseoption() function is called by the kernel to break the commandline into separate strings for each driver:

name=parm1,parm2,parm3,… 

•checksetup()

This function checks the name field of the parameter to find the matchingdevice driver. If it finds a match, it invokes the specified setup function,passing it the parameters as an integer array. It was once a simple

function using a static mapping table – it now uses ELF black magic. 

Page 7: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 7/16

Setup Function -- Example

static int __init BusLogic_Setup(char *str) {int ints[3];

(void)get_options(str, ARRAY_SIZE(ints), ints);

if (ints[0] != 0) {

BusLogic_Error("BusLogic: Obsolete Command Line Entry”

"Format Ignored\n", NULL);

return 0;

}

if (str == NULL || *str == '\0')

return 0;

return BusLogic_ParseDriverOptions(str);

}

/* This is black magic – checksetup() plays in ELF land! */

 __setup("BusLogic=", BusLogic_Setup);

Page 8: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 8/16

The Init() Function

The call to the init() function for a driver is hard-coded into thekernel’s bootstrap code. For example, a SCSI device’s intialization

function could be called within scsi_dev_init() in

drivers/scsi/scsi.c

• The init() function should ensure that the device exists.

• The init function must register the driver’s character and/or blockinterface. This installs the mapping between the generic API and

the driver’s specific behaviors. Recall that these mappings are

maintained in arrays and were defined by the driver’s

file_operation struct.

There is an array of these file_operation structs for character (chrdevs[devices and another for block devices

 – register_chrdev (major_num, “name”, &file_operation_struct) 

 – register_blkdev (major_num, “name”, *file_operation_struct) 

• It can also perform any other initialization.

Page 9: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 9/16

Page 10: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 10/16

Nomenclature

In order to avoid name-space collisions with other definitions,functions or global variables, &c, anything that could pollute the

namespace everything should begin with a unique and descriptive

prefix.

• For example, consider the nomenclature used in the Vino Video

System:

 – struct vino_device { … } 

 – static struct vino_device vino[2];

 – static void vino_setup(struct vino_device *v) { … } 

 –

static int vino_init(void) { … }  – static void vino_dma_stop(void) { … } 

 – &c

Page 11: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 11/16

Polling Mode

Polling Mode is supported in Linux – although it is favorable for almost nothing. An older version of Linux (2.0) contained code for 

a polled mode parallel port driver. It’s main work loop looked like

this:

do {

status = LP_S(minor);

count++; /* count is used as a time-out */

if (need_resched) schedule();

} while(!LP_READY(minor,status) && count < LP_CHAR(minor));

Page 12: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 12/16

Interrupt Mode

Linux supports three different flavors of Interrupt Mode I/O: • “Slow” IRQs 

These are the most common type of ISR. Slow interrupts can beinterrupted by other interrupts. Before returning to an interruptedISR(), the ret_from_sys_call() is used – this macro restores theregisters, &c to their original values.

• “Fast” IRQs 

This mode is used for very brief ISRs. When “fast” mode is used,other interrupts are not allowed. This reduces the overheadrequired to invoke the ISR, because less state needs to bepreserved.

• Interrupt Sharing

Interrupt sharing is the ability to have one IRQ service multipledevices. Basically, a chain of ISRs, each for a different device, isconstructed for the IRQ. Each ISR is executed if the interruptoccurs. The ISRs should be able to interrogate the device todetermine if, in fact, there is any work for them to do.

Page 13: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 13/16

Installing an Interrupt Handler 

An ISR must be installed before it can be used. This is done usingthe request_irq() call:

int request_irq (unsigned int irq,void (*handler)(int, struct pt_regs *),unsigned long irqflags,const char *devname,

void *dev_id)• irq is the IRQ for which the handler is installed

• handler is the handler function

• irq_flags might include SA_INTERRUPT to specify fast IRQs or SA_SHIRQ to

specify a shared IRQ (or an ORed combination).

• devname should be the name of the device driver (used in /proc for accounting)

• dev_id is meaningless to the kernel, but is passed unchanged to the handler

Page 14: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 14/16

Interrupt Handler Shell

static void dev_interrupt (int irq, void *dev_id, struct pt_regs *regs)

{

/* irq contains the number of the IRQ that caused this handler to be invoked – the same handlercan be installed for multiple IRQs.

*/

/* dev_id contains whatever it was passed intorequest_irq() when this handler was installed.

*/

/*  pt_regs contains the registers from the processes that was interrupted by this handler

*/

}

Page 15: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 15/16

Bottom Half Support

Linux recognizes the fact that interrupt handlers should only takecare of actions that require immediate attention, so it has explicit

support for routines that compose the bottom half of a device

driver.

• Up to 32 bottom half routines can be defined.

•Bottom half routines are atomic with respect to each other.

• Bottom halve routines that have work to do are said to be active.

After every slow interrupt completes, if there are no interrupted or 

pending slow interrupts, the list of bottom halves is scanned and

active bottom halves are executed. (This is done as part of 

ret_from_syscall)• In a typical case, the ISR will take care of time-critical business

and activate a bottom half to finish the processing.

Page 16: device driver (1)

7/29/2019 device driver (1)

http://slidepdf.com/reader/full/device-driver-1 16/16

Using Bottom Halves

Three data structures are used to implement bottom halfs – bh_base  – A 32 entry array. It holds the pointers to the bottom half 

routines

 – bh_mask  – a 32 bit mask. A bit set in this mask indicates that a thecorresponding bottom half is initialized and usable.

 – bh_active  – a 32 bit mask. A bit set in this mask indicates that the

corresponding bottom half is active (has work to do).

• void init_bh (int nr, void (*routine)(void))

This installs routine as the handler for bottom half number nr.

• void disable_bh (int nr)

This disables a bottom half. It turns off the mask bit for the installedbottom half nr.

• void enable_bh (int nr)

This sets the mask bit for the installed bottom half nr.

• void mark_bh (int nr)

This “actives” a bottom half, indicating that there is work for it to do.