宋宝华 《Linux设备驱动开发详解》之基本字符设备驱动misc版本

将普通字符设备驱动改造成misc设备,misc设备没有字符设备那么麻烦,以后自己写的驱动尽量用misc设备来代替
scull.c
 
 
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/gfp.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>

#define SCULL_NAME	"scull"
#define MAX_DATA	0x1000

struct scull_dev {
	struct miscdevice misc_scull;
	char data[MAX_DATA];
	struct semaphore sem;
};

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("BG2BKK");

struct	scull_dev *scull_devp;

int	scull_open(struct inode *inode, struct file *filp)
{
	printk(KERN_ALERT "open the scull device\n");
	return 0;
}

int	scull_release(struct inode *inode, struct file *filp)
{
	printk(KERN_ALERT "close the scull device\n");
	return 0;
}

ssize_t	scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_ops)
{
	unsigned long	p = *f_ops;
	unsigned int	cnt = count;
	int ret = 0;
	if(down_interruptible(&scull_devp->sem))
		return -ERESTARTSYS;

	if(copy_to_user(buf, scull_devp->data,cnt)){
		ret = -EFAULT;
	} else {
		*f_ops += cnt;
		ret = cnt;
		printk(KERN_ALERT "read %u bytes from %lu\n",cnt, p);
	}
	up(&scull_devp->sem);
	printk(KERN_ALERT "read %d bytes\n",count);
	return ret;
}

ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)
{
	unsigned long p = *f_ops;
	unsigned int cnt = count;
	int ret = 0;
	if(down_interruptible(&scull_devp->sem))
		return -ERESTARTSYS;

	if(copy_from_user(scull_devp->data,buf, cnt))
		ret = -EFAULT;
	else {
		*f_ops += cnt;
		ret = cnt;
		printk(KERN_ALERT "written %u bytes from %lu\n",cnt, p);
	}
	up(&scull_devp->sem);
	printk(KERN_ALERT "write %d bytes\n",count);
	return ret;
}

struct	file_operations scull_fops = {
	.owner	=	THIS_MODULE,
	.open	=	scull_open,
	.release=	scull_release,
	.write	=	scull_write,
	.read	=	scull_read,
};


int	scull_init(void)
{
	int result;
	
	scull_devp = kmalloc(sizeof(struct scull_dev), GFP_KERNEL);
	if(!scull_devp){
		printk(KERN_ALERT "fialed to malloc a device\n");
		result = -ENOMEM;
		goto fail_malloc;
	}
	memset(scull_devp, 0 , sizeof(struct scull_dev));

	scull_devp->misc_scull.name	=	SCULL_NAME;
	scull_devp->misc_scull.minor	=	MISC_DYNAMIC_MINOR;
	scull_devp->misc_scull.fops	=	&scull_fops;
	
	result = misc_register(&scull_devp->misc_scull);
	if(result){
		printk(KERN_ALERT "failed to register a misc device\n");
		result = -1;
		goto fail_register;
	}
	init_MUTEX(&scull_devp->sem);

	printk(KERN_ALERT "init scull device\n");
	return 0;
fail_register:
	kfree(scull_devp);
	scull_devp = NULL;
fail_malloc:
	return result;
}

void	scull_cleanup(void)
{
	misc_deregister(&scull_devp->misc_scull);
	kfree(scull_devp);
	scull_devp = NULL;
	printk(KERN_ALERT "clean scull device\n");	
}

module_init(scull_init);
module_exit(scull_cleanup);

测试代码

test.c

/*************************************************************************
 *fileName:    test.c
 *description: test the myscull.c
 *author:      Hzc
 *create time: 2007-04-20
 *modify info: -
*************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>

/* device path */
char path[] = "/dev/scull";
char buf[10];
char rbuf[10];
int i;
int t = 1;
int
main ()
{
  int f = open (path, O_RDWR);
 
  for (i = 0; i < 10; i++)
    {
      buf[i] = i;
      printf("buf[%d] = %d\n",i,buf[i]);
    }

	printf("write %d bytes\n",write (f, buf, 10));	
//  close (f);
//
//
//  f = open (path, O_RDONLY);
// if (f == -1)
//    {
//      printf ("device open error 2!\n");
//      return 1;
//    }


  printf ("Read the string from device...\n");

	printf("read %d bytes\n",read (f, rbuf, 10));	
  for (i = 0; i < 10; i++)
    {
      printf ("%d\n", rbuf[i]);
    }


  close (f);
}

Makefile

#KERNEL_DIR := /home/huang/linux-2.6.18/
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
PWD	:= $(shell pwd)

obj-m := scull.o
default:
	$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules

test: test.c
	gcc $< -o [email protected]  -g

clean:
	rm -rf *.o *.ko *~ *.order *.symvers *.markers *.mod.c
测试脚本

1 load_scull.sh

#!/bin/sh

/sbin/insmod scull.ko

2 unload_scull.sh

#!/bin/sh

/sbin/rmmod scull.ko


3 test.sh

#!/bin/sh
make clean
make 
make test
sudo ./unload_scull
sudo ./load_scull


sudo ./test.o


你可能感兴趣的:(宋宝华 《Linux设备驱动开发详解》之基本字符设备驱动misc版本)