m50x(m50星座)

m50x_device.c

#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/interrupt.h>
#include<linux/i2c.h>

static struct i2c_client *m50x_client;
static int i2c_bus_num=1;


static struct i2c_board_info m50x_boardinfo=
{
?? ?I2C_BOARD_INFO("m50x",0x50),
?? ?.platform_data = &i2c_bus_num,
};

static int __init ?m50x_dev_init(void)
{
?? ?struct i2c_adapter ?*adapter;
?? ?int ret=0;

?? ?//get i2c adapter
?? ?adapter = i2c_get_adapter(*((int *)m50x_boardinfo.platform_data));
?? ?if(NULL == adapter)
?? ?{
?? ??? ?printk("failed to get adapter

");
?? ??? ?return -ENODEV;
?? ?}

?? ?//register i2c device
?? ?m50x_client = i2c_new_device(adapter,&m50x_boardinfo);
??? ?if(NULL == m50x_client)
?? ?{
?? ??? ?printk("failed to register i2c device

");
?? ??? ?ret = -EINVAL;
?? ??? ?goto err_add_device;
?? ?}?
?? ?m50x_client->adapter=adapter;
?? ?return 0;
err_add_device:
?? ?i2c_put_adapter(adapter);
?? ?return ret;
}


static void __exit m50x_dev_exit(void)
{
?? ?//unregister i2c device
?? ?i2c_unregister_device(m50x_client);
?? ?//release i2c adapater
?? ?i2c_put_adapter(m50x_client->adapter);
}


module_init(m50x_dev_init);
module_exit(m50x_dev_exit);

MODULE_AUTHOR("TOMMY");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("PERSONAL");
?

?

?

?

?

?

?

?

?

?

?

?

?

?

m50x_driver.c

?

/****************
*******author:tommy
*******time:2018-11-25 m50x
*******description:此驱动是某公司
*******的PSAM卡的I2C驱动
************************/

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/i2c.h>
#include<linux/interrupt.h>
#include<linux/bcd.h>
#include<linux/workqueue.h>
#include<linux/slab.h>
#include<linux/types.h>
#include<linux/device.h>


#define BUF_SIZE ? 256
static dev_t dev_id;?? ??? ??? ?//设备号
static struct class *card_class;//设备类

struct m50x
{
?? ?struct cdev cdev;?? ??? ??? ?//字符设备
?? ?struct i2c_client *client;?? ?//I2C外设结构体,从机
?? ?struct semaphore sem;?? ??? ?//并发控制用的信号量
?? ?wait_queue_head_t r_wq;?? ??? ?//读等待队列
?? ?wait_queue_head_t w_wq;?? ??? ?//写等待队列
?? ?unsigned char buf[BUF_SIZE];//缓冲区
?? ?unsigned char flag; ? ? ? ?? ?//读写标志
};

static ssize_t m50x_read(struct file *file,char _user *buf,size_t count,loff_t *ofs)
{
?? ?struct m50x *chip = file->private_data;//通过私有数据获得
?? ?int ret=0;
?? ?
?? ?if(down_interruptible(&chip->sem))//若返回值非0,获取信号量失败,说明临界资源已经被占用
?? ?{
?? ??? ?return -EAGAIN;
?? ?}
?? ?if(!chip->flag)//若不可读
?? ?{
?? ??? ?up(&chip->sem);//释放信号量
?? ??? ?//应用空间若以非阻塞方式访问,则返回错误
?? ??? ?if(file->f_flags & NONBLOCK)
?? ??? ?{
?? ??? ??? ?return -EAGAIN;?? ?
?? ??? ?}
?? ??? ?else//若以阻塞方式访问内核空间
?? ??? ?{
?? ??? ??? ?//将读等待队列挂起,进入睡眠
?? ??? ??? ?if(wait_event_interruptible(chip->r_wq,chip->flag))
?? ??? ??? ?{
?? ??? ??? ??? ?return -ERESTARTSYS;?? ?
?? ??? ??? ?}
?? ??? ??? ?//若获取信号量失败
?? ??? ??? ?if(down_interruptible(&chip->sem))
?? ??? ??? ?{
?? ??? ??? ??? ?return -ERESTARTSYS;?? ?
?? ??? ??? ?}
?? ??? ?}?? ?
?? ?}
?? ?
?? ?if(count > BUF_SIZE)
?? ??? ?count=BUF_SIZE;
?? ?//ret为I2C主控器接收从机的数据长度(字节数)?? ?
?? ?ret=i2c_master_recv(chip->client,chip->buf,count);
?? ?if(ret > 0)
?? ?{
?? ??? ?//若拷贝数据到用户空间失败
?? ??? ?if(copy_to_user(buf,chip->buf,count))
?? ??? ?{
?? ??? ??? ?up(&chip->sem);//释放信号量
?? ??? ??? ?return -EFAULT;?? ?
?? ??? ?}?? ?
?? ??? ?else
?? ??? ?{
?? ??? ??? ?chip->flag=0;//置为可写标志
?? ??? ??? ?wake_up_interruptible(&chip->w_wq);//唤醒写等待队列?? ?
?? ??? ?}
?? ?}
?? ?
?? ?up(&chip->sem);
?? ?return ret ? count : -1;
}

static int m50x_write(struct file *file,char _user *buf,size_t count,loff_t *ops)
{
?? ?struct m50x *chip=file->private_data;
?? ?int ret=0;
?? ?
?? ?if(down_interruptible(&chip->sem))
?? ?{
?? ??? ?return -ERESTARTSYS;?? ?
?? ?}
?? ?
?? ?if(chip->flag)//不可写
?? ?{
?? ??? ?up(&chip->sem);//释放信号量
?? ??? ?if(file->f_flags & NONBLOCK)
?? ??? ?{
?? ??? ??? ?return -EAGAIN;
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?//让写等待队列进入睡眠
?? ??? ??? ?if(wait_event_interruptible(chip->w_wq,chip->flag == 0))
?? ??? ??? ?{
?? ??? ??? ??? ?return -ERESTARTSYS;?? ?
?? ??? ??? ?}?? ?
?? ??? ??? ?if(down_interruptible(&chip->sem))//获取信号量
?? ??? ??? ?{
?? ??? ??? ??? ?return -ERESTARTSYS;?? ?
?? ??? ??? ?}
?? ??? ?}?? ?
?? ?}
?? ?
?? ?if(count > BUF_SIZE)
?? ?{
?? ??? ?count = BUF_SIZE;?? ?
?? ?}
?? ?
?? ?if(copy_from_user(chip->buf,buf,count))
?? ?{
?? ??? ?up(&chip->sem);
?? ??? ?return -EFAULT;
?? ?}
?? ?else
?? ?{
?? ??? ?//ret为I2C主控器向从机发送的数据长度(字节数)
?? ??? ?ret=i2c_master_send(chip->client,chip->buf,count);
?? ??? ?if(ret)
?? ??? ?{
?? ??? ??? ?chip->flag=1;//可读?? ?
?? ??? ??? ?wake_up_interruptible(&chip->r_wq);
?? ??? ?}?? ?
?? ?}
?? ?up(&chip->sem);
?? ?
?? ?return ret ? count:-1
?? ?
}

static unsigned int m50x_poll(struct file *file,struct poll_table_struct *wait)
{
?? ?struct m50x *chip;
?? ?unsigned int mask =0;
?? ?int ret=0;
?? ?
?? ?if(down_interruptible(&chip->sem))
?? ?{
?? ??? ?return -ERESTERSYS;?? ?
?? ?}
?? ?
?? ?poll_wait(file,&chip->r_wq,wait);
?? ?poll_wait(file,&chip->w_wq,wait);
?? ?
?? ?if(chip->flag)//可读
?? ?{
?? ??? ?mask |=POLLIN | POLLRDNORM;?? ?
?? ?}
?? ?else//可写
?? ?{
?? ??? ?mask |= POLLOUT | POLLWRNORM;?? ?
?? ?}
?? ?up(&chip->sem);
?? ?
?? ?return mask;
}

static int m50x_open(struct inode *inode,struct file *file)
{
?? ?struct m50x *chip = container_of(inode->i_cdev,struct m50x,cdev);
?? ?
?? ?file->private_data = chip;
?? ?//初始化等待队列
?? ?init_waitqueue_head(&chip->r_wq);
?? ?init_waitqueue_head(&chip->w_wq);
?? ?
?? ?memset(chip->buf,0,BUF_SIZE);
?? ?chip->flag=0;
?? ?
?? ?return 0;
}

static int m50x_release(struct inode *inode,struct file *file)
{
?? ?return 0;
}

static const struct file_operations m50x_fops=
?? ?.owner?? ?=?? ?THIS_MODULE,
?? ?.read?? ?=?? ?m50x_read,
?? ?.write?? ?=?? ?m50x_write,
?? ?.poll?? ?=?? ?m50x_poll,
?? ?.release=?? ?m50x_release,?? ?
};


static int m50x_probe(struct ?i2c_client *client,const struct i2c_device_id *id)
{
?? ?struct m50x *chip;
?? ?int ret=0;
?? ?//申请设备结构体的动态内存空间
?? ?chip=kzalloc(sizeof(struct m50x),GFP_KERNEL);
?? ?if(!chip)
?? ?{
?? ??? ?return -ENOMH;
?? ??? ?goto alloc_err;?? ?
?? ?}
?? ?
?? ?//把m50x结构体数据作为I2C从设备的私有数据,便于以后调用
?? ?i2c_set_clientdata(client,chip);
?? ?
?? ?//对chip结构体变量的成员进行初始化
?? ?chip->client = client;
?? ?sema_init(&chip->sem,1);//初始化信号量,必须在注册前初始化,以免产生竞态
?? ?
?? ?//动态申请设备号,让内核自动分配设备号
?? ?ret = alloc_chrdev_region(&dev_id,0,1,DEVICE_NAME);
?? ?if(ret)
?? ?{
?? ??? ?printk("allocate dev id failed!

");
?? ??? ?goto alloc_dev_id_err;?? ?
?? ?}
?? ?//字符设备初始化,将字符设备成员与函数操作集进行绑定
?? ?cdev_init(&chip->cdev,&m50x_fops);
?? ?chip->cdev.owner=THIS_MODULE;
?? ?//完成设备注册,将设备与设备号绑定
?? ?ret=cdev_add(&chip->cdev,dev_id,1);
?? ?if(ret)
?? ?{
?? ??? ?printk("cdev add err!

");
?? ??? ?goto cdev_add_err;?? ?
?? ?}
?? ?//创建一个类,存放在sysfs目录下,sysfs/class/
?? ?card_class=class_create(THIS_MODULE,DEVICE_NAME);
?? ?if(NULL==card_class)
?? ?{
?? ??? ?printk("class create failed!

");
?? ??? ?ret=-EBUSY;
?? ??? ?goto class_err;?? ?
?? ?}
?? ?//创建设备节点成功,存放在/dev/目录下
?? ?device_create(card_class,NULL,dev_id,NULL,DEVICE_NAME);
?? ?printk(DEVICE_NAME" initalized!

");
?? ?
?? ?return(0);
?? ?
alloc_err:
?? ?return(ret);
alloc_dev_id_err:
?? ?kfree(chip);
cdev_add_err:
?? ?unregister_chrdev_region(dev_id,1);
class_err:
?? ?cdev_del(&chip->cdev);
?? ??? ?
}

static int m50x_remove(struct i2c_client *client,const struct i2c_device_id *id)
{
?? ?struct m50x *chip = i2c_get_clientdata(client);?? ?//获得外设的数据
?? ?device_destroy(card_class,dev_id);?? ??? ??? ??? ?//将设备号从设备类中删除
?? ?class_destroy(card_class);?? ??? ??? ??? ??? ??? ?//删除设备类
?? ?cdev_del(&chip->cdev);?? ??? ??? ??? ??? ??? ??? ?//删除字符设备
?? ?unregister_chrdev_region(dev_id,1);?? ??? ??? ??? ?//注销设备号
?? ?kfree(chip);?? ??? ??? ??? ??? ??? ??? ??? ??? ?//释放动态内存
?? ?printk(DEVICE_NAME" destroyed!");
?? ?return 0;?? ?
}

static const struct i2c_device_id m50x_id[]=
{
?? ?{"m50x",0},?? ?
?? ?{}
};
MODULE_DEVICE_TABLE(i2c,m50x_id);


static struct i2c_driver ? m50x_driver=
{
?? ?.driver=
?? ?{
?? ??? ?.name = "m50x_card",
?? ??? ?.owner=THIS_MODULE,

?? ?},
?? ?.probe=m50x_probe,
?? ?.remove=m50x_remove,
?? ?.id_table=m50x_id,

};
//入口函数
static __init ?int m50x_drv_init(void)
{

?? ?return i2c_add_driver(&m50x_driver);
}
//出口函数
static __exit ?void m50x_drv_exit(void)
{

?? ?i2c_del_driver(&m50x_driver);
}


module_init(m50x_drv_init);
module_init(m50x_drv_exit);

MODULE_AUTHOR("TOMMY");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("LINUX_WORKER");

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

makefile

?

转载请说明出处 内容投诉内容投诉
九幽软件 » m50x(m50星座)