现在的位置: 首页 > 综合 > 正文

3-2信号量驱动实例

2012年07月23日 ⁄ 综合 ⁄ 共 8008字 ⁄ 字号 评论关闭
 实例一:没有信号量的程序

1、 
nosem\driver\ nosem.c
驱动源代码

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
	 
#include <mach/regs-gpio.h>
#include <linux/cdev.h>

static int test_major = 0;

MODULE_AUTHOR("Hanson He");
MODULE_LICENSE("Dual BSD/GPL");

#define GLOBALMEM_SIZE	0x1000	/*全局内存最大4K字节*/
unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/


/*
 * Open the device; in fact, there's nothing to do here.
 */
int test_open (struct inode *inode, struct file *filp)
{
	return 0;
}

ssize_t test_read(struct file *file, char __user *buff, size_t count, loff_t *offp)
{
	return 0;
}

ssize_t test_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)
{
	int i;

	unsigned long p =  *offp;
	int ret = 0;

	/*分析和获取有效的写长度*/
	if (p >= GLOBALMEM_SIZE)
		return count ?  - ENXIO: 0;
	if (count > GLOBALMEM_SIZE - p)
		count = GLOBALMEM_SIZE - p;

	/*用户空间->内核空间*/
	  if (copy_from_user(mem + p, buff, count))
	    ret =  - EFAULT;
	  else
	  {
	    *offp += count;
	    ret = count;

	    //printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
	  }
  
	for(i=0;i<count;i++)
	{
		printk("%d",mem[i]);
		msleep(100); //delay 1ms
 	}
	printk("\n");
	return 0;
}

static int test_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	return 0;

}

static int test_release(struct inode *node, struct file *file)
{
	return 0;
}

/*
 * Set up the cdev structure for a device.
 */
static void test_setup_cdev(struct cdev *dev, int minor,
		struct file_operations *fops)
{
	int err, devno = MKDEV(test_major, minor);
    
	cdev_init(dev, fops);
	dev->owner = THIS_MODULE;
	dev->ops = fops;
	err = cdev_add (dev, devno, 1);
	/* Fail gracefully if need be */
	if (err)
		printk (KERN_NOTICE "Error %d adding test%d", err, minor);
}


/*
 * Our various sub-devices.
 */
/* Device 0 uses remap_pfn_range */
static struct file_operations test_remap_ops = {
	.owner   = THIS_MODULE,
	.open    = test_open,
	.release = test_release,
	.read    = test_read,
	.write   = test_write,
	.ioctl   = test_ioctl,	
};

/*
 * There's no need for us to maintain any
 * special housekeeping info, so we just deal with raw cdevs.
 */
static struct cdev TestDevs;

/*
 * Module housekeeping.
 */
static int test_init(void)
{
	int result;
	dev_t dev = MKDEV(test_major, 0);

	/* Figure out our device number. */
	if (test_major)
		result = register_chrdev_region(dev, 1, "nosem");
	else {
		result = alloc_chrdev_region(&dev, 0, 1, "nosem");
		test_major = MAJOR(dev);
	}
	if (result < 0) {
		printk(KERN_WARNING "test: unable to get major %d\n", test_major);
		return result;
	}
	if (test_major == 0)
		test_major = result;

	/* Now set up cdev. */
	test_setup_cdev(&TestDevs, 0, &test_remap_ops);
	printk("test device installed, with major %d\n", test_major);
	return 0;
}


static void test_cleanup(void)
{
	cdev_del(&TestDevs);
	unregister_chrdev_region(MKDEV(test_major, 0), 1);
	printk("test device uninstalled\n");
}


module_init(test_init);
module_exit(test_cleanup); 

2、 
Mafefile
文件

   ifeq ($(KERNELRELEASE),)

#KERNELDIR ?= /your/target/source/directory/
KERNELDIR ?=/home/student/linux-2.6.32.2 
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
    obj-m := nosem.o
endif

 

3、 
nosem\user\ main.c
测试程序

  #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
	int i = 0;
	int dev_fd;
	char wr_buf[60];
	int cnt = 0;
	int input = 0;
	
	if(argc > 1)
	{
		input = atoi(argv[1]);
	}else{
		printf("usage: nosem_test number\n");
		exit(1); 
	}
	dev_fd = open("/dev/nosem",O_RDWR);
	if ( dev_fd == -1 ) {
		printf("Can't open file /dev/nosem\n");
		exit(1);
	}
	memset(wr_buf, input, sizeof(wr_buf));
	/*print out 100 line number, there are 60 one every line*/
	while(1)
	{
		lseek(dev_fd,0,SEEK_SET);
		write(dev_fd,wr_buf,sizeof(wr_buf));		
		cnt ++;
		if(cnt > 100)break;
		usleep(8);
	}
	close(dev_fd);
	return 0;
}

4、 
Makefile
文件

        

 KERNELDIR ?=/home/student/linux-2.6.32.2/include
all: nosem_test

nosem_test : main.c
	#arm-linux-gcc -I$(KERNELDIR) -s -Wl,-warn-common --static -o $@ $^
	arm-linux-gcc -I$(KERNELDIR) -o $@ $^

clean :
	rm nosem_test

 

5、run_nosemtests多个测试

 ./nosem_test 1 &

./nosem_test 2 &

./nosem_test 3 &

 

实例二:带信号量的程序

6、 
\sem\driver\ Sem.c
驱动源代码

  #include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
	 
#include <mach/regs-gpio.h>
#include <linux/cdev.h>

DECLARE_MUTEX(sem); //声明一个互斥体
static int test_major = 0;

MODULE_AUTHOR("Hanson He");
MODULE_LICENSE("Dual BSD/GPL");

#define GLOBALMEM_SIZE	0x1000	/*全局内存最大4K字节*/
unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/

/*
 * Open the device; in fact, there's nothing to do here.
 */
int test_open (struct inode *inode, struct file *filp)
{
	return 0;
}

ssize_t test_read(struct file *file, char __user *buff, size_t count, loff_t *offp)
{
	return 0;
}

ssize_t test_write(struct file *file, const char __user *buff, size_t count, loff_t *offp)
{
	int i;

	unsigned long p =  *offp;
	int ret = 0;

	/*分析和获取有效的写长度*/
	if (p >= GLOBALMEM_SIZE)
		return count ?  - ENXIO: 0;
	if (count > GLOBALMEM_SIZE - p)
		count = GLOBALMEM_SIZE - p;

	if(down_interruptible(&sem))
	{
		return -ERESTARTSYS;
	}

	/*用户空间->内核空间 以下是临界区*/
	  if (copy_from_user(mem + p, buff, count))
	    ret =  - EFAULT;
	  else
	  {
	    *offp += count;
	    ret = count;

	    //printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
	  }
  
	for(i=0;i<count;i++)
	{
		printk("%d",mem[i]);
		msleep(1); //delay 1ms
 	}
	printk("\n");
	up(&sem);
	return 0;
}

static int test_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	return 0;

}

static int test_release(struct inode *node, struct file *file)
{
	return 0;
}

/*
 * Set up the cdev structure for a device.
 */
static void test_setup_cdev(struct cdev *dev, int minor,
		struct file_operations *fops)
{
	int err, devno = MKDEV(test_major, minor);
    
	cdev_init(dev, fops);
	dev->owner = THIS_MODULE;
	dev->ops = fops;
	err = cdev_add (dev, devno, 1);
	/* Fail gracefully if need be */
	if (err)
		printk (KERN_NOTICE "Error %d adding test%d", err, minor);
}


/*
 * Our various sub-devices.
 */
/* Device 0 uses remap_pfn_range */
static struct file_operations test_remap_ops = {
	.owner   = THIS_MODULE,
	.open    = test_open,
	.release = test_release,
	.read    = test_read,
	.write   = test_write,
	.ioctl   = test_ioctl,	
};

/*
 * There's no need for us to maintain any
 * special housekeeping info, so we just deal with raw cdevs.
 */
static struct cdev TestDevs;

/*
 * Module housekeeping.
 */
static int test_init(void)
{
	int result;
	dev_t dev = MKDEV(test_major, 0);
	char dev_name[]="sem";


	/* Figure out our device number. */
	if (test_major)
		result = register_chrdev_region(dev, 1, dev_name);
	else {
		result = alloc_chrdev_region(&dev, 0, 1, dev_name);
		test_major = MAJOR(dev);
	}
	if (result < 0) {
		printk(KERN_WARNING "test: unable to get major %d\n", test_major);
		return result;
	}
	if (test_major == 0)
		test_major = result;

	/* Now set up cdev. */
	test_setup_cdev(&TestDevs, 0, &test_remap_ops);
	printk("test device installed, with major %d\n", test_major);
	printk("The device name is: %s\n", dev_name);

	return 0;
}


static void test_cleanup(void)
{
	cdev_del(&TestDevs);
	unregister_chrdev_region(MKDEV(test_major, 0), 1);
	printk("test device uninstalled\n");
}


module_init(test_init);
module_exit(test_cleanup);
7、	Mafefile文件
   ifeq ($(KERNELRELEASE),)

#KERNELDIR ?= /your/target/source/directory/
KERNELDIR ?=/home/student/linux-2.6.32.2
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
    obj-m := sem.o
endif
8、	sem\use\ Main.c测试程序
   #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char *argv[])
{
	int i = 0;
	int dev_fd;
	char wr_buf[60];
	int cnt = 0;
	int input = 0;

	if(argc > 1)
	{
		input = atoi(argv[1]);
	}else{
		printf("usage: sem_test num\n");
		exit(1);
	}
	dev_fd = open("/dev/sem",O_RDWR);
	if ( dev_fd == -1 ) {
		printf("Cann't open file /dev/sem\n");
		exit(1);
	}
	memset(wr_buf, input, sizeof(wr_buf));
	/*print out 100 line input, there are 60 one every line*/
	while(1)
	{
		lseek(dev_fd, 0, SEEK_SET);
		write(dev_fd,wr_buf,sizeof(wr_buf));
		cnt ++;
		if(cnt > 100)break;
		usleep(8);
	}
	close(dev_fd);
	return 0;
}

9、  Makefile

KERNELDIR ?=/home/student/linux-2.6.32.2/include

all: sem_test

 

sem_test : main.c

       #arm-linux-gcc -I$(KERNELDIR) -s -Wl,-warn-common --static -o $@ $^

       arm-linux-gcc -I$(KERNELDIR) -o $@ $^

 

clean :

10run_semtests多个测试

./sem_test 1 &

./sem_test 2 &

./sem_test 3 &

 

声明:本文非原创,整理自申嵌

 

抱歉!评论已关闭.