⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spd.c

📁 Linux 2.6.24通过SMBUS总线(也类似于i2c总线)读写内存上的SPD信息。里面包含驱动和测试程序。再PC机上反复测试过
💻 C
字号:
#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/jiffies.h>#include <linux/i2c.h>#include <linux/mutex.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/delay.h>#include <linux/types.h>#include <asm/uaccess_32.h>#define  CREATE_AUTO		1/* Addresses to scan *///static unsigned short normal_i2c[] = { 0xA4,0xA5, I2C_CLIENT_END };static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };/* Insmod parameters */I2C_CLIENT_INSMOD_1(SPD);/* device number */#define SPD_MAJOR			(225)#define SPD_MINOR			(0)/* device node */#define NODE_NAME			("spd")   /* command mode */#define 	SPD_READ		(1)#define 	SPD_WRITE		(0)					/* functon prototype declaration */static int 	spd_attach_adapter(struct i2c_adapter *adapter);static int 	spd_detect(struct i2c_adapter *adapter, int address, int kind);static int 	spd_detach_client(struct i2c_client *client);int  		spd_open(struct inode *inode,struct file *flip);int  		spd_release(struct inode *inode,struct file *filp);int  		spd_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg);int  		spd_command(struct i2c_client *client,unsigned int cmd,void *arg);ssize_t 	spd_read(struct file *filp,unsigned char __user *buf,size_t count,loff_t *f_pos);ssize_t     spd_write(struct file *filp,const unsigned char __user *buf,size_t count,loff_t *f_pos);/* file interface */struct file_operations SPD_fops={	.owner = THIS_MODULE,	.ioctl = spd_ioctl,	.read  = spd_read,	.write = spd_write,	.open = spd_open,	.release = spd_release,};/* device struct */struct spd_dev{	struct cdev cdev;};/* Each client has this additional data */struct spd_data {	struct i2c_client client;	struct mutex update_lock;};/* This is the driver that will be inserted */static struct  i2c_driver spd_driver = {	.driver = {		.name	= "spd",	},	.attach_adapter	= spd_attach_adapter,	.detach_client	= spd_detach_client,	.command		= spd_command,};/* the glogal variable definition */struct spd_dev 		*SPD_cdev = NULL;struct spd_data     *SPD_data = NULL;#ifdef CREATE_AUTOstruct class  		*SPD_class = NULL;struct class_device *SPD_class_device =NULL;#endif/*  the function implement *//* typedef long ssize_t */#define 	COUNT		(1)ssize_t 	spd_read(struct file *filp,unsigned char __user *buf,size_t count,loff_t *f_pos){	struct i2c_client  client;	int i;	unsigned char result;	client = SPD_data->client;#if 0	result = i2c_smbus_read_byte(&client);	if(result<0)	{			printk(KERN_ALERT "    read data failed.\n");		goto out;	}		if(copy_to_user(buf,&result,COUNT))	{		result = -EFAULT;		goto out;	}#else	for(i=0;i<count;i++)	{		result = i2c_smbus_read_byte_data(&client,i);		if(result < 0)		{			printk(KERN_ALERT "    read data failed.\n");			goto out;		}		if(copy_to_user(buf+i,&result,COUNT))		{			result = -EFAULT;			goto out;		}	}#endifout:	return result;}ssize_t     spd_write(struct file *filp,const unsigned char __user *buf,size_t count,loff_t *f_pos){	struct i2c_client client;	unsigned char temp;	client = SPD_data->client;	if(copy_from_user(&temp,buf,COUNT))	{		return -EFAULT;	}	return i2c_smbus_write_byte(&client,temp);}int spd_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg){	struct i2c_adapter *adap;	printk(KERN_ALERT "    ==>sign:%s\n",__FUNCTION__);    adap = SPD_data-> client.adapter;	switch(cmd)	{		case SPD_WRITE:		case SPD_READ:			i2c_clients_command(adap,cmd,arg);				while(1)			{				printk("Just a test!\n");				ssleep(1000);			}		break;		default:-EINVAL;	}	return 0;}int spd_command(struct i2c_client *client,unsigned int cmd,void *arg){	printk(KERN_ALERT "    ==>sign:%s\n",__FUNCTION__);	switch(cmd)	{		case SPD_READ:			return i2c_smbus_read_byte(client);			break;		case SPD_WRITE:			return i2c_smbus_write_byte(client,arg);  //			break;		default: 			return -EINVAL;	}}int spd_open(struct inode *inode, struct file *filp){	struct spd_dev  *dev;	printk(KERN_ALERT "    ==>sign:%s\n",__FUNCTION__);	dev = container_of(inode->i_cdev,struct spd_dev,cdev);	filp -> private_data = dev;	return 0;}int spd_release(struct inode *inode,struct file *filp){	printk(KERN_ALERT "    ==>sign:%s\n",__FUNCTION__);	return 0;}static int spd_attach_adapter(struct i2c_adapter *adapter){	printk(KERN_ALERT "    ==>sign:%s\n",__FUNCTION__);	return i2c_probe(adapter, &addr_data, spd_detect);}/* This function is called by i2c_probe */static int spd_detect(struct i2c_adapter *adapter, int address, int kind){	struct 	i2c_client 		*new_client;	int 	err = 0;	printk(KERN_ALERT "    ==>sign:%s\n",__FUNCTION__);	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA					    | I2C_FUNC_SMBUS_BYTE))		goto exit;	if (!(SPD_data = kzalloc(sizeof(struct spd_data), GFP_KERNEL))) {		err = -ENOMEM;		goto exit;	}	new_client = &SPD_data->client;	i2c_set_clientdata(new_client, SPD_data);	new_client->addr = address;	new_client->adapter = adapter;	new_client->driver = &spd_driver;	new_client->flags = 0;	/* Fill in the remaining client fields */	strlcpy(new_client->name, "spd", I2C_NAME_SIZE);	mutex_init(&SPD_data->update_lock);	/* Tell the I2C layer a new client has arrived */	if ((err = i2c_attach_client(new_client)))		goto exit_kfree;	/* Detect the Vaio nature of EEPROMs.	   We use the "PCG-" or "VGN-" prefix as the signature. */	if (address == 0x57) 	{		char name[4];				name[0] = i2c_smbus_read_byte_data(new_client, 0x80);		name[1] = i2c_smbus_read_byte(new_client);		name[2] = i2c_smbus_read_byte(new_client);		name[3] = i2c_smbus_read_byte(new_client);	}		return 0;exit_kfree:	kfree(SPD_data);exit:	return err;}static int spd_detach_client(struct i2c_client *client){	int err;	printk(KERN_ALERT "    ==>sign:%s\n",__FUNCTION__);/*	sysfs_remove_bin_file(&client->dev.kobj, &spd_attr);*/	err = i2c_detach_client(client);	if (err)		return err;	kfree(i2c_get_clientdata(client));	return 0;}static int __init spd_init(void){	int result;	dev_t dev = 0;		printk(KERN_ALERT "    ==>Welcome to %s fuction.\n",__FUNCTION__);	/* Get the device number */	dev = MKDEV(SPD_MAJOR,SPD_MINOR);	if(SPD_MAJOR)	{		result = register_chrdev_region(dev,1,"SPD");  	// apply the device number to system 	}	else	{		result = alloc_chrdev_region(&dev,0,1,"SPD");	}	if(result )	{		printk(KERN_ALERT "SPD: can't get major %d\n",SPD_MAJOR);		return result;	}		SPD_cdev = kmalloc(sizeof(struct spd_dev),GFP_KERNEL);	if(!SPD_cdev)	{		result = -ENOMEM;		goto out_unregister_device_number;	}	memset(SPD_cdev,0,sizeof(struct spd_dev));	cdev_init(&SPD_cdev->cdev,&SPD_fops);	SPD_cdev->cdev.owner = THIS_MODULE;	SPD_cdev->cdev.ops = &SPD_fops;	result = cdev_add(&SPD_cdev->cdev,dev,1);	if(result)	{		printk(KERN_ALERT "Error %d adding SPD\n",result);		goto out_free_dev;	}	#ifdef CREATE_AUTO	/* creating my own class */	SPD_class = class_create(THIS_MODULE,"SPD");	if(IS_ERR(SPD_class))	{		printk(KERN_ALERT "ERR:failed in creating class.\n");		goto out_del_dev;	}	/* register your own device in sysfs,and this will casue udeved to create corresponding device node */	SPD_class_device = class_device_create(SPD_class,NULL,MKDEV(SPD_MAJOR,SPD_MINOR),NULL, NODE_NAME);	if(IS_ERR(SPD_class_device))	{		printk(KERN_ALERT "ERR:failed in creating class device.\n");		goto out_uncreate_class;	}#endif	/* add the  i2c_driver */	result = i2c_add_driver(&spd_driver);	if(result)	{		printk(KERN_ALERT "ERR:failed in adding i2c_driver.\n");		goto out_uncreate_device;		}	printk(KERN_ALERT "    ==>The %s fuction is OK.\n",__FUNCTION__);	return result;out_uncreate_device:	class_device_destroy(SPD_class,MKDEV(SPD_MAJOR,SPD_MINOR));out_uncreate_class:	class_destroy(SPD_class);out_del_dev:	cdev_del(&SPD_cdev->cdev);out_free_dev:	kfree(SPD_cdev);out_unregister_device_number:	unregister_chrdev_region(dev,1);	return result;}static void __exit spd_exit(void){	printk(KERN_ALERT "    ==>Goodby to  %s fuction.\n",__FUNCTION__);		i2c_del_driver(&spd_driver);#ifdef CREATE_AUTO	class_device_destroy(SPD_class,MKDEV(SPD_MAJOR,SPD_MINOR));	class_destroy(SPD_class);#endif	dev_t devno = MKDEV(SPD_MAJOR,SPD_MINOR);	cdev_del(&SPD_cdev->cdev);	kfree(SPD_cdev);	unregister_chrdev_region(devno,1);}module_init(spd_init);module_exit(spd_exit);MODULE_AUTHOR("Wshenglin <wshenglin@gmail.com>");MODULE_DESCRIPTION("SMBUS EEPROM driver");MODULE_LICENSE("Dual BSD/GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -