second_cdrv.c :
#include <linux/init.h>
#include <linux/module.h>#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
static dev_t dev_id;
static struct cdev *my_cdev;
static struct class *second_drv_class;
static struct device *second_drv_class_device;
static volatile unsigned long *gpbcon;
static volatile unsigned long *gpbdat;
#define led_on(n) *gpbdat &= ~(1<<(n+4))
#define led_off(n) *gpbdat |= (1<<(n))
static int second_cdrv_read (struct file * file, char __user * buf, size_t count, loff_t *offset)
{
printk(KERN_ALERT"second_cdrv_read start.\n");
return 0;
}
static int second_cdrv_write (struct file * file, const char __user * buf, size_t count, loff_t *offset)
{
char val;
if(count != 1)
{
return -EINVAL;
}
copy_from_user(&val, buf, 1);
if(val >= 1 && val <= 4)
{
led_on(val);
}
else if(val>= 5 && val <= 8)
{
led_off(val);
}
else
{
return -EINVAL;
}
return 0;
}
static int second_cdrv_release (struct inode * inode, struct file * file)
{
iounmap(gpbcon);
iounmap(gpbdat);
return 0;
}
static int second_cdrv_open (struct inode * inode, struct file * file)
{
gpbcon = (unsigned long *)ioremap(0x56000010 , 4);
gpbdat = (unsigned long *)ioremap(0x56000014 , 4);
*gpbcon &= ~(3<<10|3<<12|3<<14|3<<16);
*gpbcon |= (1<<10|1<<12|1<<14|1<<16);
*gpbdat |= (1<<5|1<<6|1<<7|1<<8);
return 0;
}
struct file_operations fops ={
.owner = THIS_MODULE,
.open = second_cdrv_open,
.read = second_cdrv_read,
.write = second_cdrv_write,
.release = second_cdrv_release,
};
static int __init second_cdrv_init(void)
{
int ret = 0;
ret = alloc_chrdev_region(&dev_id, 0, 4, "second_cdrv");
if(ret != 0)
{
printk(KERN_ERR"alloc_chrdev_region failed\n");
}
my_cdev = cdev_alloc();
cdev_init(my_cdev, &fops);
my_cdev->owner = THIS_MODULE;
ret = cdev_add(my_cdev, dev_id, 4);
if(ret != 0)
{
printk(KERN_ERR"cdev_add failed\n");
}
second_drv_class = class_create(THIS_MODULE, "second_cdrv");
second_drv_class_device = device_create(second_drv_class, NULL, dev_id, NULL, "chenjun");
return 0;
}
static void __exit second_cdrv_exit(void)
{
device_destroy(second_drv_class, dev_id);
class_destroy(second_drv_class);
cdev_del(my_cdev);
if(my_cdev)
{
printk(KERN_ALERT"kzfree\n");
kzfree(my_cdev);
my_cdev = NULL;
}
unregister_chrdev_region(dev_id, 4);
}
module_init(second_cdrv_init);
module_exit(second_cdrv_exit);
Makefile:
KERNELDIR := /opt/wfe/linux-3.2_m
PWD := $(shell pwd)
#obj-m := hello_world.o
#obj-m := first_cdrv.o
obj-m := second_cdrv.o
COMPILE_GCC := arm-linux-gcc
TEST := test
TEST_FILE := module_test.c
CLEAN_FILES := *.mod.* *.symvers *.order *.o *.ko $(TEST)
M_CFLAGS := -Os -Wall -g -c
default:
make -C $(KERNELDIR) M=$(PWD) modules
$(TEST):$(TEST_FILE)
$(COMPILE_GCC) -o $@ $<
.PHONY:clean
clean:
rm -rf $(CLEAN_FILES)
module_test.c :
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
char i = 1;
int ret = 0;
int fd;
fd = open("/dev/chenjun",O_RDWR);
while(1)
{
ret = write(fd, &i, 1);
sleep(1);
if(i++ == 8)
{
i = 1;
}
}
return 0;
}