130 likes | 462 Views
The ‘ioctl’ driver-function. On implementing a way to query and modify our UART’s baudrate via the ‘device-file’ abstraction . ‘struct file_operations’. For a Linux device-driver’s ‘module_init()’ function, there are two main actions:
E N D
The ‘ioctl’ driver-function On implementing a way to query and modify our UART’s baudrate via the ‘device-file’ abstraction
‘struct file_operations’ • For a Linux device-driver’s ‘module_init()’ function, there are two main actions: • Initializing the driver’s global data-structures (this includes verifying the device’s presence) • Registering the driver’s service-functions with the kernel (i.e., the ‘file_operations’ structure) • The driver’s ‘module_exit()’ function then has the duty to ‘unregister’ those services
Driver services • For character-mode device-drivers (like ‘dram.c’, ‘cmos.c’ and ‘vram.c’), we have implemented some (or all) of the following service-functions (i.e., driver ‘methods’): • read() • llseek() • write() • mmap()
The ‘file’ paradigm • The UNIX approach to device-control is to create objects that represent i/o-devices, but which behave like ‘files’ do, insofar as the application programmer is concerned • So ‘read()’, ‘lseek()’, ‘write()’ and ‘mmap() use the same function-call syntax – and in most respects the same semantics – for both ordinary ‘files’ and ‘device-files’
An imperfect paradigm • But often there are a few ways in which the file-object paradigm doesn’t quite fit with important features of an i/o device • In these cases, device-drivers can provide a ‘workaround’ that allows applications to perform device-actions that deviate from customary ‘read/write/seek’ file-like actions • This ‘workaround’ mechanism is ‘ioctl()’
The serial UART • Our PC’s serial UART device offers us an easy example of some desirable behavior that’s outside the traditional ‘file’ paradigm • In order to use our ‘dev/vram’ device-file for communications with computers that we can’t control, we may need to adjust our UART’s communication parameters • How can a program change ‘baudrate’?
Our ‘baudrate.c’ module • These techniques are demonstrated in this device-driver module’s ‘ioctl()’ function • Two IOCTL services are implemented: #define GET_BAUDRATE 0 #define SET_BAUDRATE 1 • Applications can open the device-file and invoke an ‘ioctl’ system-call; for example: int fd = open( “/dev/uart”, O_RDWR ); ioctl( fd, GET_BAUDRATE, &baudrate );
Recall role of a device-driver A device-driver is a software module that controls a hardware device in response to OS kernel requests relayed, often, from an application hardware device operating parameters in out RAM device-driver module user application ret call call ret Operating System kernel syscall standard “runtime” libraries sysret user space kernel space
UART’s baudrate-control LSB DIVISOR LATCH (bits 7..0) i/o port 0x03F8 MSB DIVISOR LATCH (bits 15..8) i/o port 0x03F9 7 6 5 4 3 2 1 0 D L A B B R E A K parity controls stop bits data bits LINE CONTROL REGISTER i/o port 0x03FB
Algorithm to ‘get’ baudrate • Input (and save) the LINE_CONTROL • Set DLAB-bit in LINE_CONTROL to 1 • Input (and save) the DIVISOR_LATCH • Restore LINE_CONTROL to former value • Compute ‘baudrate’ from divisor_latch: baudrate 115200 / divisor_latch • Return this current ‘baudrate’ value
Algorithm to ‘set’ baudrate • Receive ‘baudrate’ as function-argument • Verify that argument is within valid range • Compute ‘divisor_latch’ from ‘baudrate’: divisor_latch 115200 / baudrate • Input (and save) the LINE_CONTROL • Set DLAB-bit in LINE_CONTROL to 1 • Output ‘divisor_latch’ to UART register • Restore LINE_CONTROL to former value
Demo-program: ‘setbaud.cpp’ • This application-program lets a user query or modify the UART’s current baudrate in a convenient manner – without requiring any ‘special’ privileges (don’t need ‘iopl3’) • To see the current baudrate: $ ./setbaud • To change the current baudrate: $ ./setbaud 2400
In-class exercise • Can you modify our ‘baudrate.c’ driver so it implements an additional ‘ioctl’ service: # define GET_LINECTRL 2 • Then add an extra ‘ioctl’ system-call in our ‘setbaud.cpp’ application so that it displays the UART’s current data-format (as well as baudrate) using format similar to 8-N-1 • HINT: look at driver’s ‘get_info()’ function