实例一:没有信号量的程序
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 :
10、run_semtests多个测试
./sem_test 1 &
./sem_test 2 &
./sem_test 3 &
声明:本文非原创,整理自申嵌

本文详细介绍了如何在Linux内核中实现一个无信号量和带信号量的设备驱动,并通过测试程序验证其功能。通过对比两个实例,展示了信号量在驱动程序中的作用以及如何在用户空间和内核空间之间进行数据传输。

被折叠的 条评论
为什么被折叠?



