|
小弟最近在写SPI的设备驱动。
我在板文件中添加完spi设备信息后,写好设备驱动,insmod驱动后,成功调用probe函数。我在probe函数里获取struct spi_device *spi之外,同时注册创建了字符设备,并创建了设备节点。
然后我在用户层的测试程序中打开该设备节点文件,write,成功调用驱动里的write函数。我在write函数里完成了spi_transfer, spi_message结构体的创建,调用spi_message_init(), spi_message_add_tail(), 然后spi_sync()。程序运行到spi_sync()时出现段错误。但是如果是在probe里调用write函数,做同样的操作,运行到spi_sync则没有问题。
下面是我的驱动代码和测试程序,以及错误信息。恳请各位兄弟姐妹帮我看看,是不是我少了什么操作还是代码有错误。
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/math64.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/mod_devicetable.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#define CDD_COUNT 1
struct adf4351_devs
{
/*建立字符设备*/
struct cdev cdev;
/*将匹配的spi设备传递进来*/
struct spi_device *spi_dev;
struct device *dev_device;
struct mutex lock;
int data;
};
dev_t dev;
struct adf4351_devs *adf4351_devp = NULL;
struct class *dev_class = NULL;
/*test code*/
#if 1
static int my_write(struct adf4351_devs *devp, loff_t to, size_t len, const char *buf)
{
printk("enter my_write\n");
struct spi_transfer st;
struct spi_message msg;
spi_message_init(&msg);
memset(&st,0,sizeof(st));
st.tx_buf = buf;
st.len = len;
spi_message_add_tail(&st,&msg);
spi_sync(devp->spi_dev,&msg);
printk("exit my_write\n");
return 0;
}
#endif
/*面向用户程序的接口函数*/
ssize_t adf4351_write(struct file *fp,const char __user *buf,
size_t size, loff_t *offset)
{
int i;
struct spi_transfer st[2];
struct spi_message msg;
char buf_write[100];
memset(buf_write,0x7,100);
printk("enter adf4351_write\n");
printk("matched device's name=%s\n",adf4351_devp->spi_dev->modalias);
#if 1
spi_message_init(&msg);
memset(st,0,sizeof(st));
printk("sizeof(st)=%d,sizeof(st[0])=%d\n",sizeof(st),sizeof(st[0]));
st[0].tx_buf = buf;
st[0].len = size;
spi_message_add_tail(&st[0],&msg);
for(i=0;i<size;i++)
printk("st.tx_buf[%d]=%d\n",i,*((char *)st[0].tx_buf+i));
#if 1
// mutex_lock(&(adf4351_devp->lock));
spi_sync(adf4351_devp->spi_dev,&msg);
// mutex_unlock(&(adf4351_devp->lock));
#endif
#endif
// spi_write(adf4351_devp->spi_dev,buf,size);
printk("enter adf4351_device_0 write\n");
return 0;
}
ssize_t adf4351_read(struct file *fp,const char __user *buf,
size_t size, loff_t *offset)
{
printk("enter adf4351_read\n");
int i;
/*定义transfer*/
struct spi_transfer st[2];
/*定义message*/
struct spi_message message;
/*初始化message*/
spi_message_init(&message);
memset(st,0,sizeof(st));
st[0].rx_buf = buf;
st[0].len = size;
/*将st放到message队列的尾部*/
spi_message_add_tail(&st[0],&message);
/*原子锁*/
mutex_lock(&adf4351_devp->lock);
/*将message与spi_device关联,发送message*/
spi_sync(adf4351_devp->spi_dev,&message);
/*将读到的数据打印出来*/
for(i=0;i<size;i++)
printk("0x%02x\n",buf[i]);
/*去锁*/
mutex_unlock(&adf4351_devp->lock);
return 0;
}
struct file_operations adf4351_fops =
{
.owner = THIS_MODULE,
.write = adf4351_write,
.read = adf4351_read,
};
#if 1
static const struct spi_device_id adf4351_idtable[] =
{
{"adf4351_a",1},
// {"adf4351_b",1},
{},
};
MODULE_DEVICE_TABLE(spi, adf4351_idtable);
#endif
static int __devinit adf4351_probe(struct spi_device *spi)
{
int ret=0;
int i;
printk("enter probe\n");
/*首先创建字符设备*/
/*动态申请设备号*/
ret = alloc_chrdev_region(&dev,0,CDD_COUNT,"adf4351");
if(ret<0)
{
printk("apply dev number failed\n");
goto failure_alloc_chrdev_region;
}
/*分配空间*/
adf4351_devp = kzalloc(sizeof(struct adf4351_devs)*CDD_COUNT,GFP_KERNEL);
if(IS_ERR(adf4351_devp))
{
ret = PTR_ERR(adf4351_devp);
printk("kzalloc failed\n");
goto failure_kzalloc;
}
/*创建设备类*/
dev_class = class_create(THIS_MODULE,"adf4351_class");
if(IS_ERR(dev_class))
{
ret = PTR_ERR(dev_class);
printk("class_create failed\n");
goto failure_class_create;
}
/*创建多个设备节点*/
for(i=0;i<CDD_COUNT;i++)
{
/*将匹配的spi device传递进来*/
char buf_test[100];
memset(buf_test,0x7,100);
adf4351_devp[i].spi_dev = spi;
mutex_init(&(adf4351_devp[i].lock));
spi_set_drvdata(spi,adf4351_devp);
/*初始化cdev结构体*/
cdev_init(&(adf4351_devp[i].cdev),&adf4351_fops);
/*添加cdev设备*/
cdev_add(&(adf4351_devp[i].cdev),dev+i,1);
/*动态创建设备节点*/
adf4351_devp[i].dev_device = device_create(dev_class,NULL,dev+i,NULL,"adf4351_device_%d",i);
//*(adf4351_devp[i].dev_device->platform_data) = i;
adf4351_devp[i].data = i;
/*这么调用则没有问题*/
my_write(adf4351_devp,0,20,buf_test);
}
return 0;
failure_class_create:
kfree(adf4351_devp);
failure_kzalloc:
unregister_chrdev_region(dev,CDD_COUNT);
failure_alloc_chrdev_region:
return ret;
}
static int __devexit adf4351_remove(struct spi_device *spi)
{
printk("enter remove\n");
int i;
for(i=0;i<CDD_COUNT;i++)
{
cdev_del(&(adf4351_devp[i].cdev));
device_destroy(dev_class,dev+i);
}
class_destroy(dev_class);
kfree(adf4351_devp);
unregister_chrdev_region(dev,CDD_COUNT);
return 0;
}
/*构建spi_driver*/
static struct spi_driver adf4351_driver =
{
.driver =
{
.name = "adf4351_drv",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = adf4351_probe,
.remove = __devexit_p(adf4351_remove),
.id_table = adf4351_idtable,
};
int __init spi_init()
{
printk("-----------------------\n");
spi_register_driver(&adf4351_driver);
return 0;
}
void __exit spi_exit()
{
printk("............................\n");
spi_unregister_driver(&adf4351_driver);
}
module_init(spi_init);
module_exit(spi_exit);
MODULE_LICENSE("GPL");
用户层的测试程序:
#include <stdio.h>
#include <fcntl.h>
int main()
{
int fd = open("/dev/adf4351_device_0",O_RDWR);
if(fd<0)
{
printf("device node open failed\n");
return -1;
}
printf("enter operation code, 'w'=write,'r'=read\n");
char buf[100];
int i;
for(i=0;i<100;i++)
buf[i]=i;
write(fd,buf,10);
sleep(1);
close(fd);
return 0;
}
|
|