Hasen的linux设备驱动开发学习之旅--使用文件私有数据的字符设备驱动

本文介绍了一个基于文件私有数据的字符设备驱动实现案例。通过详细解释核心代码,展示了如何使用Linux内核API来创建和管理字符设备,包括设备注册、文件操作及内存管理等关键步骤。
/**
 * Author:hasen
 * 参考 :《linux设备驱动开发详解》
 * 简介:android小菜鸟的linux
 * 	         设备驱动开发学习之旅
 * 主题:使用文件私有数据的字符设备驱动
 * Date:2014-10-31 
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/error.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>

#define GLOBALMEM_SIZE 0x1000 /*全局变量大小:4KB*/
#define MEM_CLEAR 0x1 /*清零全局内存*/
#define GLOBALMEM_MAJOR 250 /*预设的globalmem的主设备号*/

static int globalmem_major =GLOBALMEM_MAJOR ;
/*globalmem设备结构体*/
struct globalmem_dev {
	struct cdev cdev ; /*cdev结构体*/
	unsigned char mem[GLOBALMEM_SIZE] ; /*全局内存*/
} ;

struct globalmem_dev *globalmem_devp ;/*设备结构体实例*/

/*globalmem设备文件打开函数*/
int globalmem_open(struct inode *inode ,struct file *filp)
{
	/*将设备结构体指针赋值给文件私有数据指针*/
	filp->private_data = globalmem_devp ;
	return 0 ;
}

/*globalmem驱动设备文件释放函数*/
int globalmem_release(struct inode *inode,struct file *filp)
{
	return 0 ;
}

/*globalmem设备驱动模块加载函数*/
int globalmem_init(void)
{
	int result ;
	dev_t devno = MKDEV(globalmem_major ,0) ;
	
	/*申请字符设备驱动区域*/
	if(globalmem_major)
		result = register_chrdev_region(devno,1,"globalmem") ;
	else{
		/*动态获得主设备号*/
		result = alloc_chrdev_region(&devno,0,1,"globalmem") ;
		globalmem_major = MAJOR(devno) ;
	}
	if(result < 0)
		return result ;
	/*动态申请设备结构体的内存*/
	globalmem_devp = kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL) ;
	if(!globalmem_devp){ /*申请失败*/
		result = -ENOMEM ;
		goto fail_malloc ;
	}
	
	memset(globalmem_devp,0,sizeof(struct globalmem_dev)) ;
	
	globalmem_setup_cdev(&globalmem_devp,0) ;
	return 0 ;
fail_malloc :
	unregister_chrdev_region(devno,1) ;
	return result ;
}

/*globalmem设备驱动模块卸载函数*/
void globalmem_exit(void)
{
	cdev_del(&globalmem_devp->cdev) ;/*删除cdev结构*/
	kfree(globalmem_devp) ;
	unregister_chrdev_region(MKDEV(globalmem_major,0),1) ;/*注销设备区域*/
}

/*初始化并添加cdev结构体*/
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
	int err , devno = MKDEV(globalmem_major ,index) ;
	cdev_init(&dev->cdev,&globalmem_fops) ;
	dev->cdev.owner = THIS_MODULE ;
	err = cdev_add(&dev->cdev,devno,1) ;
	if(err)
		printk(KERN_NOTICE "Error %d adding globalmem %d\n",err,index) ;
}

/*globalmem设备驱动文件操作结构体*/
const struct file_operations globalmem_fops = {
	.owner = THIS_MODULE ,
	.llseek = globalmem_llseek ,
	.read = globalmem_read ,
	.write = globalmem_write ,
	.ioctl = globalmem_ioctl ,
	.open = globalmem_open ,
	.release = globalmem_release ,
} ;

/*globalmem设备驱动读函数*/
static ssize_t globalmem_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos )
{
	unsigned long p = *ppos ;
	int ret = 0 ;
	struct globalmem_dev *dev = filp->private_data ;/*获取设备结构体指针*/
	
	/*分析和获取有效的读长度*/
	if(p >= GLOBALMEM_SIZE)/*要读的偏移位置越界*/
		return 0 ;
	if(count > GLOBALMEM_SIZE - p)/*要读的字节数太大*/
		count = GLOBALMEM_SIZE -P ;
	
	/*内核空间 -> 用户空间*/
	if(copy_to_user(buf,(void *)(dev->mem + p),count))
		ret = -EFAULT ;
	else{
		*ppos += count ;
		ret = count ;
		printk(KERN_INFO "read %d bytes from %d\n",count,p) ;	
	}
}

/*globalmem设备驱动写函数*/
static ssize_t globalmem_write(struct file *filp,const char __user buf,size_t count,loff_t *ppos)
{
	unsigned long p = *ppos ; 
	int ret = 0 ;
	struct globalmem_dev *dev = filp->private_data ;/*获取设备结构体指针*/
	
	/*分析和获取有效的写长度*/
	if(p >= GLOBALMEM_SIZE) /*要写的偏移位置越界*/
		return 0 ;
	if(count > GLOBALMEM_SIZE - p ) /*要写的字节数太大*/
		count = GLOBALMEM_SIZE - p ;
	
	/*用户空间 -> 内核空间*/
	if(copy_from_user(dev->mem+p, buf,count))
		ret = -EFAULT ;
	else{
		*ppos += count ;
		ret = count ;
		printk(KERN_INFO "write %d bytes from %d\n",count,p) ;
	}
	return ret ;
}

/*globalmem设备驱动seek()函数*/
static loff_t globalmem_llseek(struct file *filp,loff_t offset,int orig)
{
	loff_t ret ;
	switch(orig){
	case 0: /*从文件开头开始偏移*/
		if(offset <0){
			ret = -EINVAL ;
			break ;
		}
		if((unsigned int)offset >GLOBALMEM_SIZE){
			ret = -EINVAL ;
			break ;
		}
		flip->f_pos += offset ;
		ret = flip->f_pos ;
		break ;
	case 1: /*从文件当前位置开始偏移*/
		if((flip->f_pos + offset) > GLOBALMEM_SIZE ){
			ret = -EINVAL ;
			break ;
		}
		if((flip->f_pos + offset < 0)){
			ret = -EINVAL ;
			break ;
		}
		flip->f_pos += offset ;
		ret = flip->f_pos ;
		break ;
	default:
		return -EINVAL ;
	}
	return ret ;
}

/*globalmem设备驱动的ioctl()函数*/
static int globalmem_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
	struct globalmem_dev *dev = filp->private_data ;/*获取设备结构体指针*/
	switch(cmd){
	case CMD_CLEAR :
		/*清除全局变量*/
		memset(dev->mem,0,GLOBALMEM_SIZE) ;
		printk(KERN_INFO "globalmem is set to zero\n") ;
		break ;
	default:
		return -EINVAL ;/*其他不支持的命令*/
	}
	return 0 ;
}

MODULE_AUTHOR("Hasen<hasen.dc@gmail.com>") ;
MODULE_LICENSE("Dual BSD/GPL") ;

module_param(globalmem_major,int,S_IRUGO) ;

module_init(globalmem_init) ;
module_exit(globalmem_exit) ;

在Python中,逻辑回归是常用的机器学习算法,可用于数据预测和建模。以下是不同场景下的实现示例: ### 非线性逻辑回归建模 当面对非线性数据时,可通过转换数据并训练模型实现非线性逻辑回归。以下代码示例展示了如何将数据转换为最高次项为五次项,然后使用逻辑回归模型进行训练,并输出模型得分: ```python from sklearn.preprocessing import PolynomialFeatures from sklearn import linear_model # 假设x_data和y_data是已经准备好的特征数据和标签数据 # 数据转换,最高次项为五次项 poly_reg = PolynomialFeatures(degree=5) x_poly = poly_reg.fit_transform(x_data) # 定义逻辑回归模型 logistic = linear_model.LogisticRegression() logistic.fit(x_poly, y_data) # 计算模型得分 score = logistic.score(x_poly, y_data) print(score) ``` 上述代码通过`PolynomialFeatures`将数据转换为五次项,使用`LogisticRegression`进行训练并计算得分[^1]。 ### 二分类预测建模 以鸢尾花数据集为例,展示如何使用逻辑回归进行二分类预测。首先将数据集划分为训练集和测试集,然后训练模型并查看模型的权重和截距: ```python from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression import pandas as pd # 假设iris_features和iris_target是鸢尾花数据集的特征和标签 # 选择其类别为0和1的样本 (不包括类别为2的样本) iris_features_part = iris_features.iloc[:100] iris_target_part = iris_target[:100] # 训练集测试集7/3分 x_train, x_test, y_train, y_test = train_test_split(iris_features_part, iris_target_part, test_size = 0.3, random_state = 2020) # 从sklearn中导入逻辑回归模型 clf = LogisticRegression(random_state=0, solver='lbfgs') # 训练模型 clf.fit(x_train, y_train) # 查看其对应的w print('the weight of Logistic Regression:', clf.coef_) # 查看其对应的w0 print('the intercept(w0) of Logistic Regression:', clf.intercept_) ``` 该代码通过`train_test_split`划分数据集,使用`LogisticRegression`训练模型并查看模型参数[^3]。 ### 自定义逻辑回归类实现 以下是一个自定义的逻辑回归类,包含数据转换、模型训练和预测方法: ```python import numpy as np class Logistic: def transform(self, x): # 转换,将逻辑回归得到的概率值转换为实际标签 for i in range(len(x)): if x[i] >= 0.5: x[i] = 1 elif x[i] < 0.5: x[i] = 0 return x def fit(self, x, y, x1, y1): x = np.array(x) x = np.column_stack((np.ones(len(y)), x)) # 向x中插入一行1,表示线性回归中的截距 y = np.array(y) sample, featers = x.shape self.w = np.zeros(featers) # 初始化参数值 self.iters = 2 # 迭代次数,牛顿法迭代次数较低,可以很快的得到最优值 for _ in range(self.iters): y_pre = 1 / (1 + np.power(np.e, -1 * np.dot(x, self.w))) # sigmod公式得到预测值 error = y_pre - y # 损失值 dw = np.dot(error, x) # 一阶导(ypre-y)*x dsigmod = y_pre * (1 - y_pre) * x.T # 对sigmod求导 hasen = np.dot(dsigmod, x) # 海森矩阵 delt = np.linalg.solve(hasen, dw) # 变化量 self.w -= delt if np.linalg.norm(delt) < 1e-6: break def predict(self, x): # 预测 x = np.array(x) x = np.column_stack((np.ones(x.shape[0]), x)) y_pre = 1 / (1 + np.exp(-np.dot(x, self.w))) y_pre = self.transform(y_pre) return y_pre ``` 这个自定义类实现了逻辑回归的核心功能,包括数据转换、训练和预测[^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值