📄 parportbook.tmpl
字号:
port sharing, and so should only be used when sharing the port with other device drivers is impossible and would lead to incorrect behaviour. Use it sparingly! </para> <para> Devices can also be registered by device drivers based on their device numbers (the same device numbers as in the previous section). </para> <para> The <function>parport_open</function> function is similar to <function>parport_register_device</function>, and <function>parport_close</function> is the equivalent of <function>parport_unregister_device</function>. The difference is that <function>parport_open</function> takes a device number rather than a pointer to a <structname>struct parport</structname>. </para> <funcsynopsis> <funcsynopsisinfo>#include <parport.h> </funcsynopsisinfo> <funcprototype> <funcdef>struct pardevice *<function>parport_open</function></funcdef> <paramdef>int <parameter>devnum</parameter></paramdef> <paramdef>const char *<parameter>name</parameter></paramdef> <paramdef>int <parameter>(*pf)</parameter> <funcparams>void *</funcparams></paramdef> <paramdef>int <parameter>(*kf)</parameter> <funcparams>void *</funcparams></paramdef> <paramdef>int <parameter>(*irqf)</parameter> <funcparams>int, void *, struct pt_regs *</funcparams></paramdef> <paramdef>int <parameter>flags</parameter></paramdef> <paramdef>void *<parameter>handle</parameter></paramdef> </funcprototype> </funcsynopsis> <funcsynopsis> <funcprototype> <funcdef>void <function>parport_close</function></funcdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> </funcprototype> </funcsynopsis> <funcsynopsis> <funcprototype> <funcdef>struct pardevice *<function>parport_register_device</function></funcdef> <paramdef>struct parport *<parameter>port</parameter></paramdef> <paramdef>const char *<parameter>name</parameter></paramdef> <paramdef>int <parameter>(*pf)</parameter> <funcparams>void *</funcparams></paramdef> <paramdef>int <parameter>(*kf)</parameter> <funcparams>void *</funcparams></paramdef> <paramdef>int <parameter>(*irqf)</parameter> <funcparams>int, void *, struct pt_regs *</funcparams></paramdef> <paramdef>int <parameter>flags</parameter></paramdef> <paramdef>void *<parameter>handle</parameter></paramdef> </funcprototype> </funcsynopsis> <funcsynopsis> <funcprototype> <funcdef>void <function>parport_unregister_device</function></funcdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> </funcprototype> </funcsynopsis> <para> The intended use of these functions is during driver initialisation while the driver looks for devices that it supports, as demonstrated by the following code fragment: </para> <programlisting> <![CDATA[int devnum = -1;while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, devnum)) != -1) { struct pardevice *dev = parport_open (devnum, ...); ...} ]]></programlisting> <para> Once your device driver has registered its device and been handed a pointer to a <structname>struct pardevice</structname>, the next thing you are likely to want to do is communicate with the device you think is there. To do that you'll need to claim access to the port. </para> <funcsynopsis> <funcsynopsisinfo>#include <parport.h> </funcsynopsisinfo> <funcprototype> <funcdef>int <function>parport_claim</function></funcdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> </funcprototype> </funcsynopsis> <funcsynopsis> <funcprototype> <funcdef>int <function>parport_claim_or_block</function></funcdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> </funcprototype> </funcsynopsis> <funcsynopsis> <funcprototype> <funcdef>void <function>parport_release</function></funcdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> </funcprototype> </funcsynopsis> <para> To claim access to the port, use <function>parport_claim</function> or <function>parport_claim_or_block</function>. The first of these will not block, and so can be used from interrupt context. If <function>parport_claim</function> succeeds it will return zero and the port is available to use. It may fail (returning non-zero) if the port is in use by another driver and that driver is not willing to relinquish control of the port. </para> <para> The other function, <function>parport_claim_or_block</function>, will block if necessary to wait for the port to be free. If it slept, it returns <constant>1</constant>; if it succeeded without needing to sleep it returns <constant>0</constant>. If it fails it will return a negative error code. </para> <para> When you have finished communicating with the device, you can give up access to the port so that other drivers can communicate with their devices. The <function>parport_release</function> function cannot fail, but it should not be called without the port claimed. Similarly, you should not try to claim the port if you already have it claimed. </para> <para> You may find that although there are convenient points for your driver to relinquish the parallel port and allow other drivers to talk to their devices, it would be preferable to keep hold of the port. The printer driver only needs the port when there is data to print, for example, but a network driver (such as PLIP) could be sent a remote packet at any time. With PLIP, it is no huge catastrophe if a network packet is dropped, since it will likely be sent again, so it is possible for that kind of driver to share the port with other (pass-through) devices. </para> <para> The <function>parport_yield</function> and <function>parport_yield_blocking</function> functions are for marking points in the driver at which other drivers may claim the port and use their devices. Yielding the port is similar to releasing it and reclaiming it, but is more efficient because nothing is done if there are no other devices needing the port. In fact, nothing is done even if there are other devices waiting but the current device is still within its <quote>timeslice</quote>. The default timeslice is half a second, but it can be adjusted via a <filename>/proc</filename> entry. </para> <funcsynopsis> <funcsynopsisinfo>#include <parport.h> </funcsynopsisinfo> <funcprototype> <funcdef>int <function>parport_yield</function></funcdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> </funcprototype> </funcsynopsis> <funcsynopsis> <funcprototype> <funcdef>int <function>parport_yield_blocking</function></funcdef> <paramdef>struct pardevice *<parameter>dev</parameter></paramdef> </funcprototype> </funcsynopsis> <para> The first of these, <function>parport_yield</function>, will not block but as a result may fail. The return value for <function>parport_yield</function> is the same as for <function>parport_claim</function>. The blocking version, <function>parport_yield_blocking</function>, has the same return code as <function>parport_claim_or_block</function>. </para> <para> Once the port has been claimed, the device driver can use the functions in the <structname>struct parport_operations</structname> pointer in the <structname>struct parport</structname> it has a pointer to. For example: </para> <programlisting> <![CDATA[port->ops->write_data (port, d); ]]></programlisting> <para> Some of these operations have <quote>shortcuts</quote>. For instance, <function>parport_write_data</function> is equivalent to the above, but may be a little bit faster (it's a macro that in some cases can avoid needing to indirect through <varname>port</varname> and <varname>ops</varname>). </para> </chapter> <chapter id="portdrivers"> <title>Port drivers</title> <!-- What port drivers are for (i.e. implementing parport objects). --> <para> To recap, then:</para> <itemizedlist spacing=compact> <listitem> <para> The device driver registers itself with <literal>parport</literal>. </para> </listitem> <listitem> <para> A low-level driver finds a parallel port and registers it with <literal>parport</literal> (these first two things can happen in either order). This registration creates a <structname>struct parport</structname> which is linked onto a list of known ports. </para> </listitem> <listitem> <para> <literal>parport</literal> calls the <function>attach</function> function of each registered device driver, passing it the pointer to the new <structname>struct parport</structname>. </para> </listitem> <listitem> <para> The device driver gets a handle from <literal>parport</literal>, for use with <function>parport_claim</function>/<function>release</function>. This handle takes the form of a pointer to a <structname>struct pardevice</structname>, representing a particular device on the parallel port, and is acquired using <function>parport_register_device</function>. </para> </listitem> <listitem> <para> The device driver claims the port using <function>parport_claim</function> (or <function>function_claim_or_block</function>). </para> </listitem> <listitem> <para> Then it goes ahead and uses the port. When finished it releases the port. </para> </listitem> </itemizedlist> <para> The purpose of the low-level drivers, then, is to detect parallel ports and provide methods of accessing them (i.e. implementing the operations in <structname>struct parport_operations</structname>). </para> <!-- Should DocBookise this --> <para> A more complete description of which operation is supposed to do what is available in <filename>Documentation/parport-lowlevel.txt</filename>. </para> </chapter> <chapter id="lp"> <title>The printer driver</title> <!-- Talk the reader through the printer driver. --> <!-- Could even talk about parallel port console here. --> <para> The printer driver, <literal>lp</literal> is a character special device driver and a <literal>parport</literal> client. As a character special device driver it registers a <structname>struct file_operations</structname> using <function>register_chrdev</function>, with pointers filled in for <structfield>write</structfield>, <structfield>ioctl</structfield>, <structfield>open</structfield> and <structfield>release</structfield>. As a client of <literal>parport</literal>, it registers a <structname>struct parport_driver</structname> using <function>parport_register_driver</function>, so that <literal>parport</literal> knows to call <function>lp_attach</function> when a new parallel port is discovered (and <function>lp_detach</function> when it goes away). </para> <para> The parallel port console functionality is also implemented in <filename>drivers/char/lp.c</filename>, but that won't be covered here (it's quite simple though). </para> <para> The initialisation of the driver is quite easy to understand (see <function>lp_init</function>). The <varname>lp_table</varname> is an array of structures that contain information about a specific device (the <structname>struct pardevice</structname> associated with it, for example). That array is initialised to sensible values first of all. </para> <para> Next, the printer driver calls <function>register_chrdev</function> passing it a pointer to <varname>lp_fops</varname>, which contains function pointers for the printer driver's implementation of <function>open</function>, <function>write</function>, and so on. This part is the same as for any character special device driver. </para> <para> After successfully registering itself as a character special device driver, the printer driver registers itself as a <literal>parport</literal> client using <function>parport_register_driver</function>. It passes a pointer to this structure: </para> <programlisting> <![CDATA[static struct parport_driver lp_driver = { "lp", lp_attach, lp_detach, NULL}; ]]></programlisting> <para> The <function>lp_detach</function> function is not very interesting (it does nothing); the interesting bit is <function>lp_attach</function>. What goes on here depends on whether the user supplied any parameters. The possibilities are: no parameters supplied, in which case the printer driver uses every port that is detected; the user supplied the parameter <quote>auto</quote>, in which case only ports on which the device ID string indicates a printer is present are used; or the user supplied a list of parallel port numbers to try, in which case only those are used.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -