注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

LINUX驱动之SPI子系统之七数据传输1  

2012-10-30 21:22:00|  分类: LINUX内核驱动 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 

LINUX驱动之SPI子系统之七数据传输1

在LINUX中,推荐用户层和核心层的交互,使用IOCTL,当然,别的也可以,条条大路通罗马。今天主要就讲SPI数据的传输,前面已经把整个驱动,设备和总线的纠缠的关系理顺清了,下来就看他们怎么配合着来达到传输数据目的。

当通过ioctl向设备驱动发送传输数据的命令时,向SPI从设备发送读写命令,实际的读写操作还是调用了主机控制器驱动的数据传输函数。transfer函数用于spi的IO传输。但是,transfer函数一般不会执行真正的传输操作,而是把要传输的内容放到一个队列里,然后调用一种类似底半部的机制进行真正的传输。这是因为,spi总线一般会连多个spi设备,而spi设备间的访问可能会并发。如果直接在transfer函数中实现传输,那么会产生竞态,spi设备互相间会干扰。所以,真正的spi传输与具体的spi控制器的实现有关,spi的框架代码中没有涉及。像spi设备的片选,根据具体设备进行时钟调整等等都在实现传输的代码中被调用。spi的传输命令都是通过结构spi_message定义,设备程序调用transfer函数将spi_message交给spi总线驱动,总线驱动再将message传到底半部排队,实现串行化传输。Spidev.c:


1.   static struct file_operations spidev_fops = {  

2.       .owner =    THIS_MODULE,  

3.       .write =    spidev_write,  

4.       .read =     spidev_read,  

5.       .unlocked_ioctl = spidev_ioctl,  

6.       .open =     spidev_open,  

7.       .release =  spidev_release,  


};

同样在本文件中,函数spidev_ioctl的实现:


1.   static long  

2.   spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  

3.   {  

4.       int         err = 0;  

5.       int         retval = 0;  

6.       struct spidev_data  *spidev;  

7.       struct spi_device   *spi;  

8.       u32         tmp;  

9.       unsigned        n_ioc;  

10.      struct spi_ioc_transfer *ioc;  

11.    

12.      /*查看这个命令的幻数字段是否为'k'*/  

13.      if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)  

14.          return -ENOTTY;  

15.    

16.      /*如果方向是用户空间从内核读,即内核向用户空间写,则检查用户空间的地址是否有效*/  

17.      if (_IOC_DIR(cmd) & _IOC_READ)  

18.          err = !access_ok(VERIFY_WRITE,  

19.                  (void __user *)arg, _IOC_SIZE(cmd));  

20.      /*如果方向是用户空间向内核写,即内核读用户空间,则检查用户空间的地址是否有效*/  

21.      if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)  

22.          err = !access_ok(VERIFY_READ,  

23.                  (void __user *)arg, _IOC_SIZE(cmd));  

24.      if (err)  

25.          return -EFAULT;  

26.    

27.      /* guard against device removal before, or while, 

28.       * we issue this ioctl. 

29.       */  

30.      spidev = filp->private_data;  

31.      spin_lock_irq(&spidev->spi_lock);  

32.      spi = spi_dev_get(spidev->spi);  

33.      spin_unlock_irq(&spidev->spi_lock);  

34.    

35.      if (spi == NULL)  

36.          return -ESHUTDOWN;  

37.    

38.      mutex_lock(&spidev->buf_lock);  

39.    

40.      switch (cmd) {  

41.      /* read requests */  

42.      case SPI_IOC_RD_MODE:  

43.          /*因为已经进行了地址是否有效的检查,所以这里使用__put_user,__get_user,__copy_from_user可以节省几个时钟周期呢*/  

44.          retval = __put_user(spi->mode & SPI_MODE_MASK,  

45.                      (__u8 __user *)arg);  

46.          break;  

47.      case SPI_IOC_RD_LSB_FIRST:  

48.          retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,  

49.                      (__u8 __user *)arg);  

50.          break;  

51.      case SPI_IOC_RD_BITS_PER_WORD:  

52.          retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);  

53.          break;  

54.      case SPI_IOC_RD_MAX_SPEED_HZ:  

55.          retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);  

56.          break;  

57.    

58.      /*设置SPI模式*/  

59.      case SPI_IOC_WR_MODE:  

60.          retval = __get_user(tmp, (u8 __user *)arg);  

61.          if (retval == 0) {  

62.              /*先将之前的模式保存起来,一旦设置失败进行回复*/  

63.              u8  save = spi->mode;  

64.    

65.              if (tmp & ~SPI_MODE_MASK) {  

66.                  retval = -EINVAL;  

67.                  break;  

68.              }  

69.    

70.              tmp |= spi->mode & ~SPI_MODE_MASK;  

71.              spi->mode = (u8)tmp;  

72.              retval = spi_setup(spi);  

73.              if (retval < 0)  

74.                  spi->mode = save;  

75.              else  

76.                  dev_dbg(&spi->dev, "spi mode %02x\n", tmp);  

77.          }  

78.          break;  

79.      case SPI_IOC_WR_LSB_FIRST:  

80.          retval = __get_user(tmp, (__u8 __user *)arg);  

81.          if (retval == 0) {  

82.              u8  save = spi->mode;  

83.    

84.              if (tmp)  

85.                  spi->mode |= SPI_LSB_FIRST;  

86.              else  

87.                  spi->mode &= ~SPI_LSB_FIRST;  

88.              retval = spi_setup(spi);  

89.              if (retval < 0)  

90.                  spi->mode = save;  

91.              else  

92.                  dev_dbg(&spi->dev, "%csb first\n",  

93.                          tmp ? 'l' : 'm');  

94.          }  

95.          break;  

96.      case SPI_IOC_WR_BITS_PER_WORD:  

97.          retval = __get_user(tmp, (__u8 __user *)arg);  

98.          if (retval == 0) {  

99.              u8  save = spi->bits_per_word;  

100.  

101.            spi->bits_per_word = tmp;  

102.            retval = spi_setup(spi);  

103.            if (retval < 0)  

104.                spi->bits_per_word = save;  

105.            else  

106.                dev_dbg(&spi->dev, "%d bits per word\n", tmp);  

107.        }  

108.        break;  

109.    case SPI_IOC_WR_MAX_SPEED_HZ:  

110.        retval = __get_user(tmp, (__u32 __user *)arg);  

111.        if (retval == 0) {  

112.            u32 save = spi->max_speed_hz;  

113.  

114.            spi->max_speed_hz = tmp;  

115.            retval = spi_setup(spi);  

116.            if (retval < 0)  

117.                spi->max_speed_hz = save;  

118.            else  

119.                dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);  

120.        }  

121.        break;  

122.  

123.    default:  

124.        /* segmented and/or full-duplex I/O request */  

125.        if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))  

126.                || _IOC_DIR(cmd) != _IOC_WRITE) {  

127.            retval = -ENOTTY;  

128.            break;  

129.        }  

130.        /*得到用户空间数据的大小*/  

131.        tmp = _IOC_SIZE(cmd);  

132.        /*如果这些数据不能分成spi_ioc_transfer的整数倍,则不能进行传输,spi_io_transfer是对spi_transfer的映射*/  

133.        if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {  

134.            retval = -EINVAL;  

135.            break;  

136.        }  

137.        /*计算出能分多少个spi_ioc_transfer*/  

138.        n_ioc = tmp / sizeof(struct spi_ioc_transfer);  

139.        if (n_ioc == 0)  

140.            break;  

141.  

142.        /*在内核中分配装载这些数据的内存空间*/  

143.        ioc = kmalloc(tmp, GFP_KERNEL);  

144.        if (!ioc) {  

145.            retval = -ENOMEM;  

146.            break;  

147.        }  

148.        /*把用户空间的数据拷贝过来*/  

149.        if (__copy_from_user(ioc, (void __user *)arg, tmp)) {  

150.            kfree(ioc);  

151.            retval = -EFAULT;  

152.            break;  

153.        }  

154.  

155.        /*进行数据传输*/  

156.        retval = spidev_message(spidev, ioc, n_ioc);

157.        kfree(ioc);  

158.        break;  

159.    }  

160.  

161.    mutex_unlock(&spidev->buf_lock);  

162.    spi_dev_put(spi);  

163.    return retval;  

164.}  


跟踪spidev_message:


1.   static int spidev_message(struct spidev_data *spidev,  

2.           struct spi_ioc_transfer *u_xfers, unsigned n_xfers)  

3.   {  

4.       struct spi_message  msg;  

5.       struct spi_transfer *k_xfers;  

6.       struct spi_transfer *k_tmp;  

7.       struct spi_ioc_transfer *u_tmp;  

8.       unsigned        n, total;  

9.       u8          *buf;  

10.      int         status = -EFAULT;  

11.      /*初始化spi_message的tranfers链表头*/  

12.      spi_message_init(&msg);  

13.      /*分配n个spi_transfer的内存空间,一个spi_message由多个数据段spi_message组成*/  

14.      k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);  

15.      if (k_xfers == NULL)  

16.          return -ENOMEM;  

17.    

18.      buf = spidev->buffer;  

19.      total = 0;  

20.      /*这个for循环的主要任务是将所有的spi_transfer组装成一个spi_message*/  

21.      for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;  

22.              n;  

23.              n--, k_tmp++, u_tmp++) {  

24.          /*u_tmp是从用户空间传下来的spi_ioc_message的大小,spi_ioc_message是对spi_message的映射*/  

25.          k_tmp->len = u_tmp->len;  

26.          /*统计要传输数据的总量*/  

27.          total += k_tmp->len;  

28.          if (total > bufsiz) {  

29.              status = -EMSGSIZE;  

30.              goto done;  

31.          }  

32.          /*spi_transfer是一个读写的buffer对,如果是要接收则把buffer给接收的rx_buf*/  

33.          if (u_tmp->rx_buf) {  

34.              k_tmp->rx_buf = buf;  

35.              if (!access_ok(VERIFY_WRITE, (u8 __user *)  

36.                          (uintptr_t) u_tmp->rx_buf,  

37.                          u_tmp->len))  

38.                  goto done;  

39.          }  

40.          /*如果要传输,这个buffer给tx_buf使用,从用户空间拷过来要传输的数据*/  

41.          if (u_tmp->tx_buf) {  

42.              k_tmp->tx_buf = buf;  

43.              if (copy_from_user(buf, (const u8 __user *)  

44.                          (uintptr_t) u_tmp->tx_buf,  

45.                      u_tmp->len))  

46.                  goto done;  

47.          }  

48.          /*指向下一段内存*/  

49.          buf += k_tmp->len;  

50.          /*最后一个transfer传输完毕是否会影响片选*/  

51.          k_tmp->cs_change = !!u_tmp->cs_change;  

52.          /*每字长的字节数*/  

53.          k_tmp->bits_per_word = u_tmp->bits_per_word;  

54.          /*一段数据传输完需要一定的时间等待*/  

55.          k_tmp->delay_usecs = u_tmp->delay_usecs;  

56.          /*初始化传输速度*/  

57.          k_tmp->speed_hz = u_tmp->speed_hz;  

58.          /*将spi_transfer通过它的transfer_list字段挂到spi_message的transfer队列上*/  

59.          spi_message_add_tail(k_tmp, &msg);  

60.      }  

61.      /*调用底层的传输函数*/  

62. status = spidev_sync(spidev, &msg);

63.      if (status < 0)  

64.          goto done;  

65.    

66.      /* copy any rx data out of bounce buffer */  

67.      buf = spidev->buffer;  

68.      /*把传输数据拷贝到用户空间打印出来,可以查看是否传输成功*/  

69.      for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {  

70.          if (u_tmp->rx_buf) {  

71.              if (__copy_to_user((u8 __user *)  

72.                      (uintptr_t) u_tmp->rx_buf, buf,  

73.                      u_tmp->len)) {  

74.                  status = -EFAULT;  

75.                  goto done;  

76.              }  

77.          }  

78.          buf += u_tmp->len;  

79.      }  

80.      status = total;  

81.    

82.  done:  

83.      kfree(k_xfers);  

84.      return status;  

85.  }  


再看spidev_sync:


1.   static ssize_t  

2.   spidev_sync(struct spidev_data *spidev, struct spi_message *message)  

3.   {  

4.       /*声明并初始化一个完成量*/  

5.       DECLARE_COMPLETION_ONSTACK(done);  

6.       int status;  

7.       /*指定spi_message使用的唤醒完成量函数*/  

8.       message->complete = spidev_complete;  

9.       message->context = &done;  

10.    

11.      spin_lock_irq(&spidev->spi_lock);  

12.      if (spidev->spi == NULL)  

13.          status = -ESHUTDOWN;  

14.      else  

15.          /*调用spi核心中的函数进行数据传输*/  

16.      status = spi_async(spidev->spi, message);</span>  

17.      spin_unlock_irq(&spidev->spi_lock);  

18.    

19.      if (status == 0) {  

20.          /*等待完成量被唤醒*/  

21.          wait_for_completion(&done);  

22.          status = message->status;  

23.          if (status == 0)  

24.              status = message->actual_length;  

25.      }  

26.      return status;  

27.  }  

spi_async在spi.h中定义的:


1.   <span style="font-size:18px;">static inline int  

2.   spi_async(struct spi_device *spi, struct spi_message *message)  

3.   {  

4.       message->spi = spi;  

5.       return spi->master->transfer(spi, message);  

6.   }  


这里的master->transfer是在spi_bitbang_start中进行赋值的:

bitbang->master->transfer= spi_bitbang_transfer;(在spi_s3c24xx.c中)

看spi_bitbang_transfer的实现:


1.   int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)  

2.   {  

3.       struct spi_bitbang  *bitbang;  

4.       unsigned long       flags;  

5.       int         status = 0;  

6.     

7.       m->actual_length = 0;  

8.       m->status = -EINPROGRESS;  

9.       /*在spi_alloc_master函数中调用spi_master_set_devdata把struct s3c24xx_spi结构存放起来,而struct spi_bitbang正是struct s3c24xx_spi结构所包含的第一个结构*/  

10.      bitbang = spi_master_get_devdata(spi->master);  

11.    

12.      spin_lock_irqsave(&bitbang->lock, flags);  

13.      if (!spi->max_speed_hz)  

14.          status = -ENETDOWN;  

15.      else {  

16.          /*把message加入到bitbang的等待队列中*/  

17.          list_add_tail(&m->queue, &bitbang->queue);  

18.          /*把bitbang-work加入bitbang->workqueue中,调度运行*/  

19.          queue_work(bitbang->workqueue, &bitbang->work);  

20.      }  

21.      spin_unlock_irqrestore(&bitbang->lock, flags);  

22.    

23.      return status;  

24.  }  

25.  EXPORT_SYMBOL_GPL(spi_bitbang_transfer);  


和前面讲几个数据结构时进行印证一下看,会有更深的印象。代码还得好好看啊。

今天就到这里吧。

  评论这张
 
阅读(2311)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017