Advanced Systems Programming - Lesson 16: The ‘ioctl’ driver-function

‘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

pdf13 trang | Chia sẻ: candy98 | Lượt xem: 968 | Lượt tải: 0download
Bạn đang xem nội dung tài liệu Advanced Systems Programming - Lesson 16: The ‘ioctl’ driver-function, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
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 user application standard “runtime” libraries call ret user space kernel space Operating System kernel syscall sysret device-driver module call ret hardware device out in operating parameters RAM A device-driver is a software module that controls a hardware device in response to OS kernel requests relayed, often, from an application UART’s baudrate-control MSB LSBi/o port 0x03F8 i/o port 0x03F9 i/o port 0x03FB D L A B LINE CONTROL REGISTER DIVISOR LATCH (bits 7..0) DIVISOR LATCH (bits 15..8) B R E A K data bits stop bits parity controls 7 6 5 4 3 2 1 0 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