除了由file_operations结构定义的函数之外,至少还有一个您必须编写的函数,即foo_init()函数。您将需要更改chr_dev_init()在 drivers/char/mem.c 中调用您的foo_init()函数。
foo_init()应该首先调用register_chrdev()来注册它自己并避免设备号冲突。register_chrdev()接受三个参数
通常,foo_init()例程将尝试检测它应该驱动的硬件。它应该确保为所有存在的硬件填充所有必要的数据结构,并采取某种方法确保不会访问不存在的硬件。 [详细说明不同的方法。特别是,文档化 request_* 和相关函数。]
在轮询驱动程序中,foo_read()和foo_write()函数很容易编写。这是一个foo_write():
static int foo_write(struct inode * inode, struct file * file, char * buf, int count) { unsigned int minor = MINOR(inode->i_rdev); char ret; while (count > 0) { ret = foo_write_byte(minor); if (ret < 0) { foo_handle_error(WRITE, ret, minor); continue; } buf++ = ret; count-- } return count; }foo_write_byte()和foo_handle_error()是 foo.c 中其他地方定义的函数或伪代码。WRITE将是一个常量或#define.
从这个例子中应该清楚如何编写foo_read()函数。
中断驱动的驱动程序稍微困难一些。这是一个中断驱动的foo_write()的例子
static int foo_write(struct inode * inode, struct file * file, char * buf, int count) { unsigned int minor = MINOR(inode->i_rdev); unsigned long copy_size; unsigned long total_bytes_written = 0; unsigned long bytes_written; struct foo_struct *foo = &foo_table[minor]; do { copy_size = (count <= FOO_BUFFER_SIZE ? count : FOO_BUFFER_SIZE); memcpy_fromfs(foo->foo_buffer, buf, copy_size); while (copy_size) { /* initiate interrupts */ if (some_error_has_occured) { /* handle error condition */ } current->timeout = jiffies + FOO_INTERRUPT_TIMEOUT; /* set timeout in case an interrupt has been missed */ interruptible_sleep_on(&foo->foo_wait_queue); bytes_written = foo->bytes_xfered; foo->bytes_written = 0; if (current->signal & ~current->blocked) { if (total_bytes_written + bytes_written) return total_bytes_written + bytes_written; else return -EINTR; /* nothing was written, system call was interrupted, try again */ } } total_bytes_written += bytes_written; buf += bytes_written; count -= bytes_written; } while (count > 0); return total_bytes_written; } static void foo_interrupt(int irq) { struct foo_struct *foo = &foo_table[foo_irq[irq]]; /* Here, do whatever actions ought to be taken on an interrupt. Look at a flag in foo_table to know whether you ought to be reading or writing. */ /* Increment foo->bytes_xfered by however many characters were read or written */ if (buffer too full/empty) wake_up_interruptible(&foo->foo_wait_queue); }
同样,foo_read()函数以类似的方式编写。foo_table[]是一个结构数组,每个结构都有几个成员,其中一些是foo_wait_queue和bytes_xfered,可以用于读取和写入。foo_irq[]是一个包含 16 个整数的数组,用于查找foo_table[]中哪个条目与irq关联,该中断被生成并报告给foo_interrupt()函数。
要告诉中断处理代码调用foo_interrupt(),您需要使用request_irq()或irqaction()。这可以在调用foo_open()时完成,或者如果您想保持简单,则在foo_init()调用时完成。request_irq()是两者中较简单的一个,并且很像旧式信号处理程序。它接受两个参数:第一个是您请求的irq的数量,第二个是指向您的中断处理程序的指针,该处理程序必须接受一个整数参数(生成的 irq)并且具有返回类型void. request_irq()返回-EINVAL如果irq> 15 或者如果指向中断处理程序的指针是NULL, -EBUSY如果该中断已被占用,则返回 -EBUSY,成功则返回 0。
irqaction()的功能很像用户级sigaction(),实际上重用了sigaction结构。sigaction 结构的 sa_restorer()字段未使用,但其他所有内容都相同。有关irqaction()的更多信息,请参阅 支持函数 中的条目。irqaction().
版权所有 (C) 1992, 1993, 1994, 1996 Michael K. Johnson, johnsonm@redhat.com。