Title: Embedded Systems Programming
1Embedded Systems Programming
2Writing a new device driver
- When writing a device driver you can either
- Create a new, bespoke driver from scratch
- Or
- Port an existing driver
- Generally pick option 2 unless
- The hardware is so new to make porting impossible
- You are really experienced in device driver
writing - The driver has to do something really special or
diffferent
3Linux Execution Environment
4Linux Execution Paths
5Kernel Modules
- Kernel modules are inserted and unloaded
dynamically - Kernel code extensibility at run time
- insmod / lsmod/ rmmod commands. Look at
/proc/modules - Kernel and servers can detect and install them
automatically, for example, cardmgr (pc card
services manager) - Modules execute in kernel space
- Access to kernel resources (memory, I/O ports)
and global variables ( look at /proc/ksyms) - Export their own visible variables,
register_symtab () - Can implement new kernel services (new system
calls, policies) or low level drivers (new
devices, mechanisms) - Use internal kernel basic interface and can
interact with other modules (pcmcia memory_cs
uses generic card services module) - Need to implement init_module and cleanup_module
entry points, and specific subsystem functions
(open, read, write, close, ioctl )
6include ltlinux/delay.hgt include
ltlinux/module.hgt include ltlinux/ioport.hgt includ
e ltasm/io.hgt include ltasm/arch/io.hgt include
ltasm/arch/hardware.hgt include ltasm/uaccess.hgt de
fine DRIVER_AUTHOR "craig duffy
craig.duffy_at_uwe.ac.uk"define DRIVER_DESC
"FPGA DIO driver" define LED_ADDRESS
0xf2400680 define RGGG 0xf000 static int
fpga_dio_init(void) static int fpga_j
static short unsigned pattern
printk(KERN_ALERT "fpga dio loaded\n")
patternRGGG pattern pattern gtgt 4 for (
fpga_j0 fpga_j ! 16 fpga_j)
printk("pattern x\n",pattern)
udelay(400) writew(pattern,LED_ADDRESS)
pattern pattern gtgt 8 pattern--
pattern pattern ltlt 8 / return
0 static void fpga_dio_exit(void)
printk(KERN_ALERT "fpga dio unloaded\n") modul
e_init(fpga_dio_init)module_exit(fpga_dio_exit)
MODULE_LICENSE("GPL")MODULE_AUTHOR(DRIVER_AUTH
OR)MODULE_DESCRIPTION(DRIVER_DESC)MODULE_SUPPO
RTED_DEVICE("fpga_dio")
7Linking a module to the kernel (from Rubinis
book)
8Module programming
- Be careful a kernel fault is fatal to the
current process and sometimes the whole system - Modules should support concurrency (support calls
by different processes). Distinct data
structures for each process (since the same code
is executed) to ensure data is not corrupted. - Driver code must be reentrant keep status in
local (stack allocated) variables or dynamic
memory allocation kmalloc / kfree - This allows the process executing to suspend
(e.g., wait for pcmcia card interrupt) and other
processes to execute the same code. - It is not a good idea to assume your code wont
be interrupted. - Sleep_on(wait_queue) or interruptible_sleep_on(wai
t_queue) to yield the cpu to another process - /proc/ioports contains information about
registered ports. /proc/iomem contains info about
I/O memory
9Register Capability
- You can register a new device driver from the
kernel - int register_chrdev(unsigned int major, const
char name, struct file_operations fops) - A negative return value indicates an error, 0 or
positive indicates success. - major the major number being requested (a number
lt 128 or 256). - name the name of the device (which appears in
/proc/devices). - fops a pointer to a global jump table used to
invoke driver functions. - Then give to the programs a name by which they
can request the driver through a device node in
/dev - To create a char device node with major 254 and
minor 0, use - mknod /dev/memory_common c 254 0
- Minor numbers should be in the range of 0 to 255.
10Finding a device driver
- Obviously you need to be able to categorise the
device - Some Linux categories are not clear
- You can look at other open systems for example
NetBSD - This is useful as they may have ported the driver
themselves - Get as much reliable information about the device
- Data sheets, tested, stand alone code
11Example of a Parallel port
- It is quite often useful to use a parallel port
as an interface to some specialised hardware. - There are a number of approaches you could take
to controlling such hardware from Linux - A simple, low level kernel device driver
- Porting the parallel port package, ppdev,
- Writing a full blown device driver through the
file system - Writing a driver through the /procfs interface
12A simple low level kernel driver
- Under Linux it is always possible to write
directly to the hardware - This uses some low level calls to read and write
data - inb(), outb(), inw(), outw()
- The areas of memory are maped by the kernel and
ioremap/iounmap shopuld be used - Data has to be copied to and from user space unto
kernel space
13Problems with low level driver
- It is a good idea to use to test the hardware but
isnt a long term solution for driver development - Requires root access to run the kernel
- No file system interface
- Will be very limited functionality
- Cant use the kernel very effectively
- Isnt portable
- Can crash the kernel
14Porting an existing device
- With the parallel port one can use ppdev
- This give a high level interface into the file
system through /dev/parport0-n - Dont need root access
- Can have well structured driver
- Should be ported (in-time) with new kernel
releases - Less likely to cause kernel panics
15Problems with ppdev
- Unless it is a very standard parallel port
application it is likely to be difficult to get
the correct level of functionality - Will require understanding a lot of details of
parallel port and the driver which wont be
useful for your app
16Writing a device driver
- This allows you to create a new device in the
system - Uses VFS calls to access the drive
- Can open, read, write and close
- Uses ioctl calls
- Driver can be a module
- Only loaded when needed
- Easier development
17Problems