转自:http://blog.csdn.net/eastmoon502136/article/details/7921846

对于SPI的一些结构体都有所了解之后呢,那么再去瞧瞧SPI的那些长见的操作的函数了。

首先看一下本人画的比较挫的数据流了,仅供参考,如有不对,不吝赐教

接下来看看各个函数吧还是:

SPI write

  1. /**
  2. * spi_write - SPI synchronous write
  3. * @spi: device to which data will be written
  4. * @buf: data buffer
  5. * @len: data buffer size
  6. * Context: can sleep
  7. *
  8. * This writes the buffer and returns zero or a negative error code.
  9. * Callable only from contexts that can sleep.
  10. */
  11. static inline int
  12. spi_write(struct spi_device *spi, const void *buf, size_t len)
  13. {
  14. struct spi_transfer   t = {
  15. .tx_buf           = buf,
  16. .len         = len,
  17. };
  18. struct spi_message  m;
  19. spi_message_init(&m);
  20. spi_message_add_tail(&t, &m);
  21. return spi_sync(spi, &m);
  22. }

SPI发送函数,数据放在buf中,然后把要发送的数据放在工作队列中

SPI  read

  1. /**
  2. * spi_read - SPI synchronous read
  3. * @spi: device from which data will be read
  4. * @buf: data buffer
  5. * @len: data buffer size
  6. * Context: can sleep
  7. *
  8. * This reads the buffer and returns zero or a negative error code.
  9. * Callable only from contexts that can sleep.
  10. */
  11. static inline int
  12. spi_read(struct spi_device *spi, void *buf, size_t len)
  13. {
  14. struct spi_transfer   t = {
  15. .rx_buf           = buf,
  16. .len         = len,
  17. };
  18. struct spi_message  m;
  19. spi_message_init(&m);
  20. spi_message_add_tail(&t, &m);
  21. return spi_sync(spi, &m);
  22. }

SPI接收函数,数据放在buf中,然后把要发送的数据放在工作队列中,发送出去

SPI write 8 bits read 8 bits

  1. /* this copies txbuf and rxbuf data; for small transfers only! */
  2. extern int spi_write_then_read(struct spi_device *spi,
  3. const void *txbuf, unsigned n_tx,
  4. void *rxbuf, unsigned n_rx);
  5. /**
  6. * spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read
  7. * @spi: device with which data will be exchanged
  8. * @cmd: command to be written before data is read back
  9. * Context: can sleep
  10. *
  11. * This returns the (unsigned) eight bit number returned by the
  12. * device, or else a negative error code.  Callable only from
  13. * contexts that can sleep.
  14. */
  15. static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
  16. {
  17. ssize_t                   status;
  18. u8                  result;
  19. status = spi_write_then_read(spi, &cmd, 1, &result, 1);
  20. /* return negative errno or unsigned value */
  21. return (status < 0) ? status : result;
  22. }

SPI write 8 bit read 16 bits

  1. /**
  2. * spi_w8r16 - SPI synchronous 8 bit write followed by 16 bit read
  3. * @spi: device with which data will be exchanged
  4. * @cmd: command to be written before data is read back
  5. * Context: can sleep
  6. *
  7. * This returns the (unsigned) sixteen bit number returned by the
  8. * device, or else a negative error code.  Callable only from
  9. * contexts that can sleep.
  10. *
  11. * The number is returned in wire-order, which is at least sometimes
  12. * big-endian.
  13. */
  14. static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
  15. {
  16. ssize_t                   status;
  17. u16                result;
  18. status = spi_write_then_read(spi, &cmd, 1, (u8 *) &result, 2);
  19. /* return negative errno or unsigned value */
  20. return (status < 0) ? status : result;
  21. }
  1. int spi_write_then_read(struct spi_device *spi,
  2. const void *txbuf, unsigned n_tx,
  3. void *rxbuf, unsigned n_rx)
  4. {
  5. static DEFINE_MUTEX(lock);
  6. int                 status;
  7. struct spi_message  message;
  8. struct spi_transfer   x[2];
  9. u8                  *local_buf;
  10. /* Use preallocated DMA-safe buffer.  We can't avoid copying here,
  11. * (as a pure convenience thing), but we can keep heap costs
  12. * out of the hot path ...
  13. */
  14. if ((n_tx + n_rx) > SPI_BUFSIZ)
  15. return -EINVAL;
  16. spi_message_init(&message);
  17. memset(x, 0, sizeof x);
  18. if (n_tx) {
  19. x[0].len = n_tx;
  20. spi_message_add_tail(&x[0], &message);
  21. }
  22. if (n_rx) {
  23. x[1].len = n_rx;
  24. spi_message_add_tail(&x[1], &message);
  25. }
  26. /* ... unless someone else is using the pre-allocated buffer */
  27. if (!mutex_trylock(&lock)) {
  28. local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
  29. if (!local_buf)
  30. return -ENOMEM;
  31. } else
  32. local_buf = buf;
  33. memcpy(local_buf, txbuf, n_tx);
  34. x[0].tx_buf = local_buf;
  35. x[1].rx_buf = local_buf + n_tx;
  36. /* do the i/o */
  37. status = spi_sync(spi, &message);
  38. if (status == 0)
  39. memcpy(rxbuf, x[1].rx_buf, n_rx);
  40. if (x[0].tx_buf == buf)
  41. mutex_unlock(&lock);
  42. else
  43. kfree(local_buf);
  44. return status;
  45. }

SPI sync

读写都会调用到spi_sync

  1. int spi_sync(struct spi_device *spi, struct spi_message *message)
  2. {
  3. return __spi_sync(spi, message, 0);
  4. }

接着调用了__spi_sync

  1. static int __spi_sync(struct spi_device *spi, struct spi_message *message,
  2. int bus_locked)
  3. {
  4. DECLARE_COMPLETION_ONSTACK(done);
  5. int status;
  6. struct spi_master *master = spi->master;
  7. message->complete = spi_complete;
  8. message->context = &done;
  9. if (!bus_locked)
  10. mutex_lock(&master->bus_lock_mutex);
  11. status = spi_async_locked(spi, message);
  12. if (!bus_locked)
  13. mutex_unlock(&master->bus_lock_mutex);
  14. if (status == 0) {
  15. wait_for_completion(&done);
  16. status = message->status;
  17. }
  18. message->context = NULL;
  19. return status;
  20. }

然后就是spi_async

  1. int spi_async(struct spi_device *spi, struct spi_message *message)
  2. {
  3. struct spi_master *master = spi->master;
  4. int ret;
  5. unsigned long flags;
  6. spin_lock_irqsave(&master->bus_lock_spinlock, flags);
  7. if (master->bus_lock_flag)
  8. ret = -EBUSY;
  9. else
  10. ret = __spi_async(spi, message);
  11. spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
  12. return ret;
  13. }

最后调用__spi_async

  1. static int __spi_async(struct spi_device *spi, struct spi_message *message)
  2. {
  3. struct spi_master *master = spi->master;
  4. /* Half-duplex links include original MicroWire, and ones with
  5. * only one data pin like SPI_3WIRE (switches direction) or where
  6. * either MOSI or MISO is missing.  They can also be caused by
  7. * software limitations.
  8. */
  9. if ((master->flags & SPI_MASTER_HALF_DUPLEX)
  10. || (spi->mode & SPI_3WIRE)) {
  11. struct spi_transfer *xfer;
  12. unsigned flags = master->flags;
  13. list_for_each_entry(xfer, &message->transfers, transfer_list) {
  14. if (xfer->rx_buf && xfer->tx_buf)
  15. return -EINVAL;
  16. if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)
  17. return -EINVAL;
  18. if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
  19. return -EINVAL;
  20. }
  21. }
  22. message->spi = spi;
  23. message->status = -EINPROGRESS;
  24. return master->transfer(spi, message);
  25. }

返回了master->transfer(spi, message);那么就是控制器里去工作了。

我用的是gpio模拟的spi,所以那用gpio模拟的那个控制器去看控制器的处理了。

先还是看一下probe函数

  1. static int __init spi_gpio_probe(struct platform_device *pdev)
  2. {
  3. int                        status;
  4. struct spi_master           *master;
  5. struct spi_gpio                     *spi_gpio;
  6. struct spi_gpio_platform_data       *pdata;
  7. u16 master_flags = 0;
  8. pdata = pdev->dev.platform_data;
  9. #ifdef GENERIC_BITBANG
  10. if (!pdata || !pdata->num_chipselect)
  11. return -ENODEV;
  12. #endif
  13. status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);
  14. if (status < 0)
  15. return status;
  16. master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio);
  17. if (!master) {
  18. status = -ENOMEM;
  19. goto gpio_free;
  20. }
  21. spi_gpio = spi_master_get_devdata(master);
  22. platform_set_drvdata(pdev, spi_gpio);
  23. spi_gpio->pdev = pdev;
  24. if (pdata)
  25. spi_gpio->pdata = *pdata;
  26. master->flags = master_flags;
  27. master->bus_num = pdev->id;
  28. master->num_chipselect = SPI_N_CHIPSEL;
  29. master->setup = spi_gpio_setup;
  30. master->cleanup = spi_gpio_cleanup;
  31. spi_gpio->bitbang.master = spi_master_get(master);
  32. spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
  33. if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {
  34. spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
  35. spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;
  36. spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;
  37. spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;
  38. } else {
  39. spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;
  40. spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;
  41. spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;
  42. spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3;
  43. }
  44. spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;
  45. spi_gpio->bitbang.flags = SPI_CS_HIGH;
  46. status = spi_bitbang_start(&spi_gpio->bitbang);
  47. if (status < 0) {
  48. spi_master_put(spi_gpio->bitbang.master);
  49. gpio_free:
  50. if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
  51. gpio_free(SPI_MISO_GPIO);
  52. if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
  53. gpio_free(SPI_MOSI_GPIO);
  54. gpio_free(SPI_SCK_GPIO);
  55. spi_master_put(master);
  56. }
  57. return status;
  58. }

主要看下下面三个函数

  1. spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
  2. spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;
  3. status = spi_bitbang_start(&spi_gpio->bitbang);

spi_gpio_txrx_word_mode0;就是最后调用到的先放一边,spi_bitbang_start,看一下这个函数

  1. int spi_bitbang_start(struct spi_bitbang *bitbang)
  2. {
  3. int   status;
  4. if (!bitbang->master || !bitbang->chipselect)
  5. return -EINVAL;
  6. INIT_WORK(&bitbang->work, bitbang_work);
  7. spin_lock_init(&bitbang->lock);
  8. INIT_LIST_HEAD(&bitbang->queue);
  9. if (!bitbang->master->mode_bits)
  10. bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
  11. if (!bitbang->master->transfer)
  12. bitbang->master->transfer = spi_bitbang_transfer;
  13. if (!bitbang->txrx_bufs) {
  14. bitbang->use_dma = 0;
  15. bitbang->txrx_bufs = spi_bitbang_bufs;
  16. if (!bitbang->master->setup) {
  17. if (!bitbang->setup_transfer)
  18. bitbang->setup_transfer =
  19. spi_bitbang_setup_transfer;
  20. bitbang->master->setup = spi_bitbang_setup;
  21. bitbang->master->cleanup = spi_bitbang_cleanup;
  22. }
  23. } else if (!bitbang->master->setup)
  24. return -EINVAL;
  25. if (bitbang->master->transfer == spi_bitbang_transfer &&
  26. !bitbang->setup_transfer)
  27. return -EINVAL;
  28. /* this task is the only thing to touch the SPI bits */
  29. bitbang->busy = 0;
  30. bitbang->workqueue = create_singlethread_workqueue(
  31. dev_name(bitbang->master->dev.parent));
  32. if (bitbang->workqueue == NULL) {
  33. status = -EBUSY;
  34. goto err1;
  35. }
  36. /* driver may get busy before register() returns, especially
  37. * if someone registered boardinfo for devices
  38. */
  39. status = spi_register_master(bitbang->master);
  40. if (status < 0)
  41. goto err2;
  42. return status;
  43. err2:
  44. destroy_workqueue(bitbang->workqueue);
  45. err1:
  46. return status;
  47. }

看到这个函数指针了吧:

  1. if (!bitbang->master->transfer)
  2. bitbang->master->transfer = spi_bitbang_transfer;

那么设备驱动调用的master->transfer(spi, message);就是调用到了spi_bitbang_transfer了,

  1. /**
  2. * spi_bitbang_transfer - default submit to transfer queue
  3. */
  4. int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
  5. {
  6. struct spi_bitbang   *bitbang;
  7. unsigned long        flags;
  8. int                 status = 0;
  9. m->actual_length = 0;
  10. m->status = -EINPROGRESS;
  11. bitbang = spi_master_get_devdata(spi->master);
  12. spin_lock_irqsave(&bitbang->lock, flags);
  13. if (!spi->max_speed_hz)
  14. status = -ENETDOWN;
  15. else {
  16. list_add_tail(&m->queue, &bitbang->queue);
  17. queue_work(bitbang->workqueue, &bitbang->work);
  18. }
  19. spin_unlock_irqrestore(&bitbang->lock, flags);
  20. return status;
  21. }

这里是把信息加到了bitbang->workqueue,然后在bitbang->work里处理

再来看下bitbang->work做了什么

  1. static void bitbang_work(struct work_struct *work)
  2. {
  3. struct spi_bitbang   *bitbang =
  4. container_of(work, struct spi_bitbang, work);
  5. unsigned long        flags;
  6. spin_lock_irqsave(&bitbang->lock, flags);
  7. bitbang->busy = 1;
  8. while (!list_empty(&bitbang->queue)) {
  9. struct spi_message  *m;
  10. struct spi_device     *spi;
  11. unsigned         nsecs;
  12. struct spi_transfer   *t = NULL;
  13. unsigned         tmp;
  14. unsigned         cs_change;
  15. int                 status;
  16. int                 do_setup = -1;
  17. m = container_of(bitbang->queue.next, struct spi_message,
  18. queue);
  19. list_del_init(&m->queue);
  20. spin_unlock_irqrestore(&bitbang->lock, flags);
  21. /* FIXME this is made-up ... the correct value is known to
  22. * word-at-a-time bitbang code, and presumably chipselect()
  23. * should enforce these requirements too?
  24. */
  25. nsecs = 100;
  26. spi = m->spi;
  27. tmp = 0;
  28. cs_change = 1;
  29. status = 0;
  30. list_for_each_entry (t, &m->transfers, transfer_list) {
  31. /* override speed or wordsize? */
  32. if (t->speed_hz || t->bits_per_word)
  33. do_setup = 1;
  34. /* init (-1) or override (1) transfer params */
  35. if (do_setup != 0) {
  36. status = bitbang->setup_transfer(spi, t);
  37. if (status < 0)
  38. break;
  39. if (do_setup == -1)
  40. do_setup = 0;
  41. }
  42. /* set up default clock polarity, and activate chip;
  43. * this implicitly updates clock and spi modes as
  44. * previously recorded for this device via setup().
  45. * (and also deselects any other chip that might be
  46. * selected ...)
  47. */
  48. if (cs_change) {
  49. bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
  50. ndelay(nsecs);
  51. }
  52. cs_change = t->cs_change;
  53. if (!t->tx_buf && !t->rx_buf && t->len) {
  54. status = -EINVAL;
  55. break;
  56. }
  57. /* transfer data.  the lower level code handles any
  58. * new dma mappings it needs. our caller always gave
  59. * us dma-safe buffers.
  60. */
  61. if (t->len) {
  62. /* REVISIT dma API still needs a designated
  63. * DMA_ADDR_INVALID; ~0 might be better.
  64. */
  65. if (!m->is_dma_mapped)
  66. t->rx_dma = t->tx_dma = 0;
  67. status = bitbang->txrx_bufs(spi, t);
  68. }
  69. if (status > 0)
  70. m->actual_length += status;
  71. if (status != t->len) {
  72. /* always report some kind of error */
  73. if (status >= 0)
  74. status = -EREMOTEIO;
  75. break;
  76. }
  77. status = 0;
  78. /* protocol tweaks before next transfer */
  79. if (t->delay_usecs)
  80. udelay(t->delay_usecs);
  81. if (!cs_change)
  82. continue;
  83. if (t->transfer_list.next == &m->transfers)
  84. break;
  85. /* sometimes a short mid-message deselect of the chip
  86. * may be needed to terminate a mode or command
  87. */
  88. ndelay(nsecs);
  89. bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
  90. ndelay(nsecs);
  91. }
  92. m->status = status;
  93. m->complete(m->context);
  94. /* normally deactivate chipselect ... unless no error and
  95. * cs_change has hinted that the next message will probably
  96. * be for this chip too.
  97. */
  98. if (!(status == 0 && cs_change)) {
  99. ndelay(nsecs);
  100. bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
  101. ndelay(nsecs);
  102. }
  103. spin_lock_irqsave(&bitbang->lock, flags);
  104. }
  105. bitbang->busy = 0;
  106. spin_unlock_irqrestore(&bitbang->lock, flags);
  107. }

当队列非空的时候就一直去取队列的数据,然后会执行到

  1. status = bitbang->setup_transfer(spi, t);

这个函数,因为在spi_bitbang_start中

  1. if (!bitbang->txrx_bufs) {
  2. bitbang->use_dma = 0;
  3. bitbang->txrx_bufs = spi_bitbang_bufs;
  4. if (!bitbang->master->setup) {
  5. if (!bitbang->setup_transfer)
  6. bitbang->setup_transfer =
  7. spi_bitbang_setup_transfer;
  8. bitbang->master->setup = spi_bitbang_setup;
  9. bitbang->master->cleanup = spi_bitbang_cleanup;
  10. }
  11. }

所以就调用了spi_bitbang_setup_transfer;

  1. int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
  2. {
  3. struct spi_bitbang_cs      *cs = spi->controller_state;
  4. u8                  bits_per_word;
  5. u32                hz;
  6. if (t) {
  7. bits_per_word = t->bits_per_word;
  8. hz = t->speed_hz;
  9. } else {
  10. bits_per_word = 0;
  11. hz = 0;
  12. }
  13. /* spi_transfer level calls that work per-word */
  14. if (!bits_per_word)
  15. bits_per_word = spi->bits_per_word;
  16. if (bits_per_word <= 8)
  17. cs->txrx_bufs = bitbang_txrx_8;
  18. else if (bits_per_word <= 16)
  19. cs->txrx_bufs = bitbang_txrx_16;
  20. else if (bits_per_word <= 32)
  21. cs->txrx_bufs = bitbang_txrx_32;
  22. else
  23. return -EINVAL;
  24. /* nsecs = (clock period)/2 */
  25. if (!hz)
  26. hz = spi->max_speed_hz;
  27. if (hz) {
  28. cs->nsecs = (1000000000/2) / hz;
  29. if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))
  30. return -EINVAL;
  31. }
  32. return 0;
  33. }

这里主要是根据bits_per_word选择传输的方式,分8、16,、32三种模式,ads7843touchscreen是用bits_per_word默认没有,选择bitbang_txrx_8的。

  1. static unsigned bitbang_txrx_8(
  2. struct spi_device     *spi,
  3. u32                (*txrx_word)(struct spi_device *spi,
  4. unsigned nsecs,
  5. u32 word, u8 bits),
  6. unsigned         ns,
  7. struct spi_transfer   *t
  8. ) {
  9. unsigned         bits = t->bits_per_word ? : spi->bits_per_word;
  10. unsigned         count = t->len;
  11. const u8         *tx = t->tx_buf;
  12. u8                  *rx = t->rx_buf;
  13. while (likely(count > 0)) {
  14. u8           word = 0;
  15. if (tx)
  16. word = *tx++;
  17. word = txrx_word(spi, ns, word, bits);
  18. if (rx)
  19. *rx++ = word;
  20. count -= 1;
  21. }
  22. return t->len - count;
  23. }

这里word = txrx_word(spi, ns, word, bits);会调用到哪里呢?,首先看下这个函数的指针指向哪里。

在spi_bitbang_start中,bitbang->master->setup = spi_bitbang_setup;

然后在spi_bitbang_setup 中有

  1. cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];

所以,这个最终还是调用到了spi_gpio.c文件中的spi_gpio_spec_txrx_word_mode0

  1. static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
  2. unsigned nsecs, u32 word, u8 bits)
  3. {
  4. unsigned flags = spi->master->flags;
  5. return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
  6. }

然后这个函数就调用了bitbang_txrx_be_cpha0,这个函数在spi-bitbang-txrx.h中

  1. static inline u32
  2. bitbang_txrx_be_cpha0(struct spi_device *spi,
  3. unsigned nsecs, unsigned cpol, unsigned flags,
  4. u32 word, u8 bits)
  5. {
  6. /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
  7. /* clock starts at inactive polarity */
  8. for (word <<= (32 - bits); likely(bits); bits--) {
  9. /* setup MSB (to slave) on trailing edge */
  10. if ((flags & SPI_MASTER_NO_TX) == 0)
  11. setmosi(spi, word & (1 << 31));
  12. spidelay(nsecs);      /* T(setup) */
  13. setsck(spi, !cpol);
  14. spidelay(nsecs);
  15. /* sample MSB (from slave) on leading edge */
  16. word <<= 1;
  17. if ((flags & SPI_MASTER_NO_RX) == 0)
  18. word |= getmiso(spi);
  19. setsck(spi, cpol);
  20. }
  21. return word;
  22. }

这里就是gpio模拟的spi总线的协议过程了。这样,从最上面设备程序调用到控制器的整个数据流就结束了。

注:这里有一个很恶心的东东,就是在bitbang_txrx_16,bitbang_txrx_32中的

  1. const u8         *tx = t->tx_buf;
  2. u8                  *rx = t->rx_buf;

这里是强制转换的,由于大小端的问题,可能导致数据相反,从而传输会出现问题的,如果是8bit的,那么就没有任何问题了。

一段小插曲,也是用逻辑分析仪抓到的数据才发现的,如果没有这玩意儿,估计现在还纠结着。

OK,至此,linux的SPI的数据传输就到这里了。

和菜鸟一起学linux总线驱动之初识spi驱动数据传输流程【转】的更多相关文章

  1. 和菜鸟一起学linux总线驱动之i2c死锁问题

    不知不觉中已经有好几个月没有写点东西了,懒了就是懒了,说是忙着想把产品做得更好,都是借口,每天花一点时间来写点东西确实很不错,自己也坚持了很久很久,只不过今年以来,发现提高不是很大,能写的东西好少好少 ...

  2. linux总线、设备和设备驱动的关系

    之一:bus_type 总线是处理器和一个或多个设备之间的通道,在设备模型中,所有的设备都通过总线相连,甚至是内部的虚拟"platform"总线.可以通过ls -l /sys/bu ...

  3. 和菜鸟一起学linux之DBUS基础学习记录

    D-Bus三层架构 D-Bus是一个为应用程序间通信的消息总线系统, 用于进程之间的通信.它是个3层架构的IPC 系统,包括: 1.函数库libdbus ,用于两个应用程序互相联系和交互消息. 2.一 ...

  4. 【转】和菜鸟一起学linux之DBUS基础学习记录

    [原文] D-Bus三层架构 D-Bus是一个为应用程序间通信的消息总线系统, 用于进程之间的通信.它是个3层架构的IPC 系统,包括: 1.函数库libdbus ,用于两个应用程序互相联系和交互消息 ...

  5. 和菜鸟一起学linux之DBUS基础学习记录(转)

    转自:https://www.cnblogs.com/wuyida/p/6299998.html D-Bus三层架构 D-Bus是一个为应用程序间通信的消息总线系统, 用于进程之间的通信.它是个3层架 ...

  6. 和菜鸟一起学linux之upnp协议的学习记录

    UPnP全名是Universal Plug and Play,主要是微软在推行的一个标准.简单的来说,UPnP 最大的愿景就是希望任何设备只要一接上网络,所有在网络上的设备马上就能知道有新设备加入,这 ...

  7. 和菜鸟一起学linux内核源码之基础准备篇

    来源:http://blog.csdn.net/eastmoon502136/article/details/8711104 推荐阅读:linux内核源码最初版linux内核源代码,简单易懂,适合初学 ...

  8. 和菜鸟一起学linux之V4L2摄像头应用流程【转】

    转自:http://blog.csdn.net/eastmoon502136/article/details/8190262/ 上篇文章,知道了,C代码编译后存放在内存中的位置,那么C代码的整个编译过 ...

  9. 和菜鸟一起学linux内核源码之基础准备篇 系列 体系结构图

    http://blog.csdn.net/eastmoon502136/article/details/8711104

随机推荐

  1. Power-BI仪表盘文本框排行分析设计要点

    例如:我在BI软件中做一个商品类别TOP5排行. 文本框默认绑定第一列,但是没显示是那个品类. 这里我们需要做几个操作来进行优化. 1.把品类显示出来. 在序列中找到标题进行显示,如果位置有重叠可以进 ...

  2. linux操作技巧

    1. 打开终端 ctrl+ALT+T  新终端 ctrl+shift+T  原有终端新页面 2.  忘记root密码  redhat下 单用户进入grub 在核心文件后加"single&qu ...

  3. iOS - (集成支付宝SDK大坑总结)

    其实集成支付宝相对于集成微信支付来说,支付宝算是简单的了,后续有空再去研究微信支付,现目前先总结一下集成支付宝所遇到的坑,其实支付宝的坑也不算太多,细算下来大概5-6个左右,但是其报错方式有点恶心,不 ...

  4. mysql 启动服务

    http://blog.chinaunix.net/uid-13642598-id-3153537.html mysql的四种启动方式: 1.mysqld 启动mysql服务器:./mysqld -- ...

  5. MyEclipse6.5注册码(转)

    新装的MyEclipse6.5在网上找了半天的注册码,都不可用.将下面的代码放在MyEclipse下运行后,可以得到注册码.这相当于一个注册机.我得到的如下: administrator nLR8ZC ...

  6. 连接sql server数据库的两种方式

    class DB     { private static SqlConnection conn; public static SqlConnection getConn() { //conn = n ...

  7. Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-5-6 踩踏平台是怎么炼成的

    在游戏中,有很多分来飞去的平台,这个平台长短不一.如果每种长度都去创建一张图片那是比较繁琐的事情.实际上,我们只用到3张图.分别是平台的,平台的中间部分,平台的右边.关键是平台的中间部分,两张中间部分 ...

  8. [reprint]malloc与calloc的区别

    [http://blog.163.com/crazy20070501@126/] 转自某自由人的博客: malloc与calloc的区别 函数malloc()和calloc()都可以用来动态分配内存空 ...

  9. SQL面向对象抽象类

    抽象类:抽象类,只为继承而出现,不定义具体的内容,只规定该有哪些东西:一般抽象类中只放置抽象方法,只规定了返回类型和参数:例: 人 - 有吃饭,睡觉方法: 男人 - 继承人抽象类,必须实现吃饭,睡觉的 ...

  10. android 测试(转)

    个人接触android的时间也不是很长,稍微总结下在做Android测试的过程中,初次接触的同学需要些什么准备,以及需要些什么知识?下面讲到的东西可能很多人会觉得很简单,但我确实碰到过有新同学对这些点 ...