935-938.html
字号:
<HTML>
<HEAD>
<TITLE>Linux Unleashed, Third Edition:Writing Device Drivers</TITLE>
<SCRIPT>
<!--
function displayWindow(url, width, height) {
var Win = window.open(url,"displayWindow",'width=' + width +
',height=' + height + ',resizable=1,scrollbars=yes');
}
//-->
</SCRIPT>
</HEAD>
-->
<!--ISBN=0672313723//-->
<!--TITLE=Linux Unleashed, Third Edition//-->
<!--AUTHOR=Tim Parker//-->
<!--PUBLISHER=Macmillan Computer Publishing//-->
<!--IMPRINT=Sams//-->
<!--CHAPTER=58//-->
<!--PAGES=935-938//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//-->
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="931-935.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="../ch59/939-942.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<H4 ALIGN="LEFT"><A NAME="Heading11"></A><FONT COLOR="#000077">start and ioctl Routines</FONT></H4>
<P>A <TT>start</TT> routine is usually used for both block and character mode devices. It takes requests or data from device queues and sends them in order to the device. Block mode devices queue data with the <TT>strategy</TT> routine, while character mode devices use <TT>clist</TT>. The <TT>start</TT> routine maintains busy flags automatically as instructions are passed to the device. When a device has finished its process, it executes an <TT>intr</TT> routine which reinitializes the device for the next process.</P>
<P>The character mode <TT>ioctl()</TT> routine provides a special series of instructions to drivers. These include changes in the communications method between the driver and the operating system, as well as device-dependent operations (tape load or rewind, or memory allocation, for example).</P>
<P>The <TT>ioctl()</TT> function can be illustrated with the terminal device example. The <TT>ioctl()</TT> routine, in this case, calls another function that sets the device parameters. No code is supplied for the called function, but the skeleton explains the process of the device driver in order:</P>
<!-- CODE //-->
<PRE>
tdioctl(device,cmd,arg,mode) int device;
int cmd;
int mode;
faddr_t arg;
{
if(ttiocom(&td_tty[UNMODEM(device)],cmd,arg,mode))
tdparam(device)
}
dparam(device)
{
/* initialize variables */
/* get address and flags for referenced line */
addr=td_addr[UNMODEM(device)];
cflag=td_tty[UNMODEM(device].t_cflag;
/* check speed: if zero hang up line */
/* set up speed change */
/* set up line control */
/* manage interrupts */
}
</PRE>
<!-- END CODE //-->
<H3><A NAME="Heading12"></A><FONT COLOR="#000077">Using a New Device Driver</FONT></H3>
<P>Drivers are added to Linux systems in a series of steps. First the interrupt handler is identified, and then the device driver entry points (such as <TT>open</TT>) are added to a driver entry point table. The entire driver is compiled and linked to the kernel, and then placed in the <TT>/dev</TT> directory. (See Chapter 57, “Working with the Kernel,” for more information on adding to the Linux kernel.) Finally, the system is rebooted and the device driver tested. Obviously, changes to the driver require the process to be repeated, so device driver debugging is an art that minimizes the number of machine reboots!</P>
<BLOCKQUOTE>
<P><FONT SIZE="-1"><HR><B>Caution: </B><BR>Two basic <I>don’ts</I> are important for device driver programming. Don’t use <TT>sleep()</TT> or <TT>seterror()</TT> during interrupt suspensions, and don’t use floating point operations.
<P>Interrupt suspensions must be minimized, and they also must be used to avoid corruption of <TT>clist</TT> (or other buffer) data. Finally, it is important to minimize stack space.<HR></FONT>
</BLOCKQUOTE>
</P>
<P>You can simplify debugging device drivers in many cases by using judicious <TT>printf</TT> or <TT>getchar</TT> statements to another device, such as the console. Statements like <TT>printf</TT> and <TT>getchar</TT> enable you to set up code that traces the execution steps of the device driver. If you are testing the device when logged in as <TT>root</TT>, the <TT>adb</TT> debugger can be used to allow examination of the kernel’s memory while the device driver executes. Careful use of <TT>adb</TT> allows direct testing of minor changes in variables or addresses, but be careful—incorrect use of <TT>adb</TT> may result in system crashes!</P>
<P>One of the most common problems with device drivers (other than faulty coding) is the loss of interrupts or the suspension of a device while an interrupt is pending. This causes the device to hang. A time-out routine is included in most device drivers to prevent this. Typically, if an interrupt is expected and has not been received within a specified amount of time, the device is checked directly to ensure the interrupt was not missed. If an interrupt was missed, it can be simulated by code. Using the <TT>spl</TT> functions during debugging usually helps to isolate these problems.</P>
<P>Block mode-based device drivers are generally written using interrupts. However, more programmers are now using <I>polling</I> for character mode devices. Polling means the device driver checks at frequent intervals to determine the device’s status. The device driver doesn’t wait for interrupts but this does add to the CPU overhead the process requires. Polling is not suitable for many devices, such as mass storage systems, but it can be of benefit for character mode devices. Serial devices generally are polled to save interrupt overhead.</P>
<P>A 19,200 baud terminal causes approximately 1,920 interrupts per second, which in turn causes the operating system to interrupt and enter the device driver that many times. By replacing the interrupt routines with polling routines, the interval between CPU demands can be hugely decreased through the use of a small device buffer to hold intermediate characters generated to or from the device. Real-time devices also benefit from polling, since the number of interrupts does not overwhelm the CPU. If you want to use polling in your device drivers, you should read one of the books dedicated to device driver design because this is a complex subject.</P>
<H3><A NAME="Heading13"></A><FONT COLOR="#000077">Summary</FONT></H3>
<P>Most Linux users will never have to write a device driver, as most devices you can buy already have a device driver available. If you acquire brand new hardware or have an adventurous bug, you may want to try writing a driver, though. Device drivers are not really difficult to write (as long as you are comfortable coding in a high-level language like C), but drivers tend to be very difficult to debug. The device driver programmer must at all times be careful to not affect other processes or devices. However, there is a peculiar sense of accomplishment when a device driver executes properly. From here, there are some pertinent chapters to read (or re-read):
</P>
<DL>
<DD>Chapter 26, “Programming in C,” discusses the C programming language under Linux and how it can be used to write device drivers.
<DD>Chapter 28, “Perl,” discusses the handy language Perl, which can be used with surprising ease and power for quick programming tasks.
<DD>Chapter 30, “Other Compilers,” discusses other languages that are available for Linux.
</DL>
<P><BR></P>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="931-935.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="../ch59/939-942.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
</td>
</tr>
</table>
<!-- begin footer information -->
</body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -