ldd3 编写scull尝试
快速参考:
#include <linux/types.h> dev_t dev_t is the type used to represent device numbers within the kernel.
int MAJOR(dev_t dev); int MINOR(dev_t dev); Macros that extract the major and minor numbers from a device number.
dev_t MKDEV(unsigned int major, unsigned int minor); Macro that builds a dev_t data item from the major and minor numbers.
#include <linux/fs.h> The “filesystem” header is the header required for writing device drivers. Many important functions and data structures are declared in here.
int register_chrdev_region(dev_t first, unsigned int count, char *name) int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name) void unregister_chrdev_region(dev_t first, unsigned int count);
Functions that allow a driver to allocate and free ranges of device numbers. register_chrdev_region should be used when the desired major number is known in advance; for dynamic allocation, use alloc_chrdev_region instead. int register_chrdev(unsigned int major, const char *name, struct file_operations *fops); The old (pre-2.6) char device registration routine. It is emulated in the 2.6 kernel but should not be used for new code. If the major number is not 0, it is used unchanged; otherwise a dynamic number is assigned for this device.
int unregister_chrdev(unsigned int major, const char *name); Function that undoes a registration made with register_chrdev. Both major and the name string must contain the same values that were used to register the driver.
struct file_operations; struct file; struct inode; Three important data structures used by most device drivers. The file_operations structure holds a char driver’s methods; struct file represents an open file, and struct inode represents a file on disk.
#include <linux/cdev.h> struct cdev *cdev_alloc(void); void cdev_init(struct cdev *dev, struct file_operations *fops); int cdev_add(struct cdev *dev, dev_t num, unsigned int count); void cdev_del(struct cdev *dev); Functions for the management of cdev structures, which represent char devices within the kernel. #include <linux/kernel.h> container_of(pointer, type, field); A convenience macro that may be used to obtain a pointer to a structure from a pointer to some other structure contained within it.
#include <asm/uaccess.h> This include file declares functions used by kernel code to move data to and from user space. unsigned long copy_from_user (void *to, const void *from, unsigned long count); unsigned long copy_to_user (void *to, const void *from, unsigned long count);
Copy data between user space and kernel space.
第一节的测试:
#include <linux/module.h> #include <linux/init.h> #include <linux/types.h> /* dev_t */ #include <linux/kdev_t.h> /* MAJOR(dev_t dev); MINOR(dev_t dev); */ #include <linux/fs.h> /* chrdev_region */ #include "my_scull.h" MODULE_AUTHOR("chen"); MODULE_LICENSE("Dual BSD/GPL"); int my_scull_major = MY_SCULL_MAJOR; int my_scull_minor = 0; int my_scull_nr_devs = MY_SCULL_NR_DEVS; static int my_scull_init(void) { int result; dev_t dev; printk(KERN_ALERT "my scull init "); /* * Get a range of minor numbers to work with, asking for a dynamic * major unless directed otherwise at load time. */ if(my_scull_major) { dev = MKDEV(my_scull_major, my_scull_minor); result = register_chrdev_region(dev, my_scull_nr_devs, "my_scull"); } else { result = alloc_chrdev_region(&dev, my_scull_minor, my_scull_nr_devs, "my_scull"); my_scull_major = MAJOR(dev); } if(result < 0) { printk(KERN_WARNING "my scull:can't get major %d ", my_scull_major); return result; } printk(KERN_ALERT "myscull dev:%d, major:%d, minor:%d ", dev, my_scull_major, my_scull_minor); return 0; } static void my_scull_cleanup(void) { dev_t devno = MKDEV(my_scull_major, my_scull_minor); /* my_scull_cleanup is never called if registering failed */ unregister_chrdev_region(devno, my_scull_nr_devs); printk(KERN_ALERT "my scull clean up "); } module_init(my_scull_init); module_exit(my_scull_cleanup);
my_scull_load:
#!/bin/sh module="my_scull" device="my_scull" mode="644" # invoke insmod with all arguments we got # and use a pathname, as newer modutils don't look in. by default /sbin/insmod ./$module.ko $* || exit 1 # remove stale nodes rm -f /dev/${device}[0-3] major=$(awk "$2=="$module" {print $1}" /proc/devices) echo $major #echo "/dev/${device}0 c $major 0" mknod /dev/${device}0 c $major 0 mknod /dev/${device}1 c $major 1 mknod /dev/${device}2 c $major 2 mknod /dev/${device}3 c $major 3 # give appropriate group/permissions, and change the group. # Not all distributions have staff, some have "wheel" instead. group="staff" grep -q '^staff:' /etc/group || group="wheel" chgrp $group /dev/${device}[0-3] chmod $mode /dev/${device}[0-3]