‘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
13 trang |
Chia sẻ: candy98 | Lượt xem: 968 | Lượt tải: 0
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