Linuxデバイス駆動プロファイリングのSPI(四)

42154 ワード

781行の前には何も言うことはありません.783行を直接見て、ワークキューにワークを投入して、戻って、ここで前になぜ非同期だったのかという質問に答えることができます.その後、ある適切な時間にCPUがこのworkで指定した関数を実行します.ここではs 3 c 64 xx_spi_work関数、定義を見てください.
00000723 static void s3c64xx_spi_work(struct work_struct *work)
00000724 {
00000725     struct s3c64xx_spi_driver_data *sdd = container_of(work,
00000726                     struct s3c64xx_spi_driver_data, work);
00000727     unsigned long flags;
00000728 
00000729     /* Acquire DMA channels */
00000730     while (!acquire_dma(sdd))
00000731         msleep(10);
00000732 
00000733     spin_lock_irqsave(&sdd->lock, flags);
00000734 
00000735     while (!list_empty(&sdd->queue)
00000736                 && !(sdd->state & SUSPND)) {
00000737 
00000738         struct spi_message *msg;
00000739 
00000740         msg = container_of(sdd->queue.next, struct spi_message, queue);
00000741 
00000742         list_del_init(&msg->queue);
00000743 
00000744         /* Set Xfer busy flag */
00000745         sdd->state |= SPIBUSY;
00000746 
00000747         spin_unlock_irqrestore(&sdd->lock, flags);
00000748 
00000749         handle_msg(sdd, msg);
00000750 
00000751         spin_lock_irqsave(&sdd->lock, flags);
00000752 
00000753         sdd->state &= ~SPIBUSY;
00000754     }
00000755 
00000756     spin_unlock_irqrestore(&sdd->lock, flags);
00000757 
00000758     /* Free DMA channels */
00000759     s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client);
00000760     s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
00000761 }

730行、DMAを申請して、DMAのについて言わないで、1つは私がDMAに対して何も理解していないので、2つはここが基本的に使えないので、後でいつDMAを使うことができることを知っています.
735~754行、キュー内のメッセージをループして取り出し、749行のhandle_を呼び出すmsg関数処理、handle_msg関数の定義は次のとおりです.
00000568 static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
00000569                     struct spi_message *msg)
00000570 {
00000571     struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
00000572     struct spi_device *spi = msg->spi;
00000573     struct s3c64xx_spi_csinfo *cs = spi->controller_data;
00000574     struct spi_transfer *xfer;
00000575     int status = 0, cs_toggle = 0;
00000576     u32 speed;
00000577     u8 bpw;
00000578 
00000579     /* If Master's(controller) state differs from that needed by Slave */
00000580     if (sdd->cur_speed != spi->max_speed_hz
00000581             || sdd->cur_mode != spi->mode
00000582             || sdd->cur_bpw != spi->bits_per_word) {
00000583         sdd->cur_bpw = spi->bits_per_word;
00000584         sdd->cur_speed = spi->max_speed_hz;
00000585         sdd->cur_mode = spi->mode;
00000586         s3c64xx_spi_config(sdd);
00000587     }
00000588 
00000589     /* Map all the transfers if needed */
00000590     if (s3c64xx_spi_map_mssg(sdd, msg)) {
00000591         dev_err(&spi->dev,
00000592             "Xfer: Unable to map message buffers!
"); 00000593 status = -ENOMEM; 00000594 goto out; 00000595 } 00000596 00000597 /* Configure feedback delay */ 00000598 writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK); 00000599 00000600 list_for_each_entry(xfer, &msg->transfers, transfer_list) { 00000601 00000602 unsigned long flags; 00000603 int use_dma; 00000604 00000605 INIT_COMPLETION(sdd->xfer_completion); 00000606 00000607 /* Only BPW and Speed may change across transfers */ 00000608 bpw = xfer->bits_per_word ? : spi->bits_per_word; 00000609 speed = xfer->speed_hz ? : spi->max_speed_hz; 00000610 00000611 if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { 00000612 sdd->cur_bpw = bpw; 00000613 sdd->cur_speed = speed; 00000614 s3c64xx_spi_config(sdd); 00000615 } 00000616 00000617 /* Polling method for xfers not bigger than FIFO capacity */ 00000618 00000619 if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1)) 00000620 use_dma = 0; 00000621 else 00000622 use_dma = 1; 00000623 00000624 spin_lock_irqsave(&sdd->lock, flags); 00000625 00000626 /* Pending only which is to be done */ 00000627 sdd->state &= ~RXBUSY; 00000628 sdd->state &= ~TXBUSY; 00000629 00000630 enable_datapath(sdd, spi, xfer, use_dma); 00000631 00000632 /* Slave Select */ 00000633 enable_cs(sdd, spi); 00000634 00000635 /* Start the signals */ 00000636 S3C64XX_SPI_ACT(sdd); 00000637 00000638 spin_unlock_irqrestore(&sdd->lock, flags); 00000639 00000640 status = wait_for_xfer(sdd, xfer, use_dma); 00000641 00000642 /* Quiese the signals */ 00000643 S3C64XX_SPI_DEACT(sdd); 00000644 00000645 if (status) { 00000646 dev_err(&spi->dev, "I/O Error: " 00000647 "rx-%d tx-%d res:rx-%c tx-%c len-%d
", 00000648 xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0, 00000649 (sdd->state & RXBUSY) ? 'f' : 'p', 00000650 (sdd->state & TXBUSY) ? 'f' : 'p', 00000651 xfer->len); 00000652 00000653 if (use_dma) { 00000654 if (xfer->tx_buf != NULL 00000655 && (sdd->state & TXBUSY)) 00000656 s3c2410_dma_ctrl(sdd->tx_dmach, 00000657 S3C2410_DMAOP_FLUSH); 00000658 if (xfer->rx_buf != NULL 00000659 && (sdd->state & RXBUSY)) 00000660 s3c2410_dma_ctrl(sdd->rx_dmach, 00000661 S3C2410_DMAOP_FLUSH); 00000662 } 00000663 00000664 goto out; 00000665 } 00000666 00000667 if (xfer->delay_usecs) 00000668 udelay(xfer->delay_usecs); 00000669 00000670 if (xfer->cs_change) { 00000671 /* Hint that the next mssg is gonna be 00000672 for the same device */ 00000673 if (list_is_last(&xfer->transfer_list, 00000674 &msg->transfers)) 00000675 cs_toggle = 1; 00000676 else 00000677 disable_cs(sdd, spi); 00000678 } 00000679 00000680 msg->actual_length += xfer->len; 00000681 00000682 flush_fifo(sdd); 00000683 } 00000684 00000685 out: 00000686 if (!cs_toggle || status) 00000687 disable_cs(sdd, spi); 00000688 else 00000689 sdd->tgl_spi = spi; 00000690 00000691 s3c64xx_spi_unmap_mssg(sdd, msg); 00000692 00000693 msg->status = status; 00000694 00000695 if (msg->complete) 00000696 msg->complete(msg->context); 00000697 }

関数は長い580行から587行で、speed、bpw、modeの値がspiデバイスと一致しない場合、s 3 c 64 xx_が呼び出されます.spi_config関数再構成,s 3 c 64 xx_spi_config関数にはSPIレジスタが設定されています.
590〜595行、DMAマッピングについては、省略する.
598行、feedbackレジスタを設定します.
600行、各transferを巡ります.605行、また1つの完了量を初期化して、ここでは前の完了量とは異なることに注意して、ここでの完了量はDMA伝送を使う時だけ使えて、次はすぐに見ることができます.
608行から615行は、設定値に関するいくつかのチェックでもあります.
619~622行で、fifoの深さ(ここでは64バイト)よりも長いデータのみを送信または受信してuse_を設定します.dmaは1、すなわちDMAを用いて伝送され、そうでなければDMAは用いられない.
630行、enable_Datapath関数の定義は、次のとおりです.
00000232 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
00000233                 struct spi_device *spi,
00000234                 struct spi_transfer *xfer, int dma_mode)
00000235 {
00000236     struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
00000237     void __iomem *regs = sdd->regs;
00000238     u32 modecfg, chcfg;
00000239 
00000240     modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
00000241     modecfg&=~(S3C64XX_SPI_MODE_TXDMA_ON|S3C64XX_SPI_MODE_RXDMA_ON);
00000242 
00000243     chcfg = readl(regs + S3C64XX_SPI_CH_CFG);
00000244     chcfg &= ~S3C64XX_SPI_CH_TXCH_ON;
00000245 
00000246     if (dma_mode) {
00000247         chcfg &= ~S3C64XX_SPI_CH_RXCH_ON;
00000248     } else {
00000249         /* Always shift in data in FIFO, even if xfer is Tx only,
00000250          * this helps setting PCKT_CNT value for generating clocks
00000251          * as exactly needed.
00000252          */
00000253         chcfg |= S3C64XX_SPI_CH_RXCH_ON;
00000254         writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
00000255                     | S3C64XX_SPI_PACKET_CNT_EN,
00000256                     regs + S3C64XX_SPI_PACKET_CNT);
00000257     }
00000258 
00000259     if (xfer->tx_buf != NULL) {
00000260         sdd->state |= TXBUSY;
00000261         chcfg |= S3C64XX_SPI_CH_TXCH_ON;
00000262         if (dma_mode) {
00000263             modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
00000264             s3c2410_dma_config(sdd->tx_dmach, 1);
00000265             s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
00000266                         xfer->tx_dma, xfer->len);
00000267             s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
00000268         } else {
00000269             unsigned char *buf = (unsigned char *) xfer->tx_buf;
00000270             int i = 0;
00000271             while (i < xfer->len)
00000272                 writeb(buf[i++], regs + S3C64XX_SPI_TX_DATA);
00000273         }
00000274     }
00000275 
00000276     if (xfer->rx_buf != NULL) {
00000277         sdd->state |= RXBUSY;
00000278 
00000279         if (sci->high_speed && sdd->cur_speed >= 30000000UL
00000280                     && !(sdd->cur_mode & SPI_CPHA))
00000281             chcfg |= S3C64XX_SPI_CH_HS_EN;
00000282 
00000283         if (dma_mode) {
00000284             modecfg |= S3C64XX_SPI_MODE_RXDMA_ON;
00000285             chcfg |= S3C64XX_SPI_CH_RXCH_ON;
00000286             writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
00000287                     | S3C64XX_SPI_PACKET_CNT_EN,
00000288                     regs + S3C64XX_SPI_PACKET_CNT);
00000289             s3c2410_dma_config(sdd->rx_dmach, 1);
00000290             s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
00000291                         xfer->rx_dma, xfer->len);
00000292             s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
00000293         }
00000294     }
00000295 
00000296     writel(modecfg, regs + S3C64XX_SPI_MODE_CFG);
00000297     writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
00000298 }

240~244行、読み出しモード構成およびチャネル構成レジスタ.
246乃至257行は、DMAモードを採用するか否かに応じて受信カウントレジスタを設定する.
259行、早くもtx_bufはメモリを割り当てるため、条件が成立します.DMAモードを考慮しないため、262〜268行を省略する.
269~272行で、送信データを送信レジスタにループして書き込む.
276~294行、rx_bufはNULLなので、277~294行を直接省略します.
296、297行で、前の値をレジスタに書き込む.
handleに戻るmsg関数、633行、スレーブデバイスを選択します.636行、レジスタを設定し、データ転送を開始します.
640行、wait_for_xfer関数の定義:
00000319 static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
00000320                 struct spi_transfer *xfer, int dma_mode)
00000321 {
00000322     struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
00000323     void __iomem *regs = sdd->regs;
00000324     unsigned long val;
00000325     int ms;
00000326 
00000327     /* millisecs to xfer 'len' bytes @ 'cur_speed' */
00000328     ms = xfer->len * 8 * 1000 / sdd->cur_speed;
00000329     ms += 10; /* some tolerance */
00000330 
00000331     if (dma_mode) {
00000332         val = msecs_to_jiffies(ms) + 10;
00000333         val = wait_for_completion_timeout(&sdd->xfer_completion, val);
00000334     } else {
00000335         u32 status;
00000336         val = msecs_to_loops(ms);
00000337         do {
00000338             status = readl(regs + S3C64XX_SPI_STATUS);
00000339         } while (RX_FIFO_LVL(status, sci) < xfer->len && --val);
00000340     }
00000341 
00000342     if (!val)
00000343         return -EIO;
00000344 
00000345     if (dma_mode) {
00000346         u32 status;
00000347 
00000348         /*
00000349          * DmaTx returns after simply writing data in the FIFO,
00000350          * w/o waiting for real transmission on the bus to finish.
00000351          * DmaRx returns only after Dma read data from FIFO which
00000352          * needs bus transmission to finish, so we don't worry if
00000353          * Xfer involved Rx(with or without Tx).
00000354          */
00000355         if (xfer->rx_buf == NULL) {
00000356             val = msecs_to_loops(10);
00000357             status = readl(regs + S3C64XX_SPI_STATUS);
00000358             while ((TX_FIFO_LVL(status, sci)
00000359                 || !S3C64XX_SPI_ST_TX_DONE(status, sci))
00000360                     && --val) {
00000361                 cpu_relax();
00000362                 status = readl(regs + S3C64XX_SPI_STATUS);
00000363             }
00000364 
00000365             if (!val)
00000366                 return -EIO;
00000367         }
00000368     } else {
00000369         unsigned char *buf;
00000370         int i;
00000371 
00000372         /* If it was only Tx */
00000373         if (xfer->rx_buf == NULL) {
00000374             sdd->state &= ~TXBUSY;
00000375             return 0;
00000376         }
00000377 
00000378         i = 0;
00000379         buf = xfer->rx_buf;
00000380         while (i < xfer->len)
00000381             buf[i++] = readb(regs + S3C64XX_SPI_RX_DATA);
00000382 
00000383         sdd->state &= ~RXBUSY;
00000384     }
00000385 
00000386     return 0;
00000387 }

328行で、送信レートから待ち時間を計算します.331~334行、DMAに関するもの、省略.
335〜339行は状態レジスタを読み続け、受信したデータ長が送信データの長さまたはタイムアウトに等しい場合にループを終了する.
342、343行で、タイムアウトしてループを終了した場合、エラーが返されます.
345~368行、DMA関連、省略.
369~383行、データ送信のみの場合は0を返します.そうでなければ受信レジスタから受信したデータを読み出します.
handleに戻るmsg関数、643行、転送を停止します.645~665行、前のwait_for_xfer関数は0より大きい値を返すとエラーを示し、ここでいくつかの情報を印刷します.
667、668行、前に遅延が設定されていたらここで遅延します.
670〜678行で、transferの完了ごとにスライス信号を変更する必要があるかどうか.
680行で、transferが正常に送信したデータをすべて加算します.
682行、送受信レジスタをクリアします.
691行、DMAマッピングをキャンセルします.
693行、ステータス情報を記録します.
695、696行、起動前に待機していた完了量.
ここまで、writeプロセス全体を話していたので、大変でしたね!の他のread/ioctlプロセスは大同小異である.
 
まとめ
      spidev.cは汎用的なSPI駆動であるため、特定の駆動に関する論理は一切処理されず、ユーザ空間で特定の論理を完了する必要がある.実はこれはAndroid駆動の思想に合っていて、これもAndroid HAL層の存在の目的です:カーネル駆動はハードウェアの操作だけを完成して、具体的な論理はHAL層に置いて、このようにメーカー、開発者の知的財産権を保護するのに有利です.
ユーザースペースでioctlを使用するとwrite、read操作が完了します.