⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 node18.html

📁 Linux可卸载模块编程
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<!--Converted with LaTeX2HTML 98.1 release (February 19th, 1998)
originally by Nikos Drakos (nikos@cbl.leeds.ac.uk), CBLU, University of Leeds
* revised and updated by:  Marcus Hennecke, Ross Moore, Herb Swan
* with significant contributions from:
  Jens Lippmann, Marek Rouchal, Martin Wilck and others -->
<HTML>
<HEAD>
<TITLE>Talking to Device Files (writes and IOCTLs)</TITLE>
<META NAME="description" CONTENT="Talking to Device Files (writes and IOCTLs)">
<META NAME="keywords" CONTENT="mpg">
<META NAME="resource-type" CONTENT="document">
<META NAME="distribution" CONTENT="global">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<LINK REL="STYLESHEET" HREF="mpg.css">
<LINK REL="next" HREF="node19.html">
<LINK REL="previous" HREF="node17.html">
<LINK REL="up" HREF="mpg.html">
<LINK REL="next" HREF="node19.html">
</HEAD>
<BODY >
<!--Navigation Panel-->
<A NAME="tex2html599"
 HREF="node19.html">
<IMG WIDTH="37" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="next"
 SRC="next_motif.gif"></A> 
<A NAME="tex2html595"
 HREF="mpg.html">
<IMG WIDTH="26" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="up"
 SRC="up_motif.gif"></A> 
<A NAME="tex2html589"
 HREF="node17.html">
<IMG WIDTH="63" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="previous"
 SRC="previous_motif.gif"></A> 
<A NAME="tex2html597"
 HREF="node1.html">
<IMG WIDTH="65" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="contents"
 SRC="contents_motif.gif"></A> 
<A NAME="tex2html598"
 HREF="node34.html">
<IMG WIDTH="43" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="index"
 SRC="index_motif.gif"></A> 
<BR>
<B> Next:</B> <A NAME="tex2html600"
 HREF="node19.html">Startup Parameters</A>
<B> Up:</B> <A NAME="tex2html596"
 HREF="mpg.html">Linux Kernel Module Programming</A>
<B> Previous:</B> <A NAME="tex2html590"
 HREF="node17.html">Using /proc For Input</A>
<BR>
<BR>
<!--End of Navigation Panel-->

<H1><A NAME="SECTION00700000000000000000">&#160;</A><A NAME="dev-input">&#160;</A><A NAME="392">&#160;</A>
<A NAME="393">&#160;</A>
<A NAME="394">&#160;</A>
<A NAME="395">&#160;</A>
<BR>
Talking to Device Files (writes and IOCTLs)
</H1>

<P>
Device files are supposed to represent physical devices. Most physical
devices are used for output as well as input, so there has to be some
mechanism for device drivers in the kernel to get the output to send to 
the device from processes. This is done by opening the device file for 
output and writing to it, just like writing to a file. In the following 
example, this is implemented by <TT>device_write</TT>.

<P>
This is not always enough. Imagine you had a serial port connected to a modem
(even if you have an internal modem, it is still implemented from the CPU's
perspective as a serial port connected to a modem, so you don't have to tax 
your imagination too hard). The natural thing to do would be to use the 
device file to write things to the modem (either modem commands or data to 
be sent through the phone line) and read things from the modem (either 
responses for commands or the data received through the phone line). However, 
this leaves open the question of what to do when you need to talk to the 
serial port itself, for example to send the rate at which data is sent and
received.
<A NAME="397">&#160;</A>
<A NAME="398">&#160;</A>

<P>
The answer in Unix is to use a special function called <TT>ioctl</TT> (short for 
<B>i</B>nput <B>o</B>utput <B>c</B>on<B>t</B>ro<B>l</B>). Every device can have 
its own <TT>ioctl</TT> commands, 
which can be read <TT>ioctl</TT>'s (to send information from a process to the 
kernel), write <TT>ioctl</TT>'s (to return information to a process),
<A NAME="tex2html133"
 HREF="footnode.html#foot851"><SUP>5.1</SUP></A>
 both or neither. The 
ioctl function is called with three parameters: the file descriptor of the 
appropriate device file, the ioctl number, and a parameter, which is of
type long so you can use a cast to use it to pass anything.
<A NAME="tex2html134"
 HREF="footnode.html#foot410"><SUP>5.2</SUP></A> 

<P>
The ioctl number encodes the major device number, the type of the ioctl, the 
command, and the type of the parameter. This ioctl number is usually
created by a macro call (<TT>_IO</TT>, <TT>_IOR</TT>, <TT>_IOW</TT> or 
<TT>_IOWR</TT> -- depending on the
type) in a header file. This header file should then be <TT>#include</TT>'d both
by the programs which will use <TT>ioctl</TT> (so they can generate the 
appropriate
<TT>ioctl</TT>'s) and by the kernel module (so it can understand it). In the 
example below, the header file is <TT>chardev.h</TT> and the program which 
uses it is <TT>ioctl.c</TT>.
<A NAME="420">&#160;</A>
<A NAME="421">&#160;</A>
<A NAME="422">&#160;</A>
<A NAME="423">&#160;</A>

<P>
If you want to use <TT>ioctl</TT>'s in your own kernel modules, it is best to 
receive
an official <TT>ioctl</TT> assignment, so if you accidentally get somebody else's
<TT>ioctl</TT>'s, or if they get yours, you'll know something is wrong. For more 
information, consult the kernel source tree at 
`<TT>Documentation/ioctl-number.txt</TT>'.
<A NAME="428">&#160;</A>
<A NAME="429">&#160;</A>

<P>
ex
 
<FONT SIZE="+1"><B>chardev.c</B></FONT> 
<A NAME="434">&#160;</A><A NAME="435">&#160;</A> 

<P>
<PRE>
 
/* chardev.c 
 * 
 * Create an input/output character device
 */


/* Copyright (C) 1998-99 by Ori Pomerantz */



/* The necessary header files */

/* Standard in kernel modules */
#include &lt;linux/kernel.h&gt;   /* We're doing kernel work */
#include &lt;linux/module.h&gt;   /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include &lt;linux/modversions.h&gt;
#endif        

/* For character devices */

/* The character device definitions are here */
#include &lt;linux/fs.h&gt;       

/* A wrapper which does next to nothing at
 * at present, but may help for compatibility
 * with future versions of Linux */
#include &lt;linux/wrapper.h&gt;  

			     
/* Our own ioctl numbers */
#include "chardev.h"


/* In 2.2.3 /usr/include/linux/version.h includes a 
 * macro for this, but 2.0.35 doesn't - so I add it 
 * here if necessary. */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif



#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,2,0)
#include &lt;asm/uaccess.h&gt;  /* for get_user and put_user */
#endif



#define SUCCESS 0


/* Device Declarations ******************************** */


/* The name for our device, as it will appear in 
 * /proc/devices */
#define DEVICE_NAME "char_dev"


/* The maximum length of the message for the device */
#define BUF_LEN 80

/* Is the device open right now? Used to prevent 
 * concurent access into the same device */
static int Device_Open = 0;

/* The message the device will give when asked */
static char Message[BUF_LEN];

/* How far did the process reading the message get? 
 * Useful if the message is larger than the size of the 
 * buffer we get to fill in device_read. */
static char *Message_Ptr;


/* This function is called whenever a process attempts 
 * to open the device file */
static int device_open(struct inode *inode, 
                       struct file *file)
{
#ifdef DEBUG
  printk ("device_open(%p)\n", file);
#endif

  /* We don't want to talk to two processes at the 
   * same time */
  if (Device_Open)
    return -EBUSY;

  /* If this was a process, we would have had to be 
   * more careful here, because one process might have 
   * checked Device_Open right before the other one 
   * tried to increment it. However, we're in the 
   * kernel, so we're protected against context switches.
   *
   * This is NOT the right attitude to take, because we
   * might be running on an SMP box, but we'll deal with
   * SMP in a later chapter.
   */ 

  Device_Open++;

  /* Initialize the message */
  Message_Ptr = Message;

  MOD_INC_USE_COUNT;

  return SUCCESS;
}


/* This function is called when a process closes the 
 * device file. It doesn't have a return value because 
 * it cannot fail. Regardless of what else happens, you 
 * should always be able to close a device (in 2.0, a 2.2
 * device file could be impossible to close). */
#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,2,0)
static int device_release(struct inode *inode, 
                          struct file *file)
#else
static void device_release(struct inode *inode, 
                           struct file *file)
#endif
{
#ifdef DEBUG
  printk ("device_release(%p,%p)\n", inode, file);
#endif
 
  /* We're now ready for our next caller */
  Device_Open --;

  MOD_DEC_USE_COUNT;

#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,2,0)
  return 0;
#endif
}



/* This function is called whenever a process which 
 * has already opened the device file attempts to 
 * read from it. */
#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,2,0)
static ssize_t device_read(
    struct file *file,
    char *buffer, /* The buffer to fill with the data */   
    size_t length,     /* The length of the buffer */
    loff_t *offset) /* offset to the file */
#else
static int device_read(
    struct inode *inode,
    struct file *file,
    char *buffer,   /* The buffer to fill with the data */ 
    int length)     /* The length of the buffer 
                     * (mustn't write beyond that!) */
#endif
{
  /* Number of bytes actually written to the buffer */
  int bytes_read = 0;

#ifdef DEBUG
  printk("device_read(%p,%p,%d)\n",
    file, buffer, length);
#endif

  /* If we're at the end of the message, return 0 
   * (which signifies end of file) */
  if (*Message_Ptr == 0)
    return 0;

  /* Actually put the data into the buffer */
  while (length &amp;&amp; *Message_Ptr)  {

    /* Because the buffer is in the user data segment, 
     * not the kernel data segment, assignment wouldn't 
     * work. Instead, we have to use put_user which 
     * copies data from the kernel data segment to the 
     * user data segment. */
    put_user(*(Message_Ptr++), buffer++);
    length --;
    bytes_read ++;
  }

#ifdef DEBUG
   printk ("Read %d bytes, %d left\n",
     bytes_read, length);
#endif

   /* Read functions are supposed to return the number 
    * of bytes actually inserted into the buffer */
  return bytes_read;
}


/* This function is called when somebody tries to 
 * write into our device file. */ 
#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,2,0)
static ssize_t device_write(struct file *file,
                            const char *buffer,
                            size_t length,
                            loff_t *offset)
#else
static int device_write(struct inode *inode,
                        struct file *file,
                        const char *buffer,
                        int length)
#endif
{
  int i;

#ifdef DEBUG
  printk ("device_write(%p,%s,%d)",
    file, buffer, length);
#endif

  for(i=0; i&lt;length &amp;&amp; i&lt;BUF_LEN; i++)
#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,2,0)
    get_user(Message[i], buffer+i);
#else
    Message[i] = get_user(buffer+i);
#endif  

  Message_Ptr = Message;

  /* Again, return the number of input characters used */
  return i;
}


/* This function is called whenever a process tries to 
 * do an ioctl on our device file. We get two extra 
 * parameters (additional to the inode and file 
 * structures, which all device functions get): the number
 * of the ioctl called and the parameter given to the 
 * ioctl function.
 *
 * If the ioctl is write or read/write (meaning output 
 * is returned to the calling process), the ioctl call 
 * returns the output of this function.
 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -