The ‘ioctl’ driver-function On implementing a way to query

advertisement
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
operating parameters
RAM
hardware device
in
out
device-driver
module
user
application
ret
call
call
ret
syscall
standard
“runtime”
libraries
Operating System
kernel
sysret
user space
kernel space
UART’s baudrate-control
i/o port 0x03F8
LSB
DIVISOR LATCH
(bits 7..0)
i/o port 0x03F9
MSB
DIVISOR LATCH
(bits 15..8)
i/o port 0x03FB
7
6
5 4 3
2
D
L
A
B
B
R
E
A
K
parity
controls
stop
bits
1
0
data
bits
LINE CONTROL
REGISTER
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
Download