《Linux设备驱动程序》第三版 scull编译 Ubuntu18.04
作者:互联网
0 准备工作。
0.0 系统环境:Ubuntu18.04.1 amd64。
0.1 安装必要软件包
1 |
sudo apt install build-essential bison flex libssl-dev libelf-dev
|
1 下载内核源码,构建源码树
1 2 3 4 5 6 7 8 9 10 11 12 |
sudo apt install linux- source -4.15.0 -y
cd /usr/src/linux-source-4 .15.0/
sudo tar xf linux- source -4.15.0. tar .bz2
cd linux- source -4.15.0/
sudo make oldconfig
sudo make prepare
sudo make scripts
|
2 编译驱动源码
源码需要改动几处:
copy_to_user()改为raw_copy_to_user();
copy_from_user()改为raw_copy_from_user();
init_MUTEX((&scull_device->sem);改为sema_init(&scull_device->sem, 1);
1 2 3 4 5 |
make
sudo insmod scull.ko
sudo rmmod scull.ko
|
附1:scull.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include "scull.h"
int scull_major = SCULL_MAJOR;
int scull_minor = 0;
module_param(scull_major, int , S_IRUGO);
module_param(scull_minor, int , S_IRUGO);
struct scull_dev *scull_device;
int scull_trim( struct scull_dev *dev)
{
if (dev)
{
if (dev->data)
{
kfree(dev->data);
}
dev->data = NULL;
dev->size = 0;
}
return 0;
}
int scull_open( struct inode *inode, struct file *filp)
{
struct scull_dev *dev;
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev;
if ((filp->f_flags & O_ACCMODE) == O_WRONLY)
{
if (down_interruptible(&dev->sem))
{
return -ERESTARTSYS;
}
scull_trim(dev);
up(&dev->sem);
}
return 0;
}
int scull_release( struct inode *inode, struct file *filp)
{
return 0;
}
ssize_t scull_read( struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct scull_dev *dev = filp->private_data;
ssize_t retval = 0;
if (down_interruptible(&dev->sem))
{
return -ERESTARTSYS;
}
if (*f_pos >= dev->size)
{
goto out;
}
if (*f_pos + count > dev->size)
{
count = dev->size - *f_pos;
}
if (!dev->data)
{
goto out;
}
if (raw_copy_to_user(buf, dev->data + *f_pos, count))
{
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
out:
up(&dev->sem);
return retval;
}
ssize_t scull_write( struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
struct scull_dev *dev = filp->private_data;
ssize_t retval = -ENOMEM;
if (down_interruptible(&dev->sem))
{
return -ERESTARTSYS;
}
if (!dev->data)
{
dev->data = kmalloc(SCULL_BUFFER_SIZE, GFP_KERNEL);
if (!dev->data)
{
goto out;
}
memset (dev->data, 0, SCULL_BUFFER_SIZE);
}
if (count > SCULL_BUFFER_SIZE - dev->size)
{
count = SCULL_BUFFER_SIZE - dev->size;
}
if (raw_copy_from_user(dev->data + dev->size, buf, count))
{
retval = -EFAULT;
goto out;
}
dev->size += count;
retval = count;
out:
up(&dev->sem);
return retval;
}
loff_t scull_llseek( struct file *filp, loff_t off, int whence)
{
struct scull_dev *dev = filp->private_data;
loff_t newpos;
switch (whence)
{
case 0:
newpos = off;
break ;
case 1:
newpos = filp->f_pos + off;
break ;
case 2:
newpos = dev->size + off;
break ;
default :
return -EINVAL;
}
if (newpos < 0)
{
return -EINVAL;
}
filp->f_pos = newpos;
return newpos;
}
struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.open = scull_open,
.release = scull_release,
};
void scull_cleanup_module( void )
{
dev_t devno = MKDEV(scull_major, scull_minor);
if (scull_device)
{
scull_trim(scull_device);
cdev_del(&scull_device->cdev);
kfree(scull_device);
}
unregister_chrdev_region(devno, 1);
}
static void scull_setup_cdev( struct scull_dev *dev)
{
int err, devno = MKDEV(scull_major, scull_minor);
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_fops;
err = cdev_add(&dev->cdev, devno, 1);
if (err)
{
printk(KERN_NOTICE "Error %d adding scull" , err);
}
}
static int __init scull_init_module( void )
{
int result;
dev_t dev = 0;
if (scull_major)
{
dev = MKDEV(scull_major, scull_minor);
result = register_chrdev_region(dev, 1, "scull" );
}
else
{
result = alloc_chrdev_region(&dev, scull_minor, 1, "scull" );
scull_major = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "scull: can't get major %d\n" , scull_major);
return result;
}
scull_device = kmalloc( sizeof ( struct scull_dev), GFP_KERNEL);
if (!scull_device)
{
result = -ENOMEM;
goto fail;
}
memset (scull_device, 0, sizeof ( struct scull_dev));
sema_init(&scull_device->sem, 1);
scull_setup_cdev(scull_device);
return 0;
fail:
scull_cleanup_module();
return result;
}
module_init(scull_init_module);
module_exit(scull_cleanup_module);
MODULE_LICENSE( "GPL" );
|
附2:scull.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#ifndef _SCULL_H
#define _SCULL_H
#define SCULL_MAJOR 0
#define SCULL_BUFFER_SIZE PAGE_SIZE
struct scull_dev {
char *data;
unsigned long size;
struct semaphore sem;
struct cdev cdev;
};
#endif
|
附3:Makefile
1 2 3 4 5 6 7 8 9 10 |
#sample driver module
obj-m := scull.o
KDIR = /root/linux-2 .6.36.4/
PWD:=$(shell pwd )
INSTALLDIR=$(PWD)
modules:
$(MAKE) -C /lib/modules/ ` uname -r` /build M=` pwd ` modules
clean:
rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions
.PHONY:modules clean
|
标签:return,struct,dev,cdev,Linux,Ubuntu18.04,data,scull,驱动程序 来源: https://www.cnblogs.com/jiangzhaowei/p/11074142.html