linux spi驱动开发学习(二)-----spidev.c
一.spidev.c文件
看一个设备驱动的方法:
module_init标识的入口初始化函数spidev_init,(module_exit标识的出口函数)
设备与设备驱动匹配时候调用的probe方法spidev_probe
设备驱动的操作函数集file_operations--->spidev_fops
@@open方法spidev_open
进行检查, 重点是以后三条语句,其他的见下面代码注释:
-
spidev->users++;
-
filp->private_data = spidev;
-
nonseekable_open(inode, filp);
@@read方法spidev_read
spidev = filp->private_data;=========>>status = spidev_sync_read(spidev, count);===========>>
spidev_sync(spidev, &m);==========>>status = spi_async(spidev->spi, message);===========>>
wait_for_completion(&done);========>>到了这一步是重点,在spi_async()方法中,使用以下语句将要做的事情加到workqueue中
list_add_tail(&m->queue, &bitbang->queue);
queue_work(bitbang->workqueue, &bitbang->work);
此后所有的处理程序便转移到在之前初始化的work方法中看以下代码:
-
static void bitbang_work(struct work_struct *work)
-
{
-
struct spi_bitbang *bitbang =
-
container_of(work, struct spi_bitbang, work);
-
unsigned long flags;
-
int do_setup = -1;
-
int (*setup_transfer)(struct spi_device *,
-
struct spi_transfer *);
-
-
setup_transfer = bitbang->setup_transfer;
-
-
spin_lock_irqsave(&bitbang->lock, flags);
-
bitbang->busy = 1;
-
while (!list_empty(&bitbang->queue)) {
-
struct spi_message *m;
-
struct spi_device *spi;
-
unsigned nsecs;
-
struct spi_transfer *t = NULL;
-
unsigned tmp;
-
unsigned cs_change;
-
int status;
-
-
m = container_of(bitbang->queue.next, struct spi_message,
-
queue);
-
list_del_init(&m->queue);
-
spin_unlock_irqrestore(&bitbang->lock, flags);
-
-
/* FIXME this is made-up ... the correct value is known to
-
* word-at-a-time bitbang code, and presumably chipselect()
-
* should enforce these requirements too?
-
*/
-
nsecs = 100;
-
-
spi = m->spi;
-
tmp = 0;
-
cs_change = 1;
-
status = 0;
-
-
list_for_each_entry (t, &m->transfers, transfer_list) {
-
-
/* override speed or wordsize? */
-
if (t->speed_hz || t->bits_per_word)
-
do_setup = 1;
-
-
/* init (-1) or override (1) transfer params */
-
if (do_setup != 0) {
-
if (!setup_transfer) {
-
status = -ENOPROTOOPT;
-
break;
-
}
-
status = setup_transfer(spi, t);
-
if (status < 0)
-
break;
-
}
-
-
/* set up default clock polarity, and activate chip;
-
* this implicitly updates clock and spi modes as
-
* previously recorded for this device via setup().
-
* (and also deselects any other chip that might be
-
* selected ...)
-
*/
-
if (cs_change) {
-
bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
-
ndelay(nsecs);
-
}
-
cs_change = t->cs_change;
-
if (!t->tx_buf && !t->rx_buf && t->len) {
-
status = -EINVAL;
-
break;
-
}
-
-
/* transfer data. the lower level code handles any
-
* new dma mappings it needs. our caller always gave
-
* us dma-safe buffers.
-
*/
-
if (t->len) {
-
/* REVISIT dma API still needs a designated
-
* DMA_ADDR_INVALID; ~0 might be better.
-
*/
-
if (!m->is_dma_mapped)
-
t->rx_dma = t->tx_dma = 0;
-
status = bitbang->txrx_bufs(spi, t);
-
}
-
if (status > 0)
-
m->actual_length += status;
-
if (status != t->len) {
-
/* always report some kind of error */
-
if (status >= 0)
-
status = -EREMOTEIO;
-
break;
-
}
-
status = 0;
-
-
/* protocol tweaks before next transfer */
-
if (t->delay_usecs)
-
udelay(t->delay_usecs);
-
-
if (!cs_change)
-
continue;
-
if (t->transfer_list.next == &m->transfers)
-
break;
-
-
/* sometimes a short mid-message deselect of the chip
-
* may be needed to terminate a mode or command
-
*/
-
ndelay(nsecs);
-
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-
ndelay(nsecs);
-
}
-
-
m->status = status;
-
m->complete(m->context);
-
-
/* restore speed and wordsize if it was overridden */
-
if (do_setup == 1)
-
setup_transfer(spi, NULL);
-
do_setup = 0;
-
-
/* normally deactivate chipselect ... unless no error and
-
* cs_change has hinted that the next message will probably
-
* be for this chip too.
-
*/
-
if (!(status == 0 && cs_change)) {
-
ndelay(nsecs);
-
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-
ndelay(nsecs);
-
}
-
-
spin_lock_irqsave(&bitbang->lock, flags);
-
}
-
bitbang->busy = 0;
-
spin_unlock_irqrestore(&bitbang->lock, flags);
-
}
结束处理所有任务后,见上面红色底纹部分解除
wait_for_completion(&done);
最后missing = copy_to_user(buf, spidev->buffer, status);将数据发送到用户空间
@@write方法spidev_write
与上面open方式基本相同
@@ioctl方法spidev_ioctl
具体的详解见下面章节(三,四)
下面是spidev.c添加注释部分
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#define SPIDEV_MAJOR 153 //spidev主设备号
-
#define N_SPI_MINORS 32 /* ... 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_t devt;
-
spinlock_t spi_lock;
-
struct spi_device *spi;
-
struct list_head device_entry;
-
struct mutex buf_lock;
-
unsigned users;
-
u8 *buffer;
-
};
-
-
static LIST_HEAD(device_list);
-
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);
-
}
-
-
static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message)
-
{
-
DECLARE_COMPLETION_ONSTACK(done);
-
int status;
-
-
message->complete = spidev_complete;
-
message->context = &done;
-
-
spin_lock_irq(&spidev->spi_lock);
-
if (spidev->spi == NULL)
-
status = -ESHUTDOWN;
-
else
-
status = spi_async(spidev->spi, message);
-
spin_unlock_irq(&spidev->spi_lock);
-
-
if (status == 0) {
-
wait_for_completion(&done);
-
status = message->status;
-
if (status == 0)
-
status = message->actual_length;
-
}
-
return status;
-
}
-
-
static inline ssize_t spidev_sync_write(struct spidev_data *spidev, size_t len)
-
{
-
struct spi_transfer t = {
-
.tx_buf = spidev->buffer,
-
.len = len,
-
};
-
struct spi_message m;
-
-
spi_message_init(&m);
-
spi_message_add_tail(&t, &m);
-
return spidev_sync(spidev, &m);
-
}
-
-
static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len)
-
{
-
struct spi_transfer t = {
-
.rx_buf = spidev->buffer,
-
.len = len,
-
};
-
struct spi_message m;
-
-
spi_message_init(&m);
-
spi_message_add_tail(&t, &m);
-
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_t status = 0;
-
-
if (count > bufsiz)
-
return -EMSGSIZE;
-
spidev = filp->private_data;
-
mutex_lock(&spidev->buf_lock);
-
status = spidev_sync_read(spidev, count);
-
if (status > 0) {
-
unsigned long missing;
-
missing = copy_to_user(buf, spidev->buffer, status);
-
if (missing == status)
-
status = -EFAULT;
-
else
-
status = 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_t status = 0;
-
unsigned long missing;
-
-
if (count > bufsiz)
-
return -EMSGSIZE;
-
spidev = filp->private_data;
-
mutex_lock(&spidev->buf_lock);
-
missing = copy_from_user(spidev->buffer, buf, count);
-
if (missing == 0) {
-
status = spidev_sync_write(spidev, count);
-
}
-
else
-
status = -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_message msg;
-
struct spi_transfer *k_xfers;
-
struct spi_transfer *k_tmp;
-
struct spi_ioc_transfer *u_tmp;
-
unsigned n, total;
-
u8 *buf;
-
int status = -EFAULT;
-
-
spi_message_init(&msg);
-
k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
-
if (k_xfers == NULL)
-
return -ENOMEM;
-
buf = spidev->buffer;
-
total = 0;
-
-
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) {
-
status = -EMSGSIZE;
-
goto done;
-
}
-
if (u_tmp->rx_buf) {
-
k_tmp->rx_buf = buf;
-
if (!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;
-
if (copy_from_user(buf, (const u8 __user *)(uintptr_t) u_tmp->tx_buf,u_tmp->len))
-
goto done;
-
}
-
buf += k_tmp->len;
-
k_tmp->cs_change = !!u_tmp->cs_change;
-
k_tmp->bits_per_word = u_tmp->bits_per_word;
-
k_tmp->delay_usecs = u_tmp->delay_usecs;
-
k_tmp->speed_hz = u_tmp->speed_hz;
-
#ifdef VERBOSE
-
dev_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);
-
#endif
-
spi_message_add_tail(k_tmp, &msg);
-
}
-
-
status = spidev_sync(spidev, &msg);
-
if (status < 0)
-
goto done;
-
buf = spidev->buffer;
-
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
-
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;
-
}
-
status = total;
-
done:
-
kfree(k_xfers);
-
return status;
-
}
-
-
static long spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-
{
-
int err = 0;
-
int retval = 0;
-
struct spidev_data *spidev;
-
struct spi_device *spi;
-
u32 tmp;
-
unsigned n_ioc;
-
struct spi_ioc_transfer *ioc;
-
-
if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
-
return -ENOTTY;
-
if (_IOC_DIR(cmd) & _IOC_READ)
-
err = !access_ok(VERIFY_WRITE,(void __user *)arg, _IOC_SIZE(cmd));
-
if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
-
err = !access_ok(VERIFY_READ,(void __user *)arg, _IOC_SIZE(cmd));
-
if (err)
-
return -EFAULT;
-
-
spidev = filp->private_data;
-
spin_lock_irq(&spidev->spi_lock);
-
spi = spi_dev_get(spidev->spi);
-
spin_unlock_irq(&spidev->spi_lock);
-
if (spi == NULL)
-
return -ESHUTDOWN;
-
mutex_lock(&spidev->buf_lock);
-
-
switch (cmd) {
-
case SPI_IOC_RD_MODE: (此处原作者的理解与我不同,这里应该是应用程序获取数据)
-
retval = __put_user(spi->mode & SPI_MODE_MASK,(__u8 __user *)arg);
-
break;
-
case SPI_IOC_RD_LSB_FIRST: (此处原作者的理解与我不同,这里应该是应用程序获取数据)
-
retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,(__u8 __user *)arg);
-
break;
-
case SPI_IOC_RD_BITS_PER_WORD: (此处原作者的理解与我不同,这里应该是应用程序获取数据)
-
retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);
-
break;
-
case SPI_IOC_RD_MAX_SPEED_HZ: (此处原作者的理解与我不同,这里应该是应用程序获取数据)
-
retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
-
break;
-
case SPI_IOC_WR_MODE:
-
retval = __get_user(tmp, (u8 __user *)arg);
-
if (retval == 0) {
-
u8 save = spi->mode;
-
-
if (tmp & ~SPI_MODE_MASK) {
-
retval = -EINVAL;
-
break;
-
}
-
-
tmp |= spi->mode & ~SPI_MODE_MASK;
-
spi->mode = (u8)tmp;
-
retval = spi_setup(spi);
-
if (retval < 0)
-
spi->mode = save;
-
else
-
dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
-
}
-
break;
-
case SPI_IOC_WR_LSB_FIRST:
-
retval = __get_user(tmp, (__u8 __user *)arg);
-
if (retval == 0) {
-
u8 save = spi->mode;
-
-
if (tmp)
-
spi->mode |= SPI_LSB_FIRST;
-
else
-
spi->mode &= ~SPI_LSB_FIRST;
-
retval = spi_setup(spi);
-
if (retval < 0)
-
spi->mode = save;
-
else
-
dev_dbg(&spi->dev, "%csb first\n",tmp ? 'l' : 'm');
-
}
-
break;
-
case SPI_IOC_WR_BITS_PER_WORD:
-
retval = __get_user(tmp, (__u8 __user *)arg);
-
if (retval == 0) {
-
u8 save = spi->bits_per_word;
-
-
spi->bits_per_word = tmp;
-
retval = spi_setup(spi);
-
if (retval < 0)
-
spi->bits_per_word = save;
-
else
-
dev_dbg(&spi->dev, "%d bits per word\n", tmp);
-
}
-
break;
-
case SPI_IOC_WR_MAX_SPEED_HZ:
-
retval = __get_user(tmp, (__u32 __user *)arg);
-
if (retval == 0) {
-
u32 save = spi->max_speed_hz;
-
-
spi->max_speed_hz = tmp;
-
retval = spi_setup(spi);
-
if (retval < 0)
-
spi->max_speed_hz = save;
-
else
-
dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
-
}
-
break;
-
-
default:
-
-
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) {
-
retval = -EINVAL;
-
break;
-
}
-
n_ioc = tmp / sizeof(struct spi_ioc_transfer);
-
if (n_ioc == 0)
-
break;
-
-
ioc = kmalloc(tmp, GFP_KERNEL);
-
if (!ioc) {
-
retval = -ENOMEM;
-
break;
-
}
-
if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
-
kfree(ioc);
-
retval = -EFAULT;
-
break;
-
}
-
-
retval = spidev_message(spidev, ioc, n_ioc);
-
kfree(ioc);
-
break;
-
}
-
-
mutex_unlock(&spidev->buf_lock);
-
spi_dev_put(spi);
-
return retval;
-
}
-
-
static int spidev_open(struct inode *inode, struct file *filp)
-
{
-
struct spidev_data *spidev;
-
int status = -ENXIO;
-
-
mutex_lock(&device_list_lock);
-
list_for_each_entry(spidev, &device_list, device_entry) {
-
if (spidev->devt == inode->i_rdev) {
-
status = 0;
-
break;
-
}
-
}
-
if (status == 0) {
-
if (!spidev->buffer) {
-
spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
-
if (!spidev->buffer) {
-
dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
-
status = -ENOMEM;
-
}
-
}
-
if (status == 0) {
-
spidev->users++;
-
filp->private_data = spidev;
-
nonseekable_open(inode, filp);
-
}
-
}
-
else
-
pr_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;
-
int status = 0;
-
-
mutex_lock(&device_list_lock);
-
spidev = filp->private_data;
-
filp->private_data = NULL;
-
spidev->users--;
-
if (!spidev->users) {
-
int dofree;
-
kfree(spidev->buffer);
-
spidev->buffer = NULL;
-
spin_lock_irq(&spidev->spi_lock);
-
dofree = (spidev->spi == NULL);
-
spin_unlock_irq(&spidev->spi_lock);
-
if (dofree)
-
kfree(spidev);
-
}
-
mutex_unlock(&device_list_lock);
-
return status;
-
}
-
-
static const struct file_operations spidev_fops = {
-
.owner = THIS_MODULE,
-
.write = spidev_write,
-
.read = spidev_read,
-
.unlocked_ioctl = spidev_ioctl,
-
.open = spidev_open,
-
.release = spidev_release,
-
.llseek = no_llseek,
-
};
-
-
static struct class *spidev_class;
-
-
static int __devinit spidev_probe(struct spi_device *spi)
-
{
-
struct spidev_data *spidev;
-
int status;
-
unsigned long minor;
-
-
spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
-
if (!spidev)
-
return -ENOMEM;
-
spidev->spi = spi;
-
spin_lock_init(&spidev->spi_lock);
-
mutex_init(&spidev->buf_lock);
-
INIT_LIST_HEAD(&spidev->device_entry);
-
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 = 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);
-
else
-
kfree(spidev);
-
-
return status;
-
}
-
-
static int __devexit spidev_remove(struct spi_device *spi)
-
{
-
struct spidev_data *spidev = spi_get_drvdata(spi);
-
spin_lock_irq(&spidev->spi_lock);
-
spidev->spi = NULL;
-
spi_set_drvdata(spi, NULL);
-
spin_unlock_irq(&spidev->spi_lock);
-
mutex_lock(&device_list_lock);
-
list_del(&spidev->device_entry);
-
device_destroy(spidev_class, spidev->devt);
-
clear_bit(MINOR(spidev->devt), minors);
-
if (spidev->users == 0)
-
kfree(spidev);
-
mutex_unlock(&device_list_lock);
-
return 0;
-
}
-
-
static struct spi_driver spidev_spi_driver = {
-
.driver = {
-
.name = "spidev",
-
.owner = THIS_MODULE,
-
},
-
.probe = spidev_probe,
-
.remove = __devexit_p(spidev_remove),
-
};
-
-
static int __init spidev_init(void)
-
{
-
int status;
-
BUILD_BUG_ON(N_SPI_MINORS > 256);
-
-
status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
-
if (status < 0)
-
return status;
-
spidev_class = class_create(THIS_MODULE, "spidev");
-
if (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);
-
if (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)
-
{
-
spi_unregister_driver(&spidev_spi_driver);
-
class_destroy(spidev_class);
-
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
-
}
-
module_exit(spidev_exit);
-
-
MODULE_AUTHOR("Andrea Paterniani, ");
-
MODULE_DESCRIPTION("User mode SPI device interface");
-
MODULE_LICENSE("GPL");
-
MODULE_ALIAS("spi:spidev");
二.用户空间例子(spidev_test.c)
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
#include
-
-
#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 = {
-
.tx_buf = (unsigned long)tx,
-
.rx_buf = (unsigned long)rx,
-
.len = ARRAY_SIZE(tx),
-
.delay_usecs = delay,
-
.speed_hz = speed,
-
.bits_per_word = bits,
-
};
-
-
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
-
if (ret < 1)
-
pabort("can't send spi message");
-
-
for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
-
if (!(ret % 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':
-
mode |= SPI_LSB_FIRST;
-
break;
-
case 'C':
-
mode |= SPI_CS_HIGH;
-
break;
-
case '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");
-
-
-
-
-
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");
-
-
-
-
-
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");
-
-
-
-
-
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
-
SPI_IOC_RD_BITS_PER_WORD
-
SPI_IOC_RD_MAX_SPEED_HZ
-
SPI_IOC_WR_MODE
-
SPI_IOC_WR_LSB_FIRST
-
SPI_IOC_WR_BITS_PER_WORD
-
SPI_IOC_WR_MAX_SPEED_HZ
-
SPI_IOC_MESSAGE(n)
阅读(1881) | 评论(0) | 转发(0) |