Writing Linux Device Drivers

this file can be found at www.estss.com/opensource/cheatsheet.php

excellent (but wordy) overview to write linux device drivers from scratch

The Linux Kernel Module Programming Guide {{{

lsmod -> reads: /proc/modules


modinfo *.ko


	every kernel module needs to include this
	for list of available symbols exported by kernel:

	KERN_ALERT KERN_INFO etc.  (there are 8 priorities)

struct file_operations {
	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 __user *, size_t, loff_t);

	ssize_t(*write)		(struct file *, const char __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);
	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 datasync);
	int (*aio_fsync)	(struct kiocb *, int datasync);
	int (*fasync)		(int, struct file *, int);

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

	ssize_t(*readv)		(struct file *, const struct iovec *, unsigned long, loff_t *);
	ssize_t(*writev)	(struct file *, const struct iovec *, unsigned long, loff_t *);

	ssize_t(*sendfile)	(struct file *, loff_t *, size_t, read_actor_t, void __user *);
	ssize_t(*sendpage)	(struct file *, struct page *, int, size_t, loff_t *, int);

	unsigned long (*get_unmapped_area)
						(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);

struct file_operations fops = {
	.read = device_read,
	.write = device_write,
	.open = device_open,
	.release = device_release


obj-m += hello-1.o

	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


Example 2-7. hello-5.c
- fairly complete module summary with: MACROS, parameters, init, exit 

More char_driver examples see: SolidusCode and rulingminds/mod_*



struct proc_dir_entry

- create the file /proc/helloworld in the function
	init_module :: create_proc_entry

- return a value (and a buffer) when the file /proc/helloworld
  is [ read ] in the callback function

- return a value when the file /proc/helloworld is [ writen ] in the callback function

- and delete the file /proc/helloworld in the function
	cleanup_module :: remove_proc_entry

See Example 5-3. procfs3.c


Device Drivers

The ioctl number encodes:
- the major device number
- the type of the ioctl
- the command
- and the type of the parameter

need (though not required) an official ioctl assignment:
- Documentation/ioctl-number.txt

Example 7-1 to 7-3
- fairly complete ioctl summary with:
	register_chrdev		(init)
	unregister_chrdev	(exit)
	put_user			(read)
	get_user			(write)

	file_operations.ioctl = int device_ioctl( //  (module/kernelspace)
		/* see include/linux/fs.h */
			struct inode *inode,
			struct file *file,
		/* number and param for ioctl */
			unsigned int ioctl_num,
			unsigned long ioctl_param);
	--> which basically is a switch statement of ioctl_request_IDs

- ioctl requests (MACRO) IDs:
	_IOR (MAJOR_NUM, ioctl_num, ioctl_param)
	_IOWR(MAJOR_NUM, ioctl_num, ioctl_param)

- ioctl is accessed by: (app/userspace)
	fd = open( "name_of_device", 0 );
	ret_val = ioctl( fd, ioctl_request_ID, data );


system calls
user process fill the registers with values, then tells the kernel to jump
(via interrupt 0x80) to a previously defined location in the kernel
-- this is no longer running in restricted user mode


to make syscall stealing: Example 8-1 syscall.c

note: sys_call_table is no longer exported -- to keep people from doing
potential harmful things, you will have to patch your current kernel in
order to have sys_call_table exported. In the example directory you will
find a README and the patch.


To add a new syscall to the kernel: see rulingminds/0_system_calls_notes.txt 


fun drivers:

Example 10-2 kbleds.c - Blink keyboard leds until the module is unloaded

The Linux Kernel Module Programming Guide }}}

USB device driver

Linux Device Drivers, Third Edition
- PDF all chapters



struct usb_serial_device_type {
  struct module *owner;
  char *name;
  const struct usb_device_id *id_table;
  char num_interrupt_in;
  char num_bulk_in;
  char num_bulk_out;
  char num_ports;
  struct list_head driver_list;
  int (*probe) (struct usb_serial *serial);
  int (*attach) (struct usb_serial *serial);
  int (*calc_num_ports) (struct usb_serial *serial);
  void (*shutdown) (struct usb_serial *serial);
  int  (*open) (struct usb_serial_port *port,
                struct file * filp);
  void (*close) (struct usb_serial_port *port,
                 struct file * filp);
  int  (*write) (struct usb_serial_port *port,
                 int from_user,
                 const unsigned char *buf,
                 int count);
  int  (*write_room) (struct usb_serial_port *port);
  int  (*ioctl) (struct usb_serial_port *port,
                 struct file * file,
                 unsigned int cmd,
                 unsigned long arg);
  void (*set_termios) (struct usb_serial_port *port,
                       struct termios * old);
  void (*break_ctl) (struct usb_serial_port *port,
                     int break_state);
  int  (*chars_in_buffer)
         (struct usb_serial_port *port);
  void (*throttle) (struct usb_serial_port *port);
  void (*unthrottle) (struct usb_serial_port *port);
  void (*read_int_callback)(struct urb *urb);
  void (*read_bulk_callback)(struct urb *urb);
  void (*write_bulk_callback)(struct urb *urb);

Copyright © 2012 by Nick Shin. All Rights Reserved.
These pages are designed by ESTSS.