二 spi 子系统(spidev.c)

来源:互联网 发布:淘宝京东天猫哪个便宜 编辑:程序博客网 时间:2024/06/05 11:38

一.spidev.c文件

看一个设备驱动的方法:

概览下重要的结构体spidev_data及全局变量device_list,bufsiz,SPIDEV_MAJOR...

module_init标识的入口初始化函数spidev_init,(module_exit标识的出口函数)

设备与设备驱动匹配时候调用的probe方法spidev_probe

设备驱动的操作函数集file_operations--->spidev_fops

先看open方法spidev_open

接着看读写方法spidev_read & spidev_write

再接着看ioctl方法-->spidev_ioctl

再看其他剩余的方法

#include <linux/init.h>#include <linux/module.h>#include <linux/ioctl.h>#include <linux/fs.h>#include <linux/device.h>#include <linux/err.h>#include <linux/list.h>#include <linux/errno.h>#include <linux/mutex.h>#include <linux/slab.h>#include <linux/spi/spi.h>#include <linux/spi/spidev.h>#include <asm/uaccess.h>#define SPIDEV_MAJOR153//spidev主设备号#define N_SPI_MINORS32/* ... up to 256 */static DECLARE_BITMAP(minors, N_SPI_MINORS);//声明次设备位图#define SPI_MODE_MASK (SPI_CPHA|SPI_CPOL|SPI_CS_HIGH|SPI_LSB_FIRST|SPI_3WIRE|SPI_LOOP|SPI_NO_CS|SPI_READY)struct spidev_data {dev_tdevt;//设备号spinlock_tspi_lock;//自旋锁struct spi_device*spi;//spi设备结构体struct list_headdevice_entry;struct mutexbuf_lock;//互斥锁unsignedusers;//使用者计数u8*buffer;//缓冲区};static LIST_HEAD(device_list);//声明spi设备链表static DEFINE_MUTEX(device_list_lock);//定义互斥锁static unsigned bufsiz = 4096;//最大传输缓冲区大小module_param(bufsiz, uint, S_IRUGO);MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");static void spidev_complete(void *arg){complete(arg);//调用complete}static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message){DECLARE_COMPLETION_ONSTACK(done);int status;message->complete = spidev_complete;//设置spi消息的complete方法 回调函数message->context = &done;spin_lock_irq(&spidev->spi_lock);if (spidev->spi == NULL)//判断是否有指定对应的spi设备status = -ESHUTDOWN;elsestatus = spi_async(spidev->spi, message);//spi异步同步spin_unlock_irq(&spidev->spi_lock);if (status == 0) {wait_for_completion(&done);//等待传输完成status = message->status;//获取spi消息传输事务状态if (status == 0)status = message->actual_length;//status等于传输的实际长度}return status;//返回实际传输长度}static inline ssize_t spidev_sync_write(struct spidev_data *spidev, size_t len){struct spi_transfert = {.tx_buf= spidev->buffer,//发送缓冲区.len= len,//发送数据长度};struct spi_messagem;spi_message_init(&m);//初始化spi消息(初始化spi传递事务队列)spi_message_add_tail(&t, &m);//添加spr传递到该队列return spidev_sync(spidev, &m);//同步读写}static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len){struct spi_transfert = {.rx_buf= spidev->buffer,//接收缓冲区.len= len,//接收数据长度};struct spi_messagem;spi_message_init(&m);//初始化spi消息(初始化spi传递事务队列)spi_message_add_tail(&t, &m);//添加spr传递到该队列return spidev_sync(spidev, &m);//同步读写}static ssize_t spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){struct spidev_data*spidev;ssize_tstatus = 0;if (count > bufsiz)//传输数据大于缓冲区容量return -EMSGSIZE;spidev = filp->private_data;//从文件私有数据指针获取spidev_datamutex_lock(&spidev->buf_lock);//上互斥锁status = spidev_sync_read(spidev, count);//同步读,返回传输数据长度if (status > 0) {unsigned longmissing;//丢失的数据个数missing = copy_to_user(buf, spidev->buffer, status);//内核空间复制到用户空间if (missing == status)//丢失的数据个数等于要传输的数据个数status = -EFAULT;elsestatus = status - missing;//传输成功的数据个数}mutex_unlock(&spidev->buf_lock);//解互斥锁return status;//返回读取成功的数据个数}static ssize_t spidev_write(struct file *filp, const char __user *buf,size_t count, loff_t *f_pos){struct spidev_data*spidev;ssize_tstatus = 0;unsigned longmissing;if (count > bufsiz)//传输数据大于缓冲区容量return -EMSGSIZE;spidev = filp->private_data;//从文件私有数据指针获取spidev_datamutex_lock(&spidev->buf_lock);//上互斥锁missing = copy_from_user(spidev->buffer, buf, count);//用户空间复制到内核空间if (missing == 0) {//传输失败个数为0status = spidev_sync_write(spidev, count);//同步写,返回传输数据长度} elsestatus = -EFAULT;mutex_unlock(&spidev->buf_lock);//解互斥锁return status;//返回写数据的实际个数}static int spidev_message(struct spidev_data *spidev,struct spi_ioc_transfer *u_xfers, unsigned n_xfers){struct spi_messagemsg;struct spi_transfer*k_xfers;struct spi_transfer*k_tmp;struct spi_ioc_transfer *u_tmp;unsignedn, total;u8*buf;intstatus = -EFAULT;spi_message_init(&msg);//初始化spi消息(初始化spi传递事务队列)k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);//分配spi传输指针内存if (k_xfers == NULL)return -ENOMEM;buf = spidev->buffer;//获取spidev_data的缓冲区total = 0;//n=xfers为spi_ioc_transfer个数,u_tmp = u_xfers为要处理的spi_ioc_transfer指针for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;n;n--, k_tmp++, u_tmp++) {k_tmp->len = u_tmp->len;//设置传输信息的长度total += k_tmp->len;//累加传输信息的总长度if (total > bufsiz) {//信息量超过bufsiz缓冲区最大容量status = -EMSGSIZE;goto done;}if (u_tmp->rx_buf) {//接收缓冲区指针不为空k_tmp->rx_buf = buf;//缓冲区指向bufif (!access_ok(VERIFY_WRITE, (u8 __user *)(uintptr_t) u_tmp->rx_buf,u_tmp->len))goto done;}if (u_tmp->tx_buf) {//发送缓冲区指针不为空k_tmp->tx_buf = buf;//缓冲区指针指向bufif (copy_from_user(buf, (const u8 __user *)(uintptr_t) u_tmp->tx_buf,u_tmp->len))//用户空间复制数据到bufgoto done;}buf += k_tmp->len;//缓冲区指针移动一个传输信息的长度k_tmp->cs_change = !!u_tmp->cs_change;//设置cs_changek_tmp->bits_per_word = u_tmp->bits_per_word;//设置bits_per_word 一个字多少位k_tmp->delay_usecs = u_tmp->delay_usecs;//设置delay_usecs 毫秒级延时k_tmp->speed_hz = u_tmp->speed_hz;//设置speed_hz 速率#ifdef VERBOSEdev_dbg(&spidev->spi->dev,"  xfer len %zd %s%s%s%dbits %u usec %uHz\n",u_tmp->len,u_tmp->rx_buf ? "rx " : "",u_tmp->tx_buf ? "tx " : "",u_tmp->cs_change ? "cs " : "",u_tmp->bits_per_word ? : spidev->spi->bits_per_word,u_tmp->delay_usecs,u_tmp->speed_hz ? : spidev->spi->max_speed_hz);#endifspi_message_add_tail(k_tmp, &msg);//添加spr传递到该队列}//for循环的作用是将spi_ioc_transfer批量转换为spi传递结构体spi_transfer,然后添加进spi传递事务队列status = spidev_sync(spidev, &msg);//同步读写if (status < 0)goto done;buf = spidev->buffer;//获取spidev_data缓冲区指针for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {//批量从内核空间复制spi_ioc_transfer到用户空间if (u_tmp->rx_buf) {//判断是否存在接收缓冲区if (__copy_to_user((u8 __user *)(uintptr_t) u_tmp->rx_buf, buf,u_tmp->len)) {status = -EFAULT;goto done;}}buf += u_tmp->len;//buf指针位置调整指向下一个spi_ioc_transfer}status = total;//status等于实际传输的数据长度done:kfree(k_xfers);//释放k_xfersreturn status;//返回实际传输的数据长度}static long spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){interr = 0;intretval = 0;struct spidev_data*spidev;struct spi_device*spi;u32tmp;unsignedn_ioc;struct spi_ioc_transfer*ioc;if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)//判断控制命令的类型return -ENOTTY;if (_IOC_DIR(cmd) & _IOC_READ)//判断控制命令的方向是否为读readerr = !access_ok(VERIFY_WRITE,(void __user *)arg, _IOC_SIZE(cmd));//判断传输数据大小if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)//判断控制命令的方向是否为写writeerr = !access_ok(VERIFY_READ,(void __user *)arg, _IOC_SIZE(cmd));//判断传输数据大小if (err)return -EFAULT;spidev = filp->private_data;//从文件私有数据中获取spidev_dataspin_lock_irq(&spidev->spi_lock);//上自旋锁spi = spi_dev_get(spidev->spi);//获取spi设备spin_unlock_irq(&spidev->spi_lock);//解自旋锁if (spi == NULL)//获取spi设备失败return -ESHUTDOWN;//则返回错误mutex_lock(&spidev->buf_lock);//上互斥锁switch (cmd) {case SPI_IOC_RD_MODE://设置spi读模式retval = __put_user(spi->mode & SPI_MODE_MASK,(__u8 __user *)arg);break;case SPI_IOC_RD_LSB_FIRST://设置spi读最低有效位retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,(__u8 __user *)arg);break;case SPI_IOC_RD_BITS_PER_WORD://设置spi读每个字含多个个位retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);break;case SPI_IOC_RD_MAX_SPEED_HZ://设置spi读最大速率retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);break;case SPI_IOC_WR_MODE://设置spi写模式retval = __get_user(tmp, (u8 __user *)arg);if (retval == 0) {u8save = spi->mode;//获取spi设备模式if (tmp & ~SPI_MODE_MASK) {retval = -EINVAL;break;}tmp |= spi->mode & ~SPI_MODE_MASK;spi->mode = (u8)tmp;retval = spi_setup(spi);//配置spi设备if (retval < 0)spi->mode = save;elsedev_dbg(&spi->dev, "spi mode %02x\n", tmp);}break;case SPI_IOC_WR_LSB_FIRST://设置spi写最低有效位retval = __get_user(tmp, (__u8 __user *)arg);if (retval == 0) {u8save = spi->mode;//获取spi设备模式if (tmp)spi->mode |= SPI_LSB_FIRST;elsespi->mode &= ~SPI_LSB_FIRST;retval = spi_setup(spi);//配置spi设备if (retval < 0)spi->mode = save;elsedev_dbg(&spi->dev, "%csb first\n",tmp ? 'l' : 'm');}break;case SPI_IOC_WR_BITS_PER_WORD://设置spi写每个字含多个个位retval = __get_user(tmp, (__u8 __user *)arg);//用户空间获取数据if (retval == 0) {u8save = spi->bits_per_word;//获取spi设备 每个字含多少位spi->bits_per_word = tmp;//更新新的spi设备 每个字含多少位retval = spi_setup(spi);//配置spi设备if (retval < 0)//配置失败spi->bits_per_word = save;//还原spi设备 每个字含多少位elsedev_dbg(&spi->dev, "%d bits per word\n", tmp);}break;case SPI_IOC_WR_MAX_SPEED_HZ://设置spi写最大速率retval = __get_user(tmp, (__u32 __user *)arg);//用户空间获取数据if (retval == 0) {u32save = spi->max_speed_hz;//获取spi设备最大速率spi->max_speed_hz = tmp;//更新新的spi设备最大速率retval = spi_setup(spi);//配置spi设备if (retval < 0)//配置失败spi->max_speed_hz = save;//还原spi设备最大速率elsedev_dbg(&spi->dev, "%d Hz (max)\n", tmp);}break;default://命令必须为写方向的命令,且传输数据必须是SPI_IOC_MESSAGE()修饰的命令if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))|| _IOC_DIR(cmd) != _IOC_WRITE) {retval = -ENOTTY;break;}tmp = _IOC_SIZE(cmd);//计算传输数据大小if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {//判断是否为spi_ioc_transfer对齐retval = -EINVAL;break;}n_ioc = tmp / sizeof(struct spi_ioc_transfer);//计算出spi_ioc_transfer数据的个数if (n_ioc == 0)break;ioc = kmalloc(tmp, GFP_KERNEL);//分配spi_ioc_transfer指针ioc内存if (!ioc) {retval = -ENOMEM;break;}if (__copy_from_user(ioc, (void __user *)arg, tmp)) {//从用户空间复制到内核空间kfree(ioc);//复制失败则释放ioc内存retval = -EFAULT;break;}retval = spidev_message(spidev, ioc, n_ioc);//spidev消息处理kfree(ioc);//释放ioc内存break;}mutex_unlock(&spidev->buf_lock);//解互斥锁spi_dev_put(spi);//增加spi设备的引用计数return retval;}static int spidev_open(struct inode *inode, struct file *filp){struct spidev_data*spidev;intstatus = -ENXIO;mutex_lock(&device_list_lock);//上互斥锁list_for_each_entry(spidev, &device_list, device_entry) {//遍历device_listif (spidev->devt == inode->i_rdev) {//判断设备号找到对应的设备status = 0;//设置状态为0break;}}if (status == 0) {//找得到对应的设备if (!spidev->buffer) {//spidev_data缓冲区为空spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);//则分配内存if (!spidev->buffer) {//还空dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");//调试了status = -ENOMEM;}}if (status == 0) {//找得到对应的设备spidev->users++;//spidev_data使用者计数++filp->private_data = spidev;//spidev_data放在文件的私有数据里nonseekable_open(inode, filp);//设置文件的打开模式(文件读写指针不会跟随读写操作移动)}} elsepr_debug("spidev: nothing for minor %d\n", iminor(inode));mutex_unlock(&device_list_lock);//接互斥锁return status;}static int spidev_release(struct inode *inode, struct file *filp){struct spidev_data*spidev;intstatus = 0;mutex_lock(&device_list_lock);spidev = filp->private_data;//获取spidev_datafilp->private_data = NULL;//清除文件的私有数据指针spidev->users--;//使用者个数--if (!spidev->users) {//如果使用者个数为0intdofree;kfree(spidev->buffer);//释放spidev_data的缓冲区内存spidev->buffer = NULL;//清除spidev_data缓冲区指针spin_lock_irq(&spidev->spi_lock);//上自旋锁dofree = (spidev->spi == NULL);//判断spi设备是否与spidev_data解绑了spin_unlock_irq(&spidev->spi_lock);//解自旋锁if (dofree)//没有捆绑的spi设备kfree(spidev);//则是否spidev_data内存}mutex_unlock(&device_list_lock);return status;}static const struct file_operations spidev_fops = {//文件操作函数集.owner =THIS_MODULE,.write =spidev_write,//写write.read =spidev_read,//读read.unlocked_ioctl = spidev_ioctl,//控制ioctl.open =spidev_open,//打开open.release =spidev_release,//释放release.llseek =no_llseek,//文件指针移动 no_llseek表示没有移动};static struct class *spidev_class;static int __devinit spidev_probe(struct spi_device *spi){struct spidev_data*spidev;intstatus;unsigned longminor;spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);//分配spidev_data内存if (!spidev)return -ENOMEM;spidev->spi = spi;//设置spidev_data->spi(spi设备)spin_lock_init(&spidev->spi_lock);mutex_init(&spidev->buf_lock);INIT_LIST_HEAD(&spidev->device_entry);//初始化spidev_data入口链表mutex_lock(&device_list_lock);minor = find_first_zero_bit(minors, N_SPI_MINORS);//查找次设备位图分配次设备号if (minor < N_SPI_MINORS) {struct device *dev;spidev->devt = MKDEV(SPIDEV_MAJOR, minor);//计算出设备号//创建设备/dev/spidev%d.%d(spidev总线号.片选号)dev = device_create(spidev_class, &spi->dev, spidev->devt,spidev, "spidev%d.%d",spi->master->bus_num, spi->chip_select);status = IS_ERR(dev) ? PTR_ERR(dev) : 0;} else {dev_dbg(&spi->dev, "no minor number available!\n");status = -ENODEV;}if (status == 0) {//分配设备号成功set_bit(minor, minors);//更新次设备位图list_add(&spidev->device_entry, &device_list);//添加进设备链表}mutex_unlock(&device_list_lock);if (status == 0)spi_set_drvdata(spi, spidev);//spi->dev->p->driver_data=spidev elsekfree(spidev);return status;}static int __devexit spidev_remove(struct spi_device *spi){struct spidev_data*spidev = spi_get_drvdata(spi);//根据spi设备获取spidev_dataspin_lock_irq(&spidev->spi_lock);//上自旋锁spidev->spi = NULL;//清空spidev_data->spi指针spi_set_drvdata(spi, NULL);//spi->dev->p->driver_data=NULLspin_unlock_irq(&spidev->spi_lock);//解自旋锁mutex_lock(&device_list_lock);//上互斥锁list_del(&spidev->device_entry);//删除spidev_data入口链表device_destroy(spidev_class, spidev->devt);//销毁/dev/spidev%d.%dclear_bit(MINOR(spidev->devt), minors);//清除次设备位图对应位if (spidev->users == 0)//使用者个数为0kfree(spidev);//释放spidev_data内存mutex_unlock(&device_list_lock);//解互斥锁return 0;}static struct spi_driver spidev_spi_driver = {//spi设备驱动.driver = {.name ="spidev",.owner =THIS_MODULE,},.probe =spidev_probe,//spidev的probe方法(当注册了modalias域为"spidev"的spi设备或板级设备,则会调用probe方法).remove =__devexit_p(spidev_remove),//spidev的remove方法};static int __init spidev_init(void)//spidev接口初始化{int status;BUILD_BUG_ON(N_SPI_MINORS > 256);//注册字符设备,主设备号SPIDEV_MAJOR=153,捆绑的设备操作函数集为spidev_fopsstatus = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);if (status < 0)return status;spidev_class = class_create(THIS_MODULE, "spidev");//创建设备类spidev_classif (IS_ERR(spidev_class)) {unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);return PTR_ERR(spidev_class);}status = spi_register_driver(&spidev_spi_driver);//注册spi设备驱动spidev_spi_driverif (status < 0) {class_destroy(spidev_class);unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);}return status;}module_init(spidev_init);//声明初始化入口static void __exit spidev_exit(void)//spidev接口销毁{spi_unregister_driver(&spidev_spi_driver);//注销spi设备驱动spidev_spi_driverclass_destroy(spidev_class);//注销设备类spidev_classunregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);//注销字符设备}module_exit(spidev_exit);//声明初始化出口MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");MODULE_DESCRIPTION("User mode SPI device interface");MODULE_LICENSE("GPL");MODULE_ALIAS("spi:spidev");


二.用户空间例子(spidev_test.c)

#include <stdint.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <getopt.h>#include <fcntl.h>#include <sys/ioctl.h>#include <linux/types.h>#include <linux/spi/spidev.h>#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))static void pabort(const char *s){perror(s);abort();}static const char *device = "/dev/spidev1.1";static uint8_t mode;static uint8_t bits = 8;static uint32_t speed = 500000;static uint16_t delay;static void transfer(int fd){int ret;uint8_t tx[] = {//要发送的数据数组0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0x40, 0x00, 0x00, 0x00, 0x00, 0x95,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,0xF0, 0x0D,};uint8_t rx[ARRAY_SIZE(tx)] = {0, };//接收的数据数据struct spi_ioc_transfer tr = {//声明并初始化spi_ioc_transfer结构体.tx_buf = (unsigned long)tx,.rx_buf = (unsigned long)rx,.len = ARRAY_SIZE(tx),.delay_usecs = delay,.speed_hz = speed,.bits_per_word = bits,};//SPI_IOC_MESSAGE(1)的1表示spi_ioc_transfer的数量ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);//ioctl默认操作,传输数据if (ret < 1)pabort("can't send spi message");for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {//打印接收缓冲区if (!(ret % 6))//6个数据为一簇打印puts("");printf("%.2X ", rx[ret]);}puts("");}static void print_usage(const char *prog)//参数错误则打印帮助信息{printf("Usage: %s [-DsbdlHOLC3]\n", prog);puts("  -D --device   device to use (default /dev/spidev1.1)\n"     "  -s --speed    max speed (Hz)\n"     "  -d --delay    delay (usec)\n"     "  -b --bpw      bits per word \n"     "  -l --loop     loopback\n"     "  -H --cpha     clock phase\n"     "  -O --cpol     clock polarity\n"     "  -L --lsb      least significant bit first\n"     "  -C --cs-high  chip select active high\n"     "  -3 --3wire    SI/SO signals shared\n");exit(1);}static void parse_opts(int argc, char *argv[]){while (1) {static const struct option lopts[] = {//参数命令表{ "device",  1, 0, 'D' },{ "speed",   1, 0, 's' },{ "delay",   1, 0, 'd' },{ "bpw",     1, 0, 'b' },{ "loop",    0, 0, 'l' },{ "cpha",    0, 0, 'H' },{ "cpol",    0, 0, 'O' },{ "lsb",     0, 0, 'L' },{ "cs-high", 0, 0, 'C' },{ "3wire",   0, 0, '3' },{ "no-cs",   0, 0, 'N' },{ "ready",   0, 0, 'R' },{ NULL, 0, 0, 0 },};int c;c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);if (c == -1)break;switch (c) {case 'D'://设备名device = optarg;break;case 's'://速率speed = atoi(optarg);break;case 'd'://延时时间delay = atoi(optarg);break;case 'b'://每字含多少位bits = atoi(optarg);break;case 'l'://回送模式mode |= SPI_LOOP;break;case 'H'://时钟相位mode |= SPI_CPHA;break;case 'O'://时钟极性mode |= SPI_CPOL;break;case 'L'://lsb 最低有效位mode |= SPI_LSB_FIRST;break;case 'C'://片选高电平mode |= SPI_CS_HIGH;break;case '3'://3线传输模式mode |= SPI_3WIRE;break;case 'N'://没片选mode |= SPI_NO_CS;break;case 'R'://从机拉低电平停止数据传输mode |= SPI_READY;break;default://错误的参数print_usage(argv[0]);break;}}}int main(int argc, char *argv[]){int ret = 0;int fd;parse_opts(argc, argv);//解析传递进来的参数fd = open(device, O_RDWR);//打开设备文件if (fd < 0)pabort("can't open device");/* * spi mode//设置spi设备模式 */ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);//写模式if (ret == -1)pabort("can't set spi mode");ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);//读模式if (ret == -1)pabort("can't get spi mode");/* * bits per word//设置每个字含多少位 */ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);//写 每个字含多少位if (ret == -1)pabort("can't set bits per word");ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);//读 每个字含多少位if (ret == -1)pabort("can't get bits per word");/* * max speed hz//设置速率 */ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);//写速率if (ret == -1)pabort("can't set max speed hz");ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);//读速率if (ret == -1)pabort("can't get max speed hz");//打印模式,每字多少位和速率信息printf("spi mode: %d\n", mode);printf("bits per word: %d\n", bits);printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);transfer(fd);//传输测试close(fd);//关闭设备return ret;}


这里整理下ioctl的命令:

SPI_IOC_RD_MODE//读 模式SPI_IOC_RD_LSB_FIRST//读 LSBSPI_IOC_RD_BITS_PER_WORD//读 每字多少位SPI_IOC_RD_MAX_SPEED_HZ//读 最大速率SPI_IOC_WR_MODE//写 模式SPI_IOC_WR_LSB_FIRST//写 LSBSPI_IOC_WR_BITS_PER_WORD//写 每字多少位SPI_IOC_WR_MAX_SPEED_HZ//写 最大速率SPI_IOC_MESSAGE(n)//传输n个数据包

<--一 linux spi子系统(框架)
原创粉丝点击