免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7697 | 回复: 1
打印 上一主题 下一主题

s3c2440 spi ret = ioctl(fd_dev, SPI_IOC_MESSAGE(1), &spi_tr); 无规律返回1 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-04-02 13:30 |只看该作者 |倒序浏览
本帖最后由 fengchen_it168 于 2012-04-02 15:33 编辑

如题。望高手帮分析下~不胜感激~~~

////////////调用的函数///////////////
uint8_t transmit(struct cmd_type *p_cmd)
{
        int ret;
        int fd_dev;
        uint8_t i;
        uint8_t a_tx_buf[PAGE_SIZE];
        uint8_t a_rx_buf[PAGE_SIZE];
        struct spi_ioc_transfer spi_tr;
       
        fd_dev = open(device, O_RDWR);
        if (fd_dev < 0){
                puts("can't open device:1";
                exit(0);
        }
       
        spi_tr.delay_usecs = 0;
        spi_tr.cs_change = 1;        //not change
        spi_tr.len = 1+(p_cmd->num_addr)+(p_cmd->num_dummy);
        spi_tr.tx_buf = (unsigned long)a_tx_buf;
        spi_tr.rx_buf = (unsigned long)a_rx_buf;
       
//        memset(a_rx_buf,0,sizeof a_rx_buf);
//        memset(a_tx_buf,0,sizeof a_tx_buf);
        a_tx_buf[0] = p_cmd->cmd;
        for(i=0;i<(p_cmd->num_addr);i++){
                a_tx_buf[1+i] = (p_cmd->p_cmd_addr);
        }
        for(i=0;i<(p_cmd->num_dummy);i++){
                a_tx_buf[1+(p_cmd->num_addr)+i] = 0xFF;
        }
        ret = ioctl(fd_dev, SPI_IOC_MESSAGE(1), &spi_tr);
//        free(a_tr_buf);
        if (ret == 1){                                                                                ///////////就是这儿出错
                puts("111can't send chip cmd+addr+dummy";
                close(fd_dev);
                return 1;
        }

        if(p_cmd->num_data){        //send/receive data
                spi_tr.delay_usecs = p_cmd->delay_usecs;
                spi_tr.cs_change = 0;//change
                spi_tr.len = p_cmd->num_data;
                if(spi_tr.len < 2){        //why ?
                        spi_tr.len = 2;
                }
               
//                memset(a_rx_buf,0,sizeof a_rx_buf);
//                memset(a_tx_buf,0,sizeof a_tx_buf);
                if(p_cmd->mode_data_rw){        //write
                        memcpy(a_tx_buf,p_cmd->p_rw_data,p_cmd->num_data);
                }
                ret = ioctl(fd_dev, SPI_IOC_MESSAGE(1), &spi_tr);
                if(!(p_cmd->mode_data_rw)){        //read
                        memcpy(p_cmd->p_rw_data,a_rx_buf,p_cmd->num_data);
                }
                if (ret == 1){
                        puts("111can't send chip cmd+addr+dummy";
                        close(fd_dev);
                        return 1;
                }
        }
        close(fd_dev);
        return 0;
}
///////////////相关声明////////////////
struct cmd_type {
        char* cmd_name;
        uint8_t cmd;
        uint8_t num_addr;
        uint8_t *p_cmd_addr;
        uint8_t num_dummy;
        uint8_t mode_data_rw;        //r:0,w:1
        uint32_t num_data;       
        uint8_t *p_rw_data;
        uint32_t delay_usecs;
};
struct spi_ioc_transfer {
        __u64                tx_buf;
        __u64                rx_buf;

        __u32                len;
        __u32                speed_hz;

        __u16                delay_usecs;
        __u8                bits_per_word;
        __u8                cs_change;
        __u32                pad;

        /* If the contents of 'struct spi_ioc_transfer' ever change
         * incompatibly, then the ioctl number (currently 0) must change;
         * ioctls with constant size fields get a bit more in the way of
         * error checking than ones (like this) where that field varies.
         *
         * NOTE: struct layout is the same in 64bit and 32bit userspace.
         */
};


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;

        /* Construct spi_message, copying any tx data to bounce buffer.
         * We walk the array of user-provided transfers, using each one
         * to initialize a kernel version of the same transfer.
         */
        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(&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 ? : spi->bits_per_word,
                        u_tmp->delay_usecs,
                        u_tmp->speed_hz ? : spi->max_speed_hz);
#endif
                spi_message_add_tail(k_tmp, &msg);
        }

        status = spidev_sync(spidev, &msg);
        if (status < 0)
                goto done;

        /* copy any rx data out of bounce buffer */
        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;

        /* Check type and command number */
        if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
                return -ENOTTY;

        /* Check access direction once here; don't repeat below.
         * IOC_DIR is from the user perspective, while access_ok is
         * from the kernel perspective; so they look reversed.
         */
        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;

        /* guard against device removal before, or while,
         * we issue this ioctl.
         */
        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;

        /* use the buffer lock here for triple duty:
         *  - prevent I/O (from us) so calling spi_setup() is safe;
         *  - prevent concurrent SPI_IOC_WR_* from morphing
         *    data fields while SPI_IOC_RD_* reads them;
         *  - SPI_IOC_MESSAGE needs the buffer locked "normally".
         */
        mutex_lock(&spidev->buf_lock);

        switch (cmd) {
        /* read requests */
        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;

        /* write requests */
        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 = (utmp;
                        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:
                /* segmented and/or full-duplex I/O request */
                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;

                /* copy into scratch area */
                ioc = kmalloc(tmp, GFP_KERNEL);
                if (!ioc) {
                        retval = -ENOMEM;
                        break;
                }
                if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
                        kfree(ioc);
                        retval = -EFAULT;
                        break;
                }

                /* translate to spi_message, execute */
                retval = spidev_message(spidev, ioc, n_ioc);
                kfree(ioc);
                break;
        }

        mutex_unlock(&spidev->buf_lock);
        spi_dev_put(spi);
        return retval;
}

论坛徽章:
0
2 [报告]
发表于 2012-04-02 15:11 |只看该作者
用printk搞定,
ret = ioctl(fd_dev, SPI_IOC_MESSAGE(1), &spi_tr);返回为READ/WRITE(全双工)的字节数,所以可能为1.
内核DOC中的例子中用的判断ret是否为1,本来以为返回1是指有错呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP