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

📄 uio-howto.tmpl

📁 linux 内核源代码
💻 TMPL
📖 第 1 页 / 共 2 页
字号:
<chapter id="custom_kernel_module" xreflabel="Writing your own kernel module"><?dbhtml filename="custom_kernel_module.html"?><title>Writing your own kernel module</title>	<para>	Please have a look at <filename>uio_cif.c</filename> as an	example. The following paragraphs explain the different	sections of this file.	</para><sect1 id="uio_info"><title>struct uio_info</title>	<para>	This structure tells the framework the details of your driver,	Some of the members are required, others are optional.	</para><itemizedlist><listitem><para><varname>char *name</varname>: Required. The name of your driver asit will appear in sysfs. I recommend using the name of your module for this.</para></listitem><listitem><para><varname>char *version</varname>: Required. This string appears in<filename>/sys/class/uio/uioX/version</filename>.</para></listitem><listitem><para><varname>struct uio_mem mem[ MAX_UIO_MAPS ]</varname>: Required if youhave memory that can be mapped with <function>mmap()</function>. For eachmapping you need to fill one of the <varname>uio_mem</varname> structures.See the description below for details.</para></listitem><listitem><para><varname>long irq</varname>: Required. If your hardware generates aninterrupt, it's your modules task to determine the irq number duringinitialization. If you don't have a hardware generated interrupt butwant to trigger the interrupt handler in some other way, set<varname>irq</varname> to <varname>UIO_IRQ_CUSTOM</varname>.If you had no interrupt at all, you could set<varname>irq</varname> to <varname>UIO_IRQ_NONE</varname>, though thisrarely makes sense.</para></listitem><listitem><para><varname>unsigned long irq_flags</varname>: Required if you've set<varname>irq</varname> to a hardware interrupt number. The flags givenhere will be used in the call to <function>request_irq()</function>.</para></listitem><listitem><para><varname>int (*mmap)(struct uio_info *info, struct vm_area_struct*vma)</varname>: Optional. If you need a special<function>mmap()</function> function, you can set it here. If thispointer is not NULL, your <function>mmap()</function> will be calledinstead of the built-in one.</para></listitem><listitem><para><varname>int (*open)(struct uio_info *info, struct inode *inode)</varname>: Optional. You might want to have your own<function>open()</function>, e.g. to enable interrupts only when yourdevice is actually used.</para></listitem><listitem><para><varname>int (*release)(struct uio_info *info, struct inode *inode)</varname>: Optional. If you define your own<function>open()</function>, you will probably also want a custom<function>release()</function> function.</para></listitem></itemizedlist><para>Usually, your device will have one or more memory regions that can be mappedto user space. For each region, you have to set up a<varname>struct uio_mem</varname> in the <varname>mem[]</varname> array.Here's a description of the fields of <varname>struct uio_mem</varname>:</para><itemizedlist><listitem><para><varname>int memtype</varname>: Required if the mapping is used. Set this to<varname>UIO_MEM_PHYS</varname> if you you have physical memory on yourcard to be mapped. Use <varname>UIO_MEM_LOGICAL</varname> for logicalmemory (e.g. allocated with <function>kmalloc()</function>). There's also<varname>UIO_MEM_VIRTUAL</varname> for virtual memory.</para></listitem><listitem><para><varname>unsigned long addr</varname>: Required if the mapping is used.Fill in the address of your memory block. This address is the one thatappears in sysfs.</para></listitem><listitem><para><varname>unsigned long size</varname>: Fill in the size of thememory block that <varname>addr</varname> points to. If <varname>size</varname>is zero, the mapping is considered unused. Note that you<emphasis>must</emphasis> initialize <varname>size</varname> with zero forall unused mappings.</para></listitem><listitem><para><varname>void *internal_addr</varname>: If you have to access this memoryregion from within your kernel module, you will want to map it internally byusing something like <function>ioremap()</function>. Addressesreturned by this function cannot be mapped to user space, so you must notstore it in <varname>addr</varname>. Use <varname>internal_addr</varname>instead to remember such an address.</para></listitem></itemizedlist><para>Please do not touch the <varname>kobj</varname> element of<varname>struct uio_mem</varname>! It is used by the UIO frameworkto set up sysfs files for this mapping. Simply leave it alone.</para></sect1><sect1 id="adding_irq_handler"><title>Adding an interrupt handler</title>	<para>	What you need to do in your interrupt handler depends on your	hardware and on how you want to	handle it. You should try to	keep the amount of code in your kernel interrupt handler low.	If your hardware requires no action that you	<emphasis>have</emphasis> to perform after each interrupt,	then your handler can be empty.</para> <para>If, on the other	hand, your hardware <emphasis>needs</emphasis> some action to	be performed after each interrupt, then you	<emphasis>must</emphasis> do it in your kernel module. Note	that you cannot rely on the userspace part of your driver. Your	userspace program can terminate at any time, possibly leaving	your hardware in a state where proper interrupt handling is	still required.	</para>	<para>	There might also be applications where you want to read data	from your hardware at each interrupt and buffer it in a piece	of kernel memory you've allocated for that purpose.  With this	technique you could avoid loss of data if your userspace	program misses an interrupt.	</para>	<para>	A note on shared interrupts: Your driver should support	interrupt sharing whenever this is possible. It is possible if	and only if your driver can detect whether your hardware has	triggered the interrupt or not. This is usually done by looking	at an interrupt status register. If your driver sees that the	IRQ bit is actually set, it will perform its actions, and the	handler returns IRQ_HANDLED. If the driver detects that it was	not your hardware that caused the interrupt, it will do nothing	and return IRQ_NONE, allowing the kernel to call the next	possible interrupt handler.	</para>	<para>	If you decide not to support shared interrupts, your card	won't work in computers with no free interrupts. As this	frequently happens on the PC platform, you can save yourself a	lot of trouble by supporting interrupt sharing.	</para></sect1></chapter><chapter id="userspace_driver" xreflabel="Writing a driver in user space"><?dbhtml filename="userspace_driver.html"?><title>Writing a driver in userspace</title>	<para>	Once you have a working kernel module for your hardware, you can	write the userspace part of your driver. You don't need any special	libraries, your driver can be written in any reasonable language,	you can use floating point numbers and so on. In short, you can	use all the tools and libraries you'd normally use for writing a	userspace application.	</para><sect1 id="getting_uio_information"><title>Getting information about your UIO device</title>	<para>	Information about all UIO devices is available in sysfs. The	first thing you should do in your driver is check	<varname>name</varname> and <varname>version</varname> to	make sure your talking to the right device and that its kernel	driver has the version you expect.	</para>	<para>	You should also make sure that the memory mapping you need	exists and has the size you expect.	</para>	<para>	There is a tool called <varname>lsuio</varname> that lists	UIO devices and their attributes. It is available here:	</para>	<para>	<ulink url="http://www.osadl.org/projects/downloads/UIO/user/">		http://www.osadl.org/projects/downloads/UIO/user/</ulink>	</para>	<para>	With <varname>lsuio</varname> you can quickly check if your	kernel module is loaded and which attributes it exports.	Have a look at the manpage for details.	</para>	<para>	The source code of <varname>lsuio</varname> can serve as an	example for getting information about an UIO device.	The file <filename>uio_helper.c</filename> contains a lot of	functions you could use in your userspace driver code.	</para></sect1><sect1 id="mmap_device_memory"><title>mmap() device memory</title>	<para>	After you made sure you've got the right device with the	memory mappings you need, all you have to do is to call	<function>mmap()</function> to map the device's memory	to userspace.	</para>	<para>	The parameter <varname>offset</varname> of the	<function>mmap()</function> call has a special meaning	for UIO devices: It is used to select which mapping of	your device you want to map. To map the memory of	mapping N, you have to use N times the page size as	your offset:	</para><programlisting format="linespecific">	offset = N * getpagesize();</programlisting>	<para>	N starts from zero, so if you've got only one memory	range to map, set <varname>offset = 0</varname>.	A drawback of this technique is that memory is always	mapped beginning with its start address.	</para></sect1><sect1 id="wait_for_interrupts"><title>Waiting for interrupts</title>	<para>	After you successfully mapped your devices memory, you	can access it like an ordinary array. Usually, you will	perform some initialization. After that, your hardware	starts working and will generate an interrupt as soon	as it's finished, has some data available, or needs your	attention because an error occured.	</para>	<para>	<filename>/dev/uioX</filename> is a read-only file. A	<function>read()</function> will always block until an	interrupt occurs. There is only one legal value for the	<varname>count</varname> parameter of	<function>read()</function>, and that is the size of a	signed 32 bit integer (4). Any other value for	<varname>count</varname> causes <function>read()</function>	to fail. The signed 32 bit integer read is the interrupt	count of your device. If the value is one more than the value	you read the last time, everything is OK. If the difference	is greater than one, you missed interrupts.	</para>	<para>	You can also use <function>select()</function> on	<filename>/dev/uioX</filename>.	</para></sect1></chapter><appendix id="app1"><title>Further information</title><itemizedlist>	<listitem><para>			<ulink url="http://www.osadl.org">				OSADL homepage.</ulink>		</para></listitem>	<listitem><para>		<ulink url="http://www.linutronix.de">		 Linutronix homepage.</ulink>		</para></listitem></itemizedlist></appendix></book>

⌨️ 快捷键说明

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