1 / 33

Character Device Driver (Delay Routine with CMOS RAM example)

Character Device Driver (Delay Routine with CMOS RAM example). Dr A Sahu Dept of Comp Sc & Engg . IIT Guwahati. Outline. Writing/Registering to /proc Character Device Driver Characteristics and functionality Basic IO functions Examples (ADC, DAC, Printer, Test data generator)

Download Presentation

Character Device Driver (Delay Routine with CMOS RAM example)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Character Device Driver(Delay Routine with CMOS RAM example) Dr A Sahu Dept of Comp Sc & Engg. IIT Guwahati

  2. Outline • Writing/Registering to /proc • Character Device Driver • Characteristics and functionality • Basic IO functions • Examples (ADC, DAC, Printer, Test data generator) • Create 30S Delay SR using CMOS Data • Real Time CMOS Clock • 30S Delay

  3. Linux Kernel Modules Linux allows us to write our own installable kernel modules and add them to a running system application module ret call call Operating System kernel ret syscall standard “runtime” libraries sysret user space kernel space

  4. Creating our own ‘/proc’ files • We can write code to implement our own ‘pseudo’ files, located in ‘/proc’ directory • We do this by adding a ‘payload’ function to a Linux Kernel Module, and by including calls to special kernel-functions within our module-init and our module-exit routines • These special kernel-functions serve to ‘register’, and ‘unregister’, our payload

  5. Register/unregister • Your module-initialization function should ‘register’ the module’s ‘get_info()’ function: create_proc_info_entry( modname, 0, NULL, get_info ); • Your cleanup should do an ‘unregister’: remove_proc_entry( modname, NULL ); the name for your proc file the file-access attributes (0=default) directory where file will reside (NULL=default) function-pointer to your module’s ‘callback’ routine directory file’s name

  6. Device Driver (Block/Character) • A device driver is a kernel module responsible for managing low-level I/O operations for a particular hardware device. • VFS • Block drivers: Physically addressable media (disks) • All other devices are considered character devices • Line printer, ADC, DAC, …

  7. Overall Architecture (cont.) System Call Interface Socket VFS File System Network Protocol Buffer Cache Block Device Driver Character Device Driver Network Device Driver Hardware

  8. Loadable Module Entry Points • All drivers are required to implement the loadable module entry points • init () // (load) • finalize () //unload • info () // Gather information of device • Drivers should allocate and initialize any global resources in init() and release their resources in finalize().

  9. Character Driver • Device Properties • can’t be randomly accessed • can’t be buffered • usually are slow devices • Export Interface • file_operations • Data Flow in read/write

  10. Basic char-driver components Device-driver LKM layout module’s ‘payload’ is a collection of callback-functions having prescribed prototypes function function function AND a ‘package’ of function-pointers fops . . . the usual pair of module-administration functions init registers the ‘fops’ exit unregisters the ‘fops’

  11. Character Device Drivers • Character device drivers normally perform I/O in a byte stream. • Examples of devices using character drivers include tape drives and serial ports. • Character device drivers can also provide additional interfaces not present in block drivers, • I/O control (ioctl) commands • memory mapping • device polling.

  12. Character Driver Functions

  13. Character and Block Driver Entry Points • Block drivers are required to support strategy, while character drivers can choose to implement whatever mix of • read, write, ioctl, mmap, or devmap • These entry points as appropriate for the type of device. • Character drivers can also support a polling interface through • ch_poll • as well as asynchronous I/O through aread and awrite.

  14. Background • To appreciate the considerations that have motivated the over-all Linux driver’s design requires an understanding of how normal application-programs get their access to services that the operating system offers • This access is indirect – through specially protected interfaces (i.e., system calls) – usually implemented as ‘library’ functions

  15. Standard File-I/O functions int open( char *pathname, int flags, … ); int read( int fd, void *buf, size_t count ); int write( int fd, void *buf, size_t count ); int lseek( int fd, loff_t offset, int whence ); int close( int fd ); (and other less-often-used file-I/O functions)

  16. Special ‘device’ files • UNIX systems treat hardware-devices as special files, so that familiar functions can be used by application programmers to access devices (e.g., open, read, close) • But a System Administrator has to create these device-files (in the ‘/dev’ directory) • Or alternatively (as we’ve seen), an LKM could create these necessary device-files # mknod /dev/cmos c 70 0

  17. The ‘close’ function • Breaks link between file and file-descriptor • Returns 0 on success, or -1 if an error #include <unistd.h> int close( intfd );

  18. The ‘write’ function #include <unistd.h> int write( intfd, void *buf, size_t count); • Attempts to write up to ‘count’ bytes • Bytes are taken from ‘buf’ memory-buffer • Returns the number of bytes written • Or returns -1 if some error occurred • Return-value 0 means no data was written

  19. The ‘read’ function #include <unistd.h> int read( intfd, void *buf, size_t count ); • Attempts to read up to ‘count’ bytes • Bytes are placed in ‘buf’ memory-buffer • Returns the number of bytes read • Or returns -1 if some error occurred • Return-value 0 means ‘end-of-file’

  20. Notes on ‘read()’ and ‘write()’ • These functions have (as a “side-effect”) the advancement of a file-pointer variable • They return a negative function-value of -1 if an error occurs, indicating that no actual data could be transferred; otherwise, they return the number of bytes read or written • The ‘read()’ function normally does not return 0, unless ‘end-of-file’ is reached

  21. The ‘lseek’ function #include <unistd.h> off_tlseek(intfd, off_t offset, int whence ); enum { SEEK_SET, SEEK_CUR, SEEK_END }; • Modifies the file-pointer variable, based on the value of whence • Returns the new value of the file-pointer (or returns -1 if any error occurred)

  22. Getting the size of a file • For normal files, your application can find out how many bytes belong to a file using the ‘lseek()’ function: intfilesize=lseek(fd,0,SEEK_END); • But afterward you need to ‘rewind’ the file if you want to read its data: lseek( fd, 0, SEEK_SET );

  23. Implement a Simple Char Driver for CMOS RTC non-volatile memory • LKM implements a simple character-mode device-driver • For RT Clock's non-volatile memory(128 bytes). • It should fully supports read() and lseek() access, • Its support restricted access to • write(), only clock-and-calendar locations • The non-configuration data. root# mknod /dev/cmos c 70 0

  24. Example: ‘cmosram.c’ driver • We implement three callback functions: • llseek: // sets file-pointer’s position • read: // inputs a byte from CMOS • write: // outputs a byte to CMOS • We omit other callback functions, such as: • open: // we leave this function-pointer NULL • release: // we leave this function-pointer NULL • The kernel has its own ‘default’ implementation for any function with NULL as its pointer-value

  25. Basic char-driver components Device-driver LKM layout module’s ‘payload’ is a collection of callback-functions having prescribed prototypes function function function AND a ‘package’ of function-pointers fops . . . the usual pair of module-administration functions init registers the ‘fops’ exit unregisters the ‘fops’

  26. The ‘fops’ syntax • The GNU C-compiler supports a syntax for ‘struct’ field-initializations that lets you give your field-values in any convenient order: structfile_operationsmy_fops = { llseek: my_llseek, write: my_write, read: my_read, };

  27. Implement a Simple Char Driver for CMOS RTC non-volatile memory #include <linux/module.h> // for printk() #include <linux/fs.h> // for register_chrdev() #include <asm/uaccess.h> // for put_user(), get_user() #include <asm/io.h> // for inb(), outb() char modname[] = "cmosram"; // name of this kernel module char devname[] = "cmos"; // name for the device's file intmy_major = 70; // major ID-number for driver intcmos_size = 128; // total bytes of cmos memory intwrite_max = 9; // largest 'writable' address

  28. Character driver : Read() & Write() ssize_tmy_read( struct file *file, char *buf, size_tlen, loff_t *pos ) { unsigned char datum; if ( *pos >= cmos_size ) return 0; outb( *pos, 0x70 ); datum = inb( 0x71 ); if ( put_user( datum, buf ) ) return –EFAULT; *pos += 1; return 1; } ssize_tmy_write( struct file *file, const char *buf, size_tlen, loff_t *pos ) { unsigned char datum; if ( *pos >= cmos_size ) return 0; if ( *pos > write_max ) return –EPERM; if ( get_user( datum, buf ) ) return –EFAULT; outb( *pos, 0x70 ); outb( datum, 0x71 ); *pos += 1; return 1; }

  29. Character driver : Lseek() loff_tmy_llseek( struct file *file, loff_t pos, int whence ) { loff_tnewpos = -1; switch ( whence ) { case 0: newpos = pos; break; // SEEK_SET case 1: newpos = file->f_pos + pos; break; // SEEK_CUR case 2: newpos = cmos_size + pos; break; // SEEK_END } if (( newpos < 0 )||( newpos > cmos_size )) return –EINVAL; file->f_pos = newpos; return newpos; }

  30. Character driver : init(), exit(), ops structfile_operationsmy_fops = { owner: THIS_MODULE, llseek: my_llseek, write: my_write, read: my_read, }; static int __init my_init( void ) { printk( "<1>\nInstalling \'%s\' module ", devname ); printk( "(major=%d) \n", my_major ); return register_chrdev( my_major, devname, &my_fops ); } static void __exit my_exit(void ) { unregister_chrdev( my_major, devname ); printk( "<1>Removing \'%s\' module\n", devname ); } module_init( my_init ); module_exit( my_exit ); MODULE_LICENSE("GPL");

  31. 30 second loop: ThirtySec.cpp #include <stdio.h> // for printf(), perror() #include <fcntl.h> // for open() #include <unistd.h> // for read() int main( intargc, char **argv ) { int status = 0; intfd = open( "/dev/cmos", O_RDONLY ); if ( fd < 0 ) { perror( "/dev/cmos" ); return -1; } // Repeatedly reads Status_Reg until its bit has 'flipped‘ 30 times for (inti = 0; i < 30; i++) { do { // do busy-wait until UpdateInProgress is 'true' lseek( fd, 10, SEEK_SET ); read( fd, &status, 1 ); } while ( ( status & 0x80 ) == 0x00 ); do{ // do busy-wait until UpdateInProgress is 'false’ lseek( fd, 10, SEEK_SET ); read( fd, &status, 1 ); } while ( ( status & 0x80 ) == 0x80 ); printf( " %d Second Elapsed\n", i+1 ); } }

  32. Lab Exercise • Download mmake.cpp and cmosram.c • Course Website, tested on Fedora 12 • Compile mmake.cpp using ‘g++’ • Then compile cmosram.cusing ‘make’ • Install ‘cmos.ko’ (and see printk-message) • See $cat /proc/cmos • Compile ThirtySec.cpp and execute..

  33. Thanks

More Related