 |
Errata und Ergänzungen zum Buch
"Linux Hardware Hackz"
Prof. Jürgen Plate |
Linux Treiberprogrammierung
Die Art und Weise, wie ein Treiber compiliert wird, hat sich geändert.
Hierzu folgt demnächst ein kleiner Artikel. Damit Sie schon einmal sehen
können, wie es nun geht, hat der Kollege Prof. Dr. Erik Kamsties von
der Fachhochschule Lübeck dankenswerter Weise ein Beispiel erstellt und
dabei auch gleich einen dicken Fehler von mir beseitigt. Es handelt sich um
Speicher-Treiber. Das Makefile lautet nun:
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
# called from kernel build system: just declare what our modules are
obj-m := mymem.o
endif
Der Treiber wird also nicht mehr separat erstellt, sondern durch den
Make-Mechanismus des Kernels erstellt, was vieles einfacher macht.
Der Treiber selbst hat folgenden Code:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#define MYMAJOR 250
static struct cdev *my_cdev;
static char driver_buffer[1024];
static int buffer_ptr;
static int driver_open(struct inode *geraete_datei, struct file *instanz)
{
printk(KERN_INFO "Open wurde aufgerufen\n");
if ((instanz->f_flags & O_ACCMODE) == O_WRONLY)
buffer_ptr = 0;
return 0;
}
static int driver_close(struct inode *geraete_datei, struct file *instanz)
{
printk(KERN_INFO "Close wurde aufgerufen\n");
return 0;
}
static ssize_t driver_read(struct file *File, char *user_buffer, size_t count, loff_t *offs)
{
int to_copy = count, i;
printk(KERN_INFO "Read wurde aufgerufen: %d\n", to_copy);
if (to_copy > buffer_ptr)
to_copy = buffer_ptr;
if (to_copy == 0)
return(0);
if ((i = copy_to_user(user_buffer, driver_buffer, to_copy)) != 0)
{
printk(KERN_INFO "Not_Copied_To_User = %d\n", i);
return(-EFAULT);
}
buffer_ptr -= to_copy;
return(to_copy);
}
static ssize_t driver_write(struct file *File, const char *user_buffer, size_t count, loff_t *offs)
{
int to_copy = count;
printk(KERN_INFO "Write wurde aufgerufen: %d\n", count);
if (to_copy > sizeof(driver_buffer))
to_copy = sizeof(driver_buffer);
if (copy_from_user(driver_buffer, user_buffer, to_copy) != 0)
{
return(-EFAULT);
}
printk(KERN_INFO "Copy_From_User = %s", driver_buffer);
buffer_ptr = to_copy;
return(to_copy);
}
static struct file_operations my_fops =
{
.owner = THIS_MODULE,
.open = driver_open,
.release = driver_close,
.read = driver_read,
.write = driver_write,
};
static int __init mymem_init(void)
{
int err, devno = MKDEV(MYMAJOR, 0);
my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;
my_cdev->owner = THIS_MODULE;
printk(KERN_INFO "MyMemTreiber wird eingebunden\n");
err = cdev_add(my_cdev, devno, 1);
if (!err)
{
buffer_ptr = 0;
printk("Device wurde belegt\n");
return 0;
}
printk(KERN_INFO "Dummy: unable to get major %d\n",MYMAJOR);
return(-EIO);
return 0;
}
static void __exit mymem_exit(void)
{
printk(KERN_INFO "Der Kernel ist nochmal davon gekommen\n");
cdev_del(my_cdev);
}
module_init(mymem_init);
module_exit(mymem_exit);
MODULE_AUTHOR("Dein Name");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Dies ist ein Speichertreiber");