ºìÁªLinuxÃÅ»§
Linux°ïÖú

ÔÚLinux²Ù×÷ϵͳÖжÔISA×ÜÏßDMAµÄʵÏÖ·½·¨¶þ

·¢²¼Ê±¼ä:2006-11-30 09:48:14À´Ô´:ºìÁª×÷Õß:Emperor
¡¡¡¡3 Linux¶Ô¶Áд²Ù×÷8237 DMACµÄʵÏÖ

¡¡¡¡ÓÉÓÚDMACµÄ¸÷¼Ä´æÆ÷ÊÇÔÚI/O¶Ë¿Ú¿Õ¼äÖбàÖ·µÄ£¬Òò´Ë¶Áд8237 DMACÊÇÆ½Ì¨Ïà¹ØµÄ¡£¶ÔÓÚx86ƽ̨À´Ëµ£¬LinuxÔÚinclude£¯asm-i386£¯Dma.hÍ·ÎļþÖÐʵÏÖÁ˶ÔÁ½¸ö8237 DMACµÄ¶Áд²Ù×÷¡£

¡¡¡¡3£®1 ¶Ë¿ÚµØÖ·ºÍ¼Ä´æÆ÷ÖµµÄºê¶¨Òå

¡¡¡¡LinuxÓúêMAX_DMA_CHANNELSÀ´±íʾϵͳµ±Ç°µÄDMAͨµÀ¸öÊý£¬ÈçÏ£º

ÒýÓÃ:
#define MAX_DMA_CHANNELS 8


¡¡¡¡È»ºó£¬ÓúêIO_DMA1_BASEºÍIO_DMA2_BASEÀ´·Ö±ð±íʾÁ½¸öDMACÔÚI/O¶Ë¿Ú¿Õ¼äµÄ¶Ë¿Ú»ùµØÖ·£º

ÒýÓÃ:
#define IO_DMA1_BASE 0x00
¡¡¡¡¡¡¡¡/* 8 bit slave DMA, channels 0..3 */
¡¡¡¡#define IO_DMA2_BASE 0xC0
¡¡¡¡¡¡¡¡/* 16 bit master DMA, ch 4(=slave input)..7 */


¡¡¡¡½ÓÏÂÀ´£¬Linux¶¨ÒåÁËDMAC¸÷¿ØÖƼĴæÆ÷µÄ¶Ë¿ÚµØÖ·¡£ÆäÖУ¬slave SMACµÄ¸÷¿ØÖƼĴæÆ÷µÄ¶Ë¿ÚµØÖ·¶¨ÒåÈçÏ£º

ÒýÓÃ:
#define DMA1_CMD_REG 0x08 /* command register (w) */
#define DMA1_STAT_REG 0x08 /* status register (r) */
#define DMA1_REQ_REG 0x09 /* request register (w) */
#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
#define DMA1_MODE_REG 0x0B /* mode register (w) */
#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */


¡¡¡¡Master DMACµÄ¸÷¿ØÖƼĴæÆ÷µÄ¶Ë¿ÚµØÖ·¶¨ÒåÈçÏ£º

ÒýÓÃ:
#define DMA2_CMD_REG 0xD0 /* command register (w) */
#define DMA2_STAT_REG 0xD0 /* status register (r) */
#define DMA2_REQ_REG 0xD2 /* request register (w) */
#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
#define DMA2_MODE_REG 0xD6 /* mode register (w) */
#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */


¡¡¡¡8¸öDMAͨµÀµÄAddress RegisterµÄ¶Ë¿ÚµØÖ·¶¨ÒåÈçÏ£º

ÒýÓÃ:
#define DMA_ADDR_0 0x00 /* DMA address registers */
#define DMA_ADDR_1 0x02
#define DMA_ADDR_2 0x04
#define DMA_ADDR_3 0x06
#define DMA_ADDR_4 0xC0
#define DMA_ADDR_5 0xC4
#define DMA_ADDR_6 0xC8
#define DMA_ADDR_7 0xCC


¡¡¡¡8¸öDMAͨµÀµÄCount RegisterµÄ¶Ë¿ÚµØÖ·¶¨ÒåÈçÏ£º

ÒýÓÃ:
#define DMA_CNT_0 0x01 /* DMA count registers */
#define DMA_CNT_1 0x03
#define DMA_CNT_2 0x05
#define DMA_CNT_3 0x07
#define DMA_CNT_4 0xC2
#define DMA_CNT_5 0xC6
#define DMA_CNT_6 0xCA
#define DMA_CNT_7 0xCE


¡¡¡¡8¸öDMAͨµÀµÄPage RegisterµÄ¶Ë¿ÚµØÖ·¶¨ÒåÈçÏ£º

ÒýÓÃ:
#define DMA_PAGE_0 0x87 /* DMA page registers */
#define DMA_PAGE_1 0x83
#define DMA_PAGE_2 0x81
#define DMA_PAGE_3 0x82
#define DMA_PAGE_5 0x8B
#define DMA_PAGE_6 0x89
#define DMA_PAGE_7 0x8A


¡¡¡¡Mode RegisterµÄ¼¸¸ö³£ÓÃÖµµÄ¶¨ÒåÈçÏ£º

ÒýÓÃ:
#define DMA_MODE_READ 0x44
¡¡¡¡/* I/O to memory, no autoinit, increment, single mode */
¡¡¡¡#define DMA_MODE_WRITE 0x48
¡¡¡¡/* memory to I/O, no autoinit, increment, single mode */
¡¡¡¡#define DMA_MODE_CASCADE 0xC0
¡¡¡¡ /* pass thru DREQ->HRQ, DACK<-HLDA only */
¡¡¡¡#define DMA_AUTOINIT 0x10
ÎÄÕÂÆÀÂÛ

¹²ÓÐ 2 ÌõÆÀÂÛ

  1. Emperor ÓÚ 2006-11-30 09:50:28·¢±í:

    ¡¡¡¡£¨4£©ÎªDMAͨµÀÉèÖÃDMA»º³åÇøµÄÆðʼÎïÀíµØÖ·ºÍ´óС

    ¡¡¡¡ÓÉÓÚ8237ÖеÄDMAͨµÀÊÇͨ¹ýÒ»¸ö8λµÄPage RegisterºÍÒ»¸ö16λµÄAddress RegisterÀ´Ñ°Ö·Î»ÓÚϵͳRAMÖеÄDMA»º³åÇø£¬Òò´Ë8237 DMAC×î´óÖ»ÄÜѰַϵͳRAMÖÐÎïÀíµØÖ·ÔÚ0x000000¡«0xffffff·¶Î§ÄÚµÄDMA»º³åÇø£¬Ò²¼´Ö»ÄÜѰַÎïÀíÄÚ´æµÄµÍ16MB£¨24λÎïÀíµØÖ·£©¡£·´¹ýÀ´½²£¬Slave£¯Master 8237 DMACÓÖÊÇÈçºÎѰַµÍ16MBÖеÄÎïÀíÄÚ´æµ¥ÔªµÄÄØ£¿

    ¡¡¡¡Ê×ÏÈÀ´¿´Slave 8237 DMAC£¨¼´µÚÒ»¸ö8237 DMAC£©¡£ÓÉÓÚSlave 8237 DMACÊÇÒ»¸ö8λµÄDMAC£¬Òò´ËDMAͨµÀ0¡«3ÔÚÒ»´ÎDMA´«Êä²Ù×÷£¨Ò»¸öDMA´«ÊäÊÂÎñÓÖ¶à´ÎDMA´«Êä²Ù×÷×é³É£©ÖÐÖ»ÄÜ´«Êä8λÊý¾Ý£¬¼´Ò»¸ö×Ö½Ú¡£Slave 8237 DMAC½«µÍ16MBÎïÀíÄÚ´æ·Ö³É256¸ö64K´óСµÄÒ³£¨Page£©£¬È»ºóÓÃPage RegisterÀ´±íʾÄÚ´æµ¥ÔªÎïÀíµØÖ·µÄ¸ß8루bit£Û23£º16£Ý£©£¬Ò²¼´Ò³ºÅ£»ÓÃAddress RegisterÀ´±íʾÄÚ´æµ¥ÔªÎïÀíµØÖ·ÔÚÒ»¸öPage£¨64KB´óС£©ÄÚµÄÒ³ÄÚÆ«ÒÆÁ¿£¬Ò²¼´24λÎïÀíµØÖ·ÖеĵÍ16루bit£Û15£º0£Ý£©¡£ÓÉÓÚÕâÖÖѰַ»úÖÆ£¬Òò´ËDMAͨµÀ0¡«3µÄDMA»º³åÇø±ØÐëÔÚÒ»¸öPageÖ®ÄÚ£¬Ò²¼´DMA»º³åÇø²»ÄÜ¿çÔ½64KBÒ³±ß½ç¡£

    ¡¡¡¡ÔÙÀ´¿´¿´Master 8237 DMAC£¨¼´µÚ¶þ¸ö8237 DMAC£©¡£ÕâÊÇÒ»¸ö16λ¿íµÄDMAC£¬Òò´ËDMAͨµÀ5¡«7ÔÚÒ»´ÎDMA´«Êä²Ù×÷ʱ¿ÉÒÔ´«Êä16λÊý¾Ý£¬Ò²¼´Ò»¸ö×Öword¡£´ËʱDMAͨµÀµÄCount Register£¨16λ¿í£©±íʾÒÔ×ּƵĴý´«ÊäÊý¾Ý¿é´óС£¬Òò´ËÊý¾Ý¿é×î´ó¿É´ï128KB£¨64K¸ö×Ö£©£¬Ò²¼´ÏµÍ³RAMÖеÄDMA»º³åÇø×î´ó¿É´ï128KB¡£ÓÉÓÚÒ»´Î¿É´«ÊäÒ»¸ö×Ö£¬Òò´ËMaster 8237 DMACËùѰַµÄÄÚ´æµ¥ÔªµÄÎïÀíµØÖ·¿Ï¶¨ÊÇżÊý£¬Ò²¼´ÎïÀíµØÖ·µÄbit£Û0£Ý¿Ï¶¨Îª0¡£´ËʱÎïÀíÄÚ´æµÄµÍ16MB±»»¯·Ö³É128¸ö128KB´óСµÄpage£¬Page RegisterÖеÄbit£Û7£º1£ÝÓÃÀ´±íʾҳºÅ£¬Ò²¼´¶ÔÓ¦ÄÚ´æµ¥ÔªÎïÀíµØÖ·µÄbit£Û23£º17£Ý£¬¶øPage RegisterµÄbit£Û0£Ý×ÜÊDZ»ÉèÖÃΪ0¡£Address RegisterÓÃÀ´±íʾÄÚ´æµ¥ÔªÔÚ128KB´óСµÄPageÖеÄÒ³ÄÚÆ«ÒÆ£¬Ò²¼´¶ÔÓ¦ÄÚ´æµ¥ÔªÎïÀíµØÖ·µÄbit£Û16£º1£Ý£¨ÓÉÓÚ´ËʱÎïÀíµØÖ·µÄbit£Û0£Ý×ÜÊÇΪ0£¬Òò´Ë²»ÐèÒª±íʾ£©¡£ÓÉÓÚMaster 8237 DMACµÄÕâÖÖѰַ»úÖÆ£¬Òò´ËDMAͨµÀ5¡«7µÄDMA»º³åÇø²»ÄÜ¿çÔ½128KBµÄÒ³±ß½ç¡£

    ¡¡¡¡ÏÂÃæÎÒÃÇÀ´¿´¿´LinuxÊÇÈçºÎʵÏÖΪ¸÷DMAͨµÀÉèÖÃÆäPage¼Ä´æÆ÷µÄ¡£NOTE£¡DMAͨµÀ5¡«7µÄPage RegisterÖеÄbit£Û0£Ý×ÜÊÇΪ0¡£ÈçÏÂËùʾ£º

    ÒýÓÃ:
    static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
    {
    switch(dmanr) {
    case 0:
    dma_outb(pagenr, DMA_PAGE_0);
    break;
    case 1:
    dma_outb(pagenr, DMA_PAGE_1);
    break;
    case 2:
    dma_outb(pagenr, DMA_PAGE_2);
    break;
    case 3:
    dma_outb(pagenr, DMA_PAGE_3);
    break;
    case 5:
    dma_outb(pagenr & 0xfe, DMA_PAGE_5);
    break;
    case 6:
    dma_outb(pagenr & 0xfe, DMA_PAGE_6);
    break;
    case 7:
    dma_outb(pagenr & 0xfe, DMA_PAGE_7);
    break;
    }
    }


    ¡¡¡¡ÔÚÉÏÊöº¯ÊýµÄ»ù´¡ÉÏ£¬º¯Êýset_dma_addr()ÓÃÀ´ÎªÌض¨DMAͨµÀÉèÖÃDMA»º³åÇøµÄ»ùµØÖ·£¬´«ÊädmanrÖ¸¶¨DMAͨµÀºÅ£¬´«ÊäaÖ¸¶¨Î»ÓÚϵͳRAMÖеÄDMA»º³åÇøÆðʼλÖõÄÎïÀíµØÖ·¡£ÈçÏ£º

    ÒýÓÃ:
    /* Set transfer address & page bits for specific DMA channel.
    * Assumes dma flipflop is clear.
    */
    static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
    {
    set_dma_page(dmanr, a>>16);
    if (dmanr <= 3) {
    dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
    dma_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
    } else {
    dma_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
    dma_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
    }
    }


    ¡¡¡¡º¯Êýset_dma_count()ÎªÌØ¶¨DMAͨµÀÉèÖÃÆäCount RegisterµÄÖµ¡£´«ÊädmanrÖ¸¶¨DMAͨµÀ£¬´«ÊäcountÖ¸¶¨´ý´«ÊäµÄÊý¾Ý¿é´óС£¨ÒÔ×ֽڼƣ©£¬Êµ¼Êдµ½Count RegisterÖеÄÖµÓ¦¸ÃÊÇcount£­1¡£ÈçÏÂËùʾ£º

    ÒýÓÃ:
    static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
    {
    count--;
    if (dmanr <= 3) {
    dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
    dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
    } else {
    dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
    dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
    }
    }


    ¡¡¡¡º¯Êýget_dma_residue()»ñȡij¸öDMAͨµÀÉϵ±Ç°DMA´«ÊäÊÂÎñµÄδ´«ÊäÊ£ÓàÊý¾Ý¿éµÄ´óС£¨ÒÔ×ֽڼƣ©¡£DMAͨµÀµÄCount RegisterµÄÖµÔÚµ±Ç°DMA´«ÊäÊÂÎñ½øÐÐÆÚ¼ä»á²»¶ÏµØ×Ô¶¯½«¼õС£¬Ö±µ½µ±Ç°DMA´«ÊäÊÂÎñÍê³É£¬Count RegisterµÄÖµ¼õСΪ0¡£ÈçÏ£º

    ÒýÓÃ:
    static __inline__ int get_dma_residue(unsigned int dmanr)
    {
    unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
    : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;

    /* using short to get 16-bit wrap around */
    unsigned short count;

    count = 1 + dma_inb(io_port);
    count += dma_inb(io_port) << 8;

    return (dmanr<=3)? count : (count<<1);
    }

  2. Emperor ÓÚ 2006-11-30 09:49:28·¢±í:

    ¡¡¡¡3£®2 ¶ÁдDMACµÄ¸ß²ã½Ó¿Úº¯Êý

    ¡¡¡¡£¨1£©Ê¹ÄÜ£¯½ûÖ¹Ò»¸öÌØ¶¨µÄDMAͨµÀ

    ¡¡¡¡Single Channel Mask RegisterÖеÄbit£Û2£ÝΪ0±íʾʹÄÜÒ»¸öDMAͨµÀ£¬Îª1±íʾ½ûÖ¹Ò»¸öDMAͨµÀ£»¶ø¸Ã¼Ä´æÆ÷ÖеÄbit£Û1£º0£ÝÔòÓÃÓÚ±íʾʹÄÜ»ò½ûÖ¹ÄÄÒ»¸öDMAͨµÀ¡£

    ¡¡¡¡º¯Êýenable_dma()ʵÏÖʹÄÜij¸öÌØ¶¨µÄDMAͨµÀ£¬´«ÊädmanrÖ¸¶¨DMAͨµÀºÅ£¬Æäȡֵ·¶Î§ÊÇ0¡«DMA_MAX_CHANNELS£­1¡£ÈçÏ£º

    ÒýÓÃ:
    static __inline__ void enable_dma(unsigned int dmanr)
    {
    if (dmanr<=3)
    dma_outb(dmanr, DMA1_MASK_REG);
    else
    dma_outb(dmanr & 3, DMA2_MASK_REG);
    }


    ¡¡¡¡ºêdma_outbºÍdma_inbʵ¼ÊÉϾÍÊÇoutb£¨»òoutb_p£©ºÍinbº¯Êý¡£×¢Ò⣬µ±dmanrȡֵ´óÓÚ3ʱ£¬¶ÔÓ¦µÄÊÇMaster DMACÉϵÄDMAͨµÀ0¡«3£¬Òò´ËÔÚдDMA2_MASK_REG֮ǰ£¬Òª½«dmanrÓëÖµ3½øÐÐÓë²Ù×÷£¬ÒԵõ½ËüÔÚmaster DMACÉϵľֲ¿Í¨µÀ±àºÅ¡£

    ¡¡¡¡º¯Êýdisable_dma()½ûÖ¹Ò»¸öÌØ¶¨µÄDMAͨµÀ£¬ÆäÔ´ÂëÈçÏ£º

    ÒýÓÃ:
    static __inline__ void disable_dma(unsigned int dmanr)
    {
    if (dmanr<=3)
    dma_outb(dmanr | 4, DMA1_MASK_REG);
    else
    dma_outb((dmanr & 3) | 4, DMA2_MASK_REG);
    }


    ¡¡¡¡Îª½ûֹij¸öDMAͨµÀ£¬Single Channel Mask RegisterÖеÄbit£Û2£ÝÓ¦±»ÖÃΪ1¡£

    ¡¡¡¡£¨2£©Çå³ýFlip-Flop¼Ä´æÆ÷

    ¡¡¡¡º¯ÊýClear_dma_ff()ʵÏÖ¶Ôslave/Master DMACµÄFlip-Flop¼Ä´æÆ÷½øÐÐÇåÁã²Ù×÷¡£ÈçÏ£º

    ÒýÓÃ:
    static __inline__ void clear_dma_ff(unsigned int dmanr)
    {
    if (dmanr<=3)
    dma_outb(0, DMA1_CLEAR_FF_REG);
    else
    dma_outb(0, DMA2_CLEAR_FF_REG);
    }


    ¡¡¡¡£¨3£©ÉèÖÃij¸öÌØ¶¨DMAͨµÀµÄ¹¤×÷ģʽ

    ¡¡¡¡º¯Êýset_dma_mode()ʵÏÖÉèÖÃÒ»¸öÌØ¶¨DMAͨµÀµÄ¹¤×÷ģʽ¡£ÈçÏÂ

    ÒýÓÃ:
    static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
    {
    if (dmanr<=3)
    dma_outb(mode | dmanr, DMA1_MODE_REG);
    else
    dma_outb(mode | (dmanr&3), DMA2_MODE_REG);
    }


    ¡¡¡¡DMAC µÄMode RegisterÖеÄbit£Û1£º0£ÝÖ¸¶¨¶Ô¸ÃDMACÉϵÄÄÄÒ»¸öDMAͨµÀ½øÐÐģʽÉèÖá£