Çý¶¯

Ŀ ¼

  1. Çý¶¯
    1. I/O¶Ë¿Ú
    2. from smth
      1. »ù±¾½á¹¹
      2. Çý¶¯³ÌÐò
      3. ¾ßÌåʵÏÖ
    3. PCI
    4. loopback
    5. Sis 900
    6. ISA×ÜÏßDMAµÄʵÏÖ


Çý¶¯

    Linuxϵͳ֧³ÖÈýÖÖÀàÐ͵ÄÓ²¼þÉ豸£º×Ö·ûÉ豸¡¢¿éÉ豸ºÍÍøÂçÉ豸¡£×Ö·ûÉ豸ÊÇÖ±½Ó¶ÁÈ¡µÄ£¬²»±ØÊ¹Óûº³åÇø¡£ÀýÈ磬ϵͳµÄ´®ÐпÚ/dev/cua0ºÍ/dev/cua1¡£¿éÉ豸ÿ´ÎÖ»ÄܶÁȡһ¶¨´óСµÄ¿éµÄ±¶Êý£¬Í¨³£Ò»¿éÊÇ512»òÕß1024×Ö½Ú¡£¿éÉ豸ͨ¹ý»º³åÇø¶Áд£¬²¢ÇÒ¿ÉÒÔËæ»úµØ¶Áд¡£¿éÉ豸¿ÉÒÔͨ¹ýËüÃǵÄÉ豸Îļþ´æÈ¡£¬µ«Í¨³£ÊÇͨ¹ýÎļþϵͳ´æÈ¡¡£Ö»ÓпéÉ豸֧³Ö¹Ò½ÓµÄÎļþϵͳ¡£ÍøÂçÉ豸ÊÇͨ¹ýBSDÌ×½Ó×Ö½çÃæ´æÈ¡µÄ¡£

    Linuxϵͳ֧³Ö¶àÖÖÉ豸£¬ÕâЩÉ豸µÄÇý¶¯³ÌÐòÖ®¼äÓÐһЩ¹²Í¬µÄÌØµã£º
    * Äں˴úÂ룺É豸Çý¶¯³ÌÐòÊÇϵͳÄں˵ÄÒ»²¿·Ö£¬ËùÒÔÈç¹ûÇý¶¯³ÌÐò³öÏÖ´íÎóµÄ»°£¬½«¿ÉÄÜÑÏÖØµØÆÆ»µÕû¸öϵͳ¡£
    * Äں˽ӿڣºÉ豸Çý¶¯³ÌÐò±ØÐëΪϵͳÄں˻òÕßËüÃǵÄ×ÓϵͳÌṩһ¸ö±ê×¼µÄ½Ó¿Ú¡£ÀýÈ磬һ¸öÖÕ¶ËÇý¶¯³ÌÐò±ØÐëΪLinuxÄÚºËÌṩһ¸öÎļþI/O½Ó¿Ú£»Ò»¸öSCSIÉ豸Çý¶¯³ÌÐòÓ¦¸ÃΪSCSI×ÓϵͳÌṩһ¸öSCSIÉ豸½Ó¿Ú£¬Í¬Ê±SCSI×ÓϵͳҲӦΪϵͳÄÚºËÌṩÎļþI/OºÍ»º³åÇø¡£
    * Äں˻úÖÆºÍ·þÎñ£ºÉ豸Çý¶¯³ÌÐòÀûÓÃһЩ±ê×¼µÄÄں˷þÎñ£¬ÀýÈçÄÚ´æ·ÖÅäµÈ¡£
    * ¿É×°È룺´ó¶àÊýµÄLinuxÉ豸Çý¶¯³ÌÐò¶¼¿ÉÒÔÔÚÐèҪʱװÈëÄںˣ¬ÔÚ²»ÐèÒªÊ±Ð¶ÔØ¡£
    * ¿ÉÉèÖãºLinuxϵͳÉ豸Çý¶¯³ÌÐò¿ÉÒÔ¼¯³ÉΪϵͳÄں˵ÄÒ»²¿·Ö£¬ÖÁÓÚÄÄÒ»²¿·ÖÐèÒª¼¯³Éµ½ÄÚºËÖУ¬¿ÉÒÔÔÚϵͳ±àÒëʱÉèÖá£

[Ŀ¼]


I/O¶Ë¿Ú

¡¡¡¡¹Ø¼ü´Ê£ºÉ豸¹ÜÀí¡¢Çý¶¯³ÌÐò¡¢I/O¶Ë¿Ú¡¢×ÊÔ´

¡¡¡¡ÉêÃ÷£ºÕâ·ÝÎĵµÊǰ´ÕÕ×ÔÓÉÈí¼þ¿ª·ÅÔ´´úÂëµÄ¾«Éñ·¢²¼µÄ£¬ÈκÎÈË¿ÉÒÔÃâ·Ñ»ñµÃ¡¢Ê¹ÓúÍÖØÐ·¢²¼£¬µ«ÊÇÄãûÓÐÏÞÖÆ±ðÈËÖØÐ·¢²¼Äã·¢²¼ÄÚÈݵÄȨÀû¡£·¢²¼±¾ÎĵÄÄ¿µÄÊÇÏ£ÍûËüÄܶԶÁÕßÓÐÓ㬵«Ã»ÓÐÈκε£±££¬ÉõÖÁûÓÐÊʺÏÌØ¶¨Ä¿µÄµÄÒþº¬µÄµ£±£¡£¸üÏêϸµÄÇé¿öÇë²ÎÔÄGNUͨÓù«¹²Ðí¿ÉÖ¤(GPL)£¬ÒÔ¼°GNU×ÔÓÉÎĵµÐ­Òé(GFDL)¡£

¡¡¡¡¼¸ºõÿһÖÖÍâÉè¶¼ÊÇͨ¹ý¶ÁдÉ豸ÉϵļĴæÆ÷À´½øÐеġ£ÍâÉè¼Ä´æÆ÷Ò²³ÆÎª¡°I/O¶Ë¿Ú¡±£¬Í¨³£°üÀ¨£º¿ØÖƼĴæÆ÷¡¢×´Ì¬¼Ä´æÆ÷ºÍÊý¾Ý¼Ä´æÆ÷Èý´óÀ࣬¶øÇÒÒ»¸öÍâÉèµÄ¼Ä´æÆ÷ͨ³£±»Á¬ÐøµØ±àÖ·¡£CPU¶ÔÍâÉèIO¶Ë¿ÚÎïÀíµØÖ·µÄ±àÖ··½Ê½ÓÐÁ½ÖÖ£ºÒ»ÖÖÊÇI/OÓ³É䷽ʽ£¨I/O£­mapped£©£¬ÁíÒ»ÖÖÊÇÄÚ´æÓ³É䷽ʽ£¨Memory£­mapped£©¡£¶ø¾ßÌå²ÉÓÃÄÄÒ»ÖÖÔòÈ¡¾öÓÚCPUµÄÌåϵ½á¹¹¡£

¡¡¡¡ÓÐЩÌåϵ½á¹¹µÄCPU£¨È磬PowerPC¡¢m68kµÈ£©Í¨³£Ö»ÊµÏÖÒ»¸öÎïÀíµØÖ·¿Õ¼ä£¨RAM£©¡£ÔÚÕâÖÖÇé¿öÏ£¬ÍâÉèI/O¶Ë¿ÚµÄÎïÀíµØÖ·¾Í±»Ó³Éäµ½CPUµÄµ¥Ò»ÎïÀíµØÖ·¿Õ¼äÖУ¬¶ø³ÉΪÄÚ´æµÄÒ»²¿·Ö¡£´Ëʱ£¬CPU¿ÉÒÔÏó·ÃÎÊÒ»¸öÄÚ´æµ¥ÔªÄÇÑù·ÃÎÊÍâÉèI/O¶Ë¿Ú£¬¶ø²»ÐèÒªÉèÁ¢×¨ÃŵÄÍâÉèI/OÖ¸Áî¡£Õâ¾ÍÊÇËùνµÄ¡°ÄÚ´æÓ³É䷽ʽ¡±£¨Memory£­mapped£©¡£

¡¡¡¡¶øÁíÍâһЩÌåϵ½á¹¹µÄCPU£¨µäÐ͵ØÈçX86£©ÔòΪÍâÉèרÃÅʵÏÖÁËÒ»¸öµ¥¶ÀµØµØÖ·¿Õ¼ä£¬³ÆÎª¡°I/OµØÖ·¿Õ¼ä¡±»òÕß¡°I/O¶Ë¿Ú¿Õ¼ä¡±¡£ÕâÊÇÒ»¸öÓëCPUµØRAMÎïÀíµØÖ·¿Õ¼ä²»Í¬µÄµØÖ·¿Õ¼ä£¬ËùÓÐÍâÉèµÄI/O¶Ë¿Ú¾ùÔÚÕâÒ»¿Õ¼äÖнøÐбàÖ·¡£CPUͨ¹ýÉèÁ¢×¨ÃŵÄI/OÖ¸ÁÈçX86µÄINºÍOUTÖ¸ÁÀ´·ÃÎÊÕâÒ»¿Õ¼äÖеĵØÖ·µ¥Ôª£¨Ò²¼´I/O¶Ë¿Ú£©¡£Õâ¾ÍÊÇËùνµÄ¡°I/OÓ³É䷽ʽ¡±£¨I/O£­mapped£©¡£ÓëRAMÎïÀíµØÖ·¿Õ¼äÏà±È£¬I/OµØÖ·¿Õ¼äͨ³£¶¼±È½ÏС£¬Èçx86 CPUµÄI/O¿Õ¼ä¾ÍÖ»ÓÐ64KB£¨0£­0xffff£©¡£ÕâÊÇ¡°I/OÓ³É䷽ʽ¡±µÄÒ»¸öÖ÷Ҫȱµã¡£

¡¡¡¡Linux½«»ùÓÚI/OÓ³É䷽ʽµÄ»òÄÚ´æÓ³É䷽ʽµÄI/O¶Ë¿Úͨ³ÆÎª¡°I/OÇøÓò¡±£¨I/O region£©¡£ÔÚÌÖÂÛ¶ÔI/OÇøÓòµÄ¹ÜÀí֮ǰ£¬ÎÒÃÇÊ×ÏÈÀ´·ÖÎöÒ»ÏÂLinuxÊÇÈçºÎʵÏÖ¡°I/O×ÊÔ´¡±ÕâÒ»³éÏó¸ÅÄîµÄ¡£

3£®1 Linux¶ÔI/O×ÊÔ´µÄÃèÊö

¡¡¡¡LinuxÉè¼ÆÁËÒ»¸öͨÓõÄÊý¾Ý½á¹¹resourceÀ´ÃèÊö¸÷ÖÖI/O×ÊÔ´£¨È磺I/O¶Ë¿Ú¡¢ÍâÉèÄÚ´æ¡¢DMAºÍIRQµÈ£©¡£¸Ã½á¹¹¶¨ÒåÔÚinclude/linux/ioport.hÍ·ÎļþÖУº


¡¡¡¡struct resource {
        const char *name;
        unsigned long start, end;
        unsigned long flags;
        struct resource *parent, *sibling, *child;
¡¡¡¡};

¡¡¡¡¸÷³ÉÔ±µÄº¬ÒåÈçÏ£º

¡¡¡¡1. nameÖ¸Õ룺ָÏò´Ë×ÊÔ´µÄÃû³Æ¡£
¡¡¡¡2. startºÍend£º±íʾ×ÊÔ´µÄÆðʼÎïÀíµØÖ·ºÍÖÕÖ¹ÎïÀíµØÖ·¡£ËüÃÇÈ·¶¨ÁË×ÊÔ´µÄ·¶Î§£¬Ò²¼´ÊÇÒ»¸ö±ÕÇø¼ä[start,end]¡£
¡¡¡¡3. flags£ºÃèÊö´Ë×ÊÔ´ÊôÐԵıêÖ¾£¨¼ûÏÂÃæ£©¡£
¡¡¡¡4. Ö¸Õëparent¡¢siblingºÍchild£º·Ö±ðΪָÏò¸¸Çס¢ÐֵܺÍ×Ó×ÊÔ´µÄÖ¸Õë¡£

¡¡¡¡ÊôÐÔflagsÊÇÒ»¸öunsigned longÀàÐ͵Ä32λ±êÖ¾Öµ£¬ÓÃÒÔÃèÊö×ÊÔ´µÄÊôÐÔ¡£±ÈÈ磺×ÊÔ´µÄÀàÐÍ¡¢ÊÇ·ñÖ»¶Á¡¢ÊÇ·ñ¿É»º´æ£¬ÒÔ¼°ÊÇ·ñÒѱ»Õ¼Óõȡ£ÏÂÃæÊÇÒ»²¿·Ö³£ÓÃÊôÐÔ±ê־λµÄ¶¨Ò壨ioport.h£©£º


/*
* IO resources have these defined flags.
*/
#define IORESOURCE_BITS                0x000000ff        /* Bus-specific bits */

#define IORESOURCE_IO                0x00000100        /* Resource type */
#define IORESOURCE_MEM                0x00000200
#define IORESOURCE_IRQ                0x00000400
#define IORESOURCE_DMA                0x00000800

#define IORESOURCE_PREFETCH        0x00001000        /* No side effects */
#define IORESOURCE_READONLY        0x00002000
#define IORESOURCE_CACHEABLE        0x00004000
#define IORESOURCE_RANGELENGTH        0x00008000
#define IORESOURCE_SHADOWABLE        0x00010000
#define IORESOURCE_BUS_HAS_VGA        0x00080000

#define IORESOURCE_UNSET        0x20000000
#define IORESOURCE_AUTO                0x40000000
#define IORESOURCE_BUSY                0x80000000
        /* Driver has marked this resource busy */

¡¡¡¡Ö¸Õëparent¡¢siblingºÍchildµÄÉèÖÃÊÇΪÁËÒÔÒ»ÖÖÊ÷µÄÐÎʽÀ´¹ÜÀí¸÷ÖÖI/O×ÊÔ´¡£

3£®2 Linux¶ÔI/O×ÊÔ´µÄ¹ÜÀí

¡¡¡¡LinuxÊÇÒÔÒ»ÖÖµ¹ÖõÄÊ÷ÐνṹÀ´¹ÜÀíÿһÀàI/O×ÊÔ´£¨È磺I/O¶Ë¿Ú¡¢ÍâÉèÄÚ´æ¡¢DMAºÍIRQ£©µÄ¡£Ã¿Ò»ÀàI/O×ÊÔ´¶¼¶ÔÓ¦ÓÐÒ»¿Åµ¹ÖõÄ×ÊÔ´Ê÷£¬Ê÷ÖеÄÿһ¸ö½Úµã¶¼ÊÇÒ»¸öresource½á¹¹£¬¶øÊ÷µÄ¸ù½áµãrootÔòÃèÊöÁ˸ÃÀà×ÊÔ´µÄÕû¸ö×ÊÔ´¿Õ¼ä¡£

¡¡¡¡»ùÓÚÉÏÊöÕâ¸ö˼Ï룬LinuxÔÚkernel/Resource.cÎļþÖÐʵÏÖÁ˶Ô×ÊÔ´µÄÉêÇë¡¢Êͷż°²éÕҵȲÙ×÷¡£

¡¡¡¡3£®2£®1 I/O×ÊÔ´µÄÉêÇë

¡¡¡¡¼ÙÉèijÀà×ÊÔ´ÓÐÈçÏÂÕâÑùÒ»¿Å×ÊÔ´Ê÷£º

¡¡¡¡½Úµãroot¡¢r1¡¢r2ºÍr3ʵ¼ÊÉ϶¼ÊÇÒ»¸öresource½á¹¹ÀàÐÍ¡£×Ó×ÊÔ´r1¡¢r2ºÍr3ͨ¹ýsiblingÖ¸ÕëÁ´½Ó³ÉÒ»Ìõµ¥Ïò·ÇÑ­»·Á´±í£¬Æä±íÍ·ÓÉroot½ÚµãÖеÄchildÖ¸Õ붨Ò壬Òò´ËÒ²³ÆÎª¸¸×ÊÔ´µÄ×Ó×ÊÔ´Á´±í¡£r1¡¢r2ºÍr3µÄparentÖ¸Õë¾ùÖ¸ÏòËûÃǵĸ¸×ÊÔ´½Úµã£¬ÔÚÕâÀïÒ²¾ÍÊÇͼÖеÄroot½Úµã¡£

¡¡¡¡¼ÙÉèÏëÔÚroot½ÚµãÖзÖÅäÒ»¶ÎI/O×ÊÔ´£¨ÓÉͼÖеÄÒõÓ°ÇøÓò±íʾ£©¡£º¯Êýrequest_resource()ʵÏÖÕâÒ»¹¦ÄÜ¡£ËüÓÐÁ½¸ö²ÎÊý£º¢ÙrootÖ¸Õ룬±íʾҪÔÚÄĸö×ÊÔ´¸ù½ÚµãÖнøÐзÖÅ䣻¢ÚnewÖ¸Õ룬ָÏòÃèÊöËùÒª·ÖÅäµÄ×ÊÔ´£¨¼´Í¼ÖеÄÒõÓ°ÇøÓò£©µÄresource½á¹¹¡£¸Ãº¯ÊýµÄÔ´´úÂëÈçÏ£¨kernel/resource.c£©:


¡¡¡¡int request_resource(struct resource *root, struct resource *new)
¡¡¡¡{
        struct resource *conflict;

        write_lock(&resource_lock);
        conflict = __request_resource(root, new);
        write_unlock(&resource_lock);
        return conflict ? -EBUSY : 0;
¡¡¡¡}

¡¡¡¡¶ÔÉÏÊöº¯ÊýµÄNOTEÈçÏ£º

¡¡¡¡¢Ù×ÊÔ´Ëøresource_lock¶ÔËùÓÐ×ÊÔ´Ê÷½øÐжÁд±£»¤£¬ÈκδúÂë¶ÎÔÚ·ÃÎÊijһ¿Å×ÊÔ´Ê÷֮ǰ¶¼±ØÐëÏȳÖÓиÃËø¡£Æä¶¨ÒåÈçÏ£¨kernel/Resource.c£©£º

¡¡¡¡static rwlock_t resource_lock = RW_LOCK_UNLOCKED;

¡¡¡¡¢Ú¿ÉÒÔ¿´³ö£¬º¯Êýʵ¼ÊÉÏÊÇͨ¹ýµ÷ÓÃÄÚ²¿¾²Ì¬º¯Êý__request_resource()À´Íê³Éʵ¼ÊµÄ×ÊÔ´·ÖÅ乤×÷¡£Èç¹û¸Ãº¯Êý·µ»Ø·Ç¿ÕÖ¸Õ룬Ôò±íʾÓÐ×ÊÔ´³åÍ»£»·ñÔò£¬·µ»ØNULL¾Í±íʾ·ÖÅä³É¹¦¡£

¡¡¡¡¢Û×îºó£¬Èç¹ûconflictÖ¸ÕëΪNULL£¬Ôòrequest_resource()º¯Êý·µ»Ø·µ»ØÖµ0£¬±íʾ³É¹¦£»·ñÔò·µ»Ø£­EBUSY±íʾÏëÒª·ÖÅäµÄ×ÊÔ´Òѱ»Õ¼Óá£

¡¡¡¡º¯Êý__request_resource()Íê³Éʵ¼ÊµÄ×ÊÔ´·ÖÅ乤×÷¡£Èç¹û²ÎÊýnewËùÃèÊöµÄ×ÊÔ´ÖеÄÒ»²¿·Ö»òÈ«²¿ÒѾ­±»ÆäËü½ÚµãËùÕ¼Óã¬Ôòº¯Êý·µ»ØÓënewÏà³åÍ»µÄresource½á¹¹µÄÖ¸Õë¡£·ñÔò¾Í·µ»ØNULL¡£¸Ãº¯ÊýµÄÔ´´úÂëÈçÏÂ


£¨kernel/Resource.c£©£º
/* Return the conflict entry if you can't request it */
static struct resource * __request_resource
¡¡¡¡(struct resource *root, struct resource *new)
{
        unsigned long start = new->start;
        unsigned long end = new->end;
        struct resource *tmp, **p;

        if (end < start)
                return root;
        if (start < root->start)
                return root;
        if (end > root->end)
                return root;
        p = &root->child;
        for (;;) {
                tmp = *p;
                if (!tmp || tmp->start > end) {
                        new->sibling = tmp;
                        *p = new;
                        new->parent = root;
                        return NULL;
                }
                p = &tmp->sibling;
                if (tmp->end < start)
                        continue;
                return tmp;
        }
}

¡¡¡¡¶Ôº¯ÊýµÄNOTE£º

¡¡¡¡¢ÙǰÈý¸öifÓï¾äÅжÏnewËùÃèÊöµÄ×ÊÔ´·¶Î§ÊÇ·ñ±»°üº¬ÔÚrootÄÚ£¬ÒÔ¼°ÊÇ·ñÊÇÒ»¶ÎÓÐЧµÄ×ÊÔ´£¨ÒòΪend±ØÐë´óÓÚstart£©¡£·ñÔò¾Í·µ»ØrootÖ¸Õ룬±íʾÓë¸ù½áµãÏà³åÍ»¡£

¡¡¡¡¢Ú½ÓÏÂÀ´ÓÃÒ»¸öforÑ­»·±éÀú¸ù½ÚµãrootµÄchildÁ´±í£¬ÒÔ±ã¼ì²éÊÇ·ñÓÐ×ÊÔ´³åÍ»£¬²¢½«new²åÈëµ½childÁ´±íÖеĺÏÊÊλÖã¨childÁ´±íÊÇÒÔI/O×ÊÔ´ÎïÀíµØÖ·´ÓµÍµ½¸ßµÄ˳ÐòÅÅÁеģ©¡£Îª´Ë£¬ËüÓÃtmpÖ¸ÕëÖ¸Ïòµ±Ç°Õý±»É¨ÃèµÄresource½á¹¹£¬ÓÃÖ¸ÕëpÖ¸Ïòǰһ¸öresource½á¹¹µÄsiblingÖ¸Õë³ÉÔ±±äÁ¿£¬pµÄ³õʼֵΪָÏòroot£­>sibling¡£ForÑ­»·ÌåµÄÖ´Ðв½ÖèÈçÏ£º

¡¡¡¡l ÈÃtmpÖ¸Ïòµ±Ç°Õý±»É¨ÃèµÄresource½á¹¹£¨tmp£½*p£©¡£

¡¡¡¡l ÅжÏtmpÖ¸ÕëÊÇ·ñΪ¿Õ£¨tmpÖ¸ÕëΪ¿Õ˵Ã÷ÒѾ­±éÀúÍêÕû¸öchildÁ´±í£©£¬»òÕßµ±Ç°±»É¨Ãè½ÚµãµÄÆðʼλÖÃstartÊÇ·ñ±ÈnewµÄ½áÊøÎ»ÖÃend»¹Òª´ó¡£Ö»ÒªÕâÁ½¸öÌõ¼þÖ®Ò»³ÉÁ¢µÄ»°£¬¾Í˵Ã÷ûÓÐ×ÊÔ´³åÍ»£¬ÓÚÊǾͿÉÒÔ°ÑnewÁ´ÈëchildÁ´±íÖУº¢ÙÉèÖÃnewµÄsiblingÖ¸ÕëÖ¸Ïòµ±Ç°Õý±»É¨ÃèµÄ½Úµãtmp£¨new->sibling=tmp£©£»¢Úµ±Ç°½ÚµãtmpµÄǰһ¸öÐֵܽڵãµÄsiblingÖ¸Õë±»ÐÞ¸ÄΪָÏònewÕâ¸ö½Úµã£¨*p=new£©£»¢Û½«newµÄparentÖ¸ÕëÉèÖÃΪָÏòroot¡£È»ºóº¯Êý¾Í¿ÉÒÔ·µ»ØÁË£¨·µ»ØÖµNULL±íʾûÓÐ×ÊÔ´³åÍ»£©¡£

¡¡¡¡l Èç¹ûÉÏÊöÁ½¸öÌõ¼þ¶¼²»³ÉÁ¢£¬Õâ˵Ã÷µ±Ç°±»É¨Ãè½ÚµãµÄ×ÊÔ´ÓòÓпÉÄÜÓënewÏà³åÍ»£¨Êµ¼ÊÉϾÍÊÇÁ½¸ö±ÕÇø¼äÓн»¼¯£©£¬Òò´ËÐèÒª½øÒ»²½Åжϡ£Îª´ËËüÊ×ÏÈÐÞ¸ÄÖ¸Õëp£¬ÈÃËüÖ¸Ïòtmp->sibling£¬ÒÔ±ãÓÚ¼ÌÐøÉ¨ÃèchildÁ´±í¡£È»ºó£¬ÅжÏtmp->endÊÇ·ñСÓÚnew->start£¬Èç¹ûСÓÚ£¬Ôò˵Ã÷µ±Ç°½ÚµãtmpºÍnewûÓÐ×ÊÔ´³åÍ»£¬Òò´ËÖ´ÐÐcontinueÓï¾ä£¬¼ÌÐøÏòÏÂɨÃèchildÁ´±í¡£·ñÔò£¬Èç¹ûtmp->end´óÓÚ»òµÈÓÚnew->start£¬Ôò˵Ã÷tmp->[start,end]ºÍnew->[start,end]Ö®¼äÓн»¼¯¡£ËùÒÔ·µ»Øµ±Ç°½ÚµãµÄÖ¸Õëtmp£¬±íʾ·¢Éú×ÊÔ´³åÍ»¡£

¡¡¡¡3£®2£®2 ×ÊÔ´µÄÊÍ·Å

¡¡¡¡º¯Êýrelease_resource()ÓÃÓÚʵÏÖI/O×ÊÔ´µÄÊÍ·Å¡£¸Ãº¯ÊýÖ»ÓÐÒ»¸ö²ÎÊý¡ª¡ª¼´Ö¸Õëold£¬ËüÖ¸ÏòËùÒªÊͷŵÄ×ÊÔ´¡£ÆðÔ´´úÂëÈçÏ£º


int release_resource(struct resource *old)
{
        int retval;

        write_lock(&resource_lock);
        retval = __release_resource(old);
        write_unlock(&resource_lock);
        return retval;
}

¡¡¡¡¿ÉÒÔ¿´³ö£¬Ëüʵ¼ÊÉÏͨ¹ýµ÷ÓÃ__release_resource()Õâ¸öÄÚ²¿¾²Ì¬º¯ÊýÀ´Íê³Éʵ¼ÊµÄ×ÊÔ´Êͷʤ×÷¡£º¯Êý__release_resource()µÄÖ÷ÒªÈÎÎñ¾ÍÊǽ«×ÊÔ´ÇøÓòold£¨Èç¹ûÒѾ­´æÔڵϰ£©´ÓÆä¸¸×ÊÔ´µÄchildÁ´±íÖØÕª³ý£¬ËüµÄÔ´´úÂëÈçÏ£º


static int __release_resource(struct resource *old)
{
        struct resource *tmp, **p;

        p = &old->parent->child;
        for (;;) {
                tmp = *p;
                if (!tmp)
                        break;
                if (tmp == old) {
                        *p = tmp->sibling;
                        old->parent = NULL;
                        return 0;
                }
                p = &tmp->sibling;
        }
        return -EINVAL;
}

¡¡¡¡¶ÔÉÏÊöº¯Êý´úÂëµÄNOTEÈçÏ£º

¡¡¡¡Í¬º¯Êý__request_resource()ÏàÀàËÆ£¬¸Ãº¯ÊýÒ²ÊÇͨ¹ýÒ»¸öforÑ­»·À´±éÀú¸¸×ÊÔ´µÄchildÁ´±í¡£Îª´Ë£¬ËüÈÃtmpÖ¸ÕëÖ¸Ïòµ±Ç°±»É¨ÃèµÄ×ÊÔ´£¬¶øÖ¸ÕëpÔòÖ¸Ïòµ±Ç°½ÚµãµÄǰһ¸ö½ÚµãµÄsibling³ÉÔ±£¨pµÄ³õʼֵΪָÏò¸¸×ÊÔ´µÄchildÖ¸Õ룩¡£Ñ­»·ÌåµÄ²½ÖèÈçÏ£º

¡¡¡¡¢ÙÊ×ÏÈ£¬ÈÃtmpÖ¸ÕëÖ¸Ïòµ±Ç°±»É¨ÃèµÄ½Úµã£¨tmp£½*p£©¡£

¡¡¡¡¢ÚÈç¹ûtmpÖ¸ÕëΪ¿Õ£¬ËµÃ÷ÒѾ­±éÀúÍêÕû¸öchildÁ´±í£¬Òò´ËÖ´ÐÐbreakÓï¾äÍÆ³öforÑ­»·¡£ÓÉÓÚÔÚ±éÀú¹ý³ÌÖÐûÓÐÔÚchildÁ´±íÖÐÕÒµ½²ÎÊýoldËùÖ¸¶¨µÄ×ÊÔ´½Úµã£¬Òò´Ë×îºó·µ»Ø´íÎóÖµ£­EINVAL£¬±íʾ²ÎÊýoldÊÇÒ»¸öÎÞЧµÄÖµ¡£

¡¡¡¡¢Û½ÓÏÂÀ´£¬Åжϵ±Ç°±»É¨Ãè½ÚµãÊÇ·ñ¾ÍÊDzÎÊýoldËùÖ¸¶¨µÄ×ÊÔ´½Úµã¡£Èç¹ûÊÇ£¬ÄǾͽ«old´ÓchildÁ´±íÖÐÈ¥³ý£¬Ò²¼´Èõ±Ç°½áµãtmpµÄǰһ¸öÐֵܽڵãµÄsiblingÖ¸ÕëÖ¸ÏòtmpµÄÏÂÒ»¸ö½Úµã£¬È»ºó½«old£­>parentÖ¸ÕëÉèÖÃΪNULL¡£×îºó·µ»Ø0Öµ±íʾִÐгɹ¦¡£

¡¡¡¡¢ÜÈç¹ûµ±Ç°±»É¨Ãè½Úµã²»ÊÇ×ÊÔ´old£¬ÄǾͼÌÐøÉ¨ÃèchildÁ´±íÖеÄÏÂÒ»¸öÔªËØ¡£Òò´Ë½«Ö¸ÕëpÖ¸Ïòtmp£­>sibling³ÉÔ±¡£

¡¡¡¡3£®2£®3 ¼ì²é×ÊÔ´ÊÇ·ñÒѱ»Õ¼Óã¬

¡¡¡¡º¯Êýcheck_resource()ÓÃÓÚʵÏÖ¼ì²éijһ¶ÎI/O×ÊÔ´ÊÇ·ñÒѱ»Õ¼Óá£ÆäÔ´´úÂëÈçÏ£º


int check_resource(struct resource *root, unsigned long start, unsigned long len)
{
        struct resource *conflict, tmp;

        tmp.start = start;
        tmp.end = start + len - 1;
        write_lock(&resource_lock);
        conflict = __request_resource(root, &tmp);
        if (!conflict)
                __release_resource(&tmp);
        write_unlock(&resource_lock);
        return conflict ? -EBUSY : 0;
}

¡¡¡¡¶Ô¸Ãº¯ÊýµÄNOTEÈçÏ£º

¡¡¡¡¢Ù¹¹ÔìÒ»¸öÁÙʱ×ÊÔ´tmp£¬±íʾËùÒª¼ì²éµÄ×ÊÔ´[start,start+end-1]¡£

¡¡¡¡¢Úµ÷ÓÃ__request_resource()º¯ÊýÔÚ¸ù½ÚµãrootÉêÇëtmpËù±íʾµÄ×ÊÔ´¡£Èç¹ûtmpËùÃèÊöµÄ×ÊÔ´»¹±»ÈËʹÓã¬Ôò¸Ãº¯Êý·µ»ØNULL£¬·ñÔò·µ»Ø·Ç¿ÕÖ¸Õë¡£Òò´Ë½ÓÏÂÀ´ÔÚconflictΪNULLµÄÇé¿öÏ£¬µ÷ÓÃ__release_resource()½«¸Õ¸ÕÉêÇëµÄ×ÊÔ´Êͷŵô¡£

¡¡¡¡¢Û×îºó¸ù¾ÝconflictÊÇ·ñΪNULL£¬·µ»Ø£­EBUSY»ò0Öµ¡£

¡¡¡¡3£®2£®4 ѰÕÒ¿ÉÓÃ×ÊÔ´

¡¡¡¡º¯Êýfind_resource()ÓÃÓÚÔÚÒ»¿Å×ÊÔ´Ê÷ÖÐѰÕÒδ±»Ê¹Óõġ¢ÇÒÂú×ã¸ø¶¨Ìõ¼þµÄ£¨Ò²¼´×ÊÔ´³¤¶È´óСΪsize£¬ÇÒÔÚ[min,max]Çø¼äÄÚ£©µÄ×ÊÔ´¡£Æäº¯ÊýÔ´´úÂëÈçÏ£º


/*
* Find empty slot in the resource tree given range and alignment.
*/
static int find_resource(struct resource *root, struct resource *new,
                  unsigned long size,
                  unsigned long min, unsigned long max,
                  unsigned long align,
                  void (*alignf)(void *, struct resource *, unsigned long),
                  void *alignf_data)
{
        struct resource *this = root->child;

        new->start = root->start;
        for(;;) {
                if (this)
                        new->end = this->start;
                else
                        new->end = root->end;
                if (new->start < min)
                        new->start = min;
                if (new->end > max)
                        new->end = max;
                new->start = (new->start + align - 1) & ~(align - 1);
                if (alignf)
                        alignf(alignf_data, new, size);
                if (new->start < new->end && new->end - new->start + 1 >= size)
                  {
                        new->end = new->start + size - 1;
                        return 0;
                }
                if (!this)
                        break;
                new->start = this->end + 1;
                this = this->sibling;
        }
        return -EBUSY;
}

¡¡¡¡¶Ô¸Ãº¯ÊýµÄNOTEÈçÏ£º

¡¡¡¡Í¬Ñù£¬¸Ãº¯ÊýÒ²Òª±éÀúrootµÄchildÁ´±í£¬ÒÔѰÕÒδ±»Ê¹ÓõÄ×ÊÔ´¿Õ¶´¡£Îª´Ë£¬ËüÈÃthisÖ¸Õë±íʾµ±Ç°Õý±»É¨ÃèµÄ×Ó×ÊÔ´½Úµã£¬Æä³õʼֵµÈÓÚroot->child£¬¼´Ö¸ÏòchildÁ´±íÖеĵÚÒ»¸ö½Úµã£¬²¢ÈÃnew->startµÄ³õʼֵµÈÓÚroot->start£¬È»ºóÓÃÒ»¸öforÑ­»·¿ªÊ¼É¨ÃèchildÁ´±í£¬¶ÔÓÚÿһ¸ö±»É¨ÃèµÄ½Úµã£¬Ñ­»·ÌåÖ´ÐÐÈçϲÙ×÷£º

¡¡¡¡¢ÙÊ×ÏÈ£¬ÅжÏthisÖ¸ÕëÊÇ·ñΪNULL¡£Èç¹û²»Îª¿Õ£¬¾ÍÈÃnew->endµÈÓÚthis->start£¬Ò²¼´ÈÃ×ÊÔ´new±íʾµ±Ç°×ÊÔ´½ÚµãthisÇ°ÃæÄÇÒ»¶ÎδʹÓõÄ×ÊÔ´Çø¼ä¡£

¡¡¡¡¢ÚÈç¹ûthisÖ¸ÕëΪ¿Õ£¬ÄǾÍÈÃnew->endµÈÓÚroot->end¡£ÕâÓÐÁ½²ãÒâ˼£ºµÚÒ»ÖÖÇé¿ö¾ÍÊǸù½áµãµÄchildÖ¸ÕëΪNULL£¨¼´¸ù½ÚµãûÓÐÈκÎ×Ó×ÊÔ´£©¡£Òò´Ë´ËʱÏÈÔÝʱ½«new->end·Åµ½×î´ó¡£µÚ¶þÖÖÇé¿ö¾ÍÊÇÒѾ­±éÀúÍêÕû¸öchildÁ´±í£¬ËùÒÔ´Ëʱ¾ÍÈÃnew±íʾ×îºóÒ»¸ö×Ó×ÊÔ´ºóÃæÄÇÒ»¶ÎδʹÓõÄ×ÊÔ´Çø¼ä¡£

¡¡¡¡¢Û¸ù¾Ý²ÎÊýminºÍmaxÐÞÕýnew->[start,end]µÄÖµ£¬ÒÔʹ×ÊÔ´new±»°üº¬ÔÚ[min,max]ÇøÓòÄÚ¡£

¡¡¡¡¢Ü½ÓÏÂÀ´½øÐÐ¶ÔÆë²Ù×÷¡£

¡¡¡¡¢ÝÈ»ºó£¬ÅжϾ­¹ýÉÏÊöÕâЩ²½ÖèËùÐγɵÄ×ÊÔ´ÇøÓònewÊÇ·ñÊÇÒ»¶ÎÓÐЧµÄ×ÊÔ´£¨end±ØÐë´óÓÚ»òµÈÓÚstart£©£¬¶øÇÒ×ÊÔ´ÇøÓòµÄ³¤¶ÈÂú×ãsize²ÎÊýµÄÒªÇó£¨end£­start£«1>=size£©¡£Èç¹ûÕâÁ½¸öÌõ¼þ¾ùÂú×㣬Ôò˵Ã÷ÎÒÃÇÒѾ­ÕÒµ½ÁËÒ»¶ÎÂú×ãÌõ¼þµÄ×ÊÔ´¿Õ¶´¡£Òò´ËÔÚ¶Ônew->endµÄÖµ½øÐÐÐÞÕýºó£¬È»ºó¾Í¿ÉÒÔ·µ»ØÁË£¨·µ»ØÖµ0±íʾ³É¹¦£©¡£

¡¡¡¡¢ÞÈç¹ûÉÏÊöÁ½Ìõ¼þ²»ÄÜͬʱÂú×㣬Ôò˵Ã÷»¹Ã»ÓÐÕÒµ½£¬Òò´ËÒª¼ÌÐøÉ¨ÃèÁ´±í¡£ÔÚ¼ÌÐøÉ¨Ãè֮ǰ£¬ÎÒÃÇ»¹ÊÇÒªÅжÏÒ»ÏÂthisÖ¸ÕëÊÇ·ñΪ¿Õ¡£Èç¹ûΪ¿Õ£¬ËµÃ÷ÒѾ­É¨ÃèÍêÕû¸öchildÁ´±í£¬Òò´Ë¾Í¿ÉÒÔÍÆ³öforÑ­»·ÁË¡£·ñÔò¾Í½«new->startµÄÖµÐÞ¸ÄΪthis->end+1£¬²¢ÈÃthisÖ¸ÏòÏÂÒ»¸öÐÖµÜ×ÊÔ´½Úµã£¬´Ó¶ø¼ÌÐøÉ¨ÃèÁ´±íÖеÄÏÂÒ»¸ö×Ó×ÊÔ´½Úµã¡£

¡¡¡¡3£®2£®5 ·ÖÅä½Ó¿Úallocate_resource()

¡¡¡¡ÔÚfind_resource()º¯ÊýµÄ»ù´¡ÉÏ£¬º¯Êýallocate_resource()ʵÏÖ£ºÔÚÒ»¿Å×ÊÔ´Ê÷ÖзÖÅäÒ»ÌõÖ¸¶¨´óСµÄ¡¢ÇÒ°üº¬ÔÚÖ¸¶¨ÇøÓò[min,max]Öеġ¢Î´Ê¹ÓÃ×ÊÔ´ÇøÓò¡£ÆäÔ´´úÂëÈçÏ£º


/*
* Allocate empty slot in the resource tree given range and alignment.
*/
int allocate_resource(struct resource *root, struct resource *new,
                      unsigned long size,
                      unsigned long min, unsigned long max,
                      unsigned long align,
                      void (*alignf)(void *, struct resource *, unsigned long),
                      void *alignf_data)
{
    int err;

    write_lock(&resource_lock);
    err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
    if (err >= 0 && __request_resource(root, new))
        err = -EBUSY;
    write_unlock(&resource_lock);
    return err;
}

¡¡¡¡3£®2£®6 »ñÈ¡×ÊÔ´µÄÃû³ÆÁбí

¡¡¡¡º¯Êýget_resource_list()ÓÃÓÚ»ñÈ¡¸ù½ÚµãrootµÄ×Ó×ÊÔ´Ãû×ÖÁÐ±í¡£¸Ãº¯ÊýÖ÷ÒªÓÃÀ´Ö§³Ö/proc/Îļþϵͳ£¨±ÈÈçʵÏÖproc/ioportsÎļþºÍ/proc/iomemÎļþ£©¡£ÆäÔ´´úÂëÈçÏ£º


int get_resource_list(struct resource *root, char *buf, int size)
{
        char *fmt;
        int retval;

        fmt = "        %08lx-%08lx : %s
";
        if (root->end < 0x10000)
                fmt = "        %04lx-%04lx : %s
";
        read_lock(&resource_lock);
        retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
        read_unlock(&resource_lock);
        return retval;
}

¡¡¡¡¿ÉÒÔ¿´³ö£¬¸Ãº¯ÊýÖ÷Ҫͨ¹ýµ÷ÓÃÄÚ²¿¾²Ì¬º¯Êýdo_resource_list()À´ÊµÏ֯书ÄÜ£¬ÆäÔ´´úÂëÈçÏ£º


/*
* This generates reports for /proc/ioports and /proc/iomem
*/
static char * do_resource_list(struct resource *entry, const char *fmt,
¡¡¡¡int offset, char *buf, char *end)
{
        if (offset < 0)
                offset = 0;

        while (entry) {
                const char *name = entry->name;
                unsigned long from, to;

                if ((int) (end-buf) < 80)
                        return buf;

                from = entry->start;
                to = entry->end;
                if (!name)
                        name = "";

                buf += sprintf(buf, fmt + offset, from, to, name);
                if (entry->child)
                   buf = do_resource_list(entry->child, fmt, offset-2, buf, end);
                entry = entry->sibling;
        }

        return buf;
}

¡¡¡¡º¯Êýdo_resource_list()Ö÷Ҫͨ¹ýÒ»¸öwhile{}Ñ­»·ÒÔ¼°µÝ¹éǶÌ×µ÷ÓÃÀ´ÊµÏÖ£¬½ÏΪ¼òµ¥£¬ÕâÀï¾Í²»ÔÚÏêϸ½âÊÍÁË¡£

3£®3 ¹ÜÀíI/O Region×ÊÔ´

¡¡¡¡Linux½«»ùÓÚI/OÓ³É䷽ʽµÄI/O¶Ë¿ÚºÍ»ùÓÚÄÚ´æÓ³É䷽ʽµÄI/O¶Ë¿Ú×ÊԴͳ³ÆÎª¡°I/OÇøÓò¡±£¨I/O Region£©¡£I/O RegionÈÔÈ»ÊÇÒ»ÖÖI/O×ÊÔ´£¬Òò´ËËüÈÔÈ»¿ÉÒÔÓÃresource½á¹¹ÀàÐÍÀ´ÃèÊö¡£ÏÂÃæÎÒÃǾÍÀ´¿´¿´LinuxÊÇÈçºÎ¹ÜÀíI/O RegionµÄ¡£

¡¡¡¡3£®3£®1 I/O RegionµÄ·ÖÅä

¡¡¡¡ÔÚº¯Êý__request_resource()µÄ»ù´¡ÉÏ£¬LinuxʵÏÖÁËÓÃÓÚ·ÖÅäI/OÇøÓòµÄº¯Êý__request_region()£¬ÈçÏÂ:


struct resource * __request_region(struct resource *parent,
¡¡¡¡unsigned long start, unsigned long n, const char *name)
{
        struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);

        if (res) {
                memset(res, 0, sizeof(*res));
                res->name = name;
                res->start = start;
                res->end = start + n - 1;
                res->flags = IORESOURCE_BUSY;

                write_lock(&resource_lock);

                for (;;) {
                        struct resource *conflict;

                        conflict = __request_resource(parent, res);
                        if (!conflict)
                                break;
                        if (conflict != parent) {
                                parent = conflict;
                                if (!(conflict->flags & IORESOURCE_BUSY))
                                        continue;
                        }

                        /* Uhhuh, that didn't work out.. */
                        kfree(res);
                        res = NULL;
                        break;
                }
                write_unlock(&resource_lock);
        }
        return res;
}

NOTE£º

¡¡¡¡¢ÙÊ×ÏÈ£¬µ÷ÓÃkmalloc£¨£©º¯ÊýÔÚSLAB·ÖÅäÆ÷»º´æÖзÖÅäÒ»¸öresource½á¹¹¡£

¡¡¡¡¢ÚÈ»ºó£¬ÏàÓ¦µÄ¸ù¾Ý²ÎÊýÖµ³õʼ»¯Ëù·ÖÅäµÄresource½á¹¹¡£×¢Ò⣡flags³ÉÔ±±»³õʼ»¯ÎªIORESOURCE_BUSY¡£

¡¡¡¡¢Û½ÓÏÂÀ´£¬ÓÃÒ»¸öforÑ­»·¿ªÊ¼½øÐÐ×ÊÔ´·ÖÅ䣬ѭ»·ÌåµÄ²½ÖèÈçÏ£º

¡¡¡¡l Ê×ÏÈ£¬µ÷ÓÃ__request_resource()º¯Êý½øÐÐ×ÊÔ´·ÖÅä¡£Èç¹û·µ»ØNULL£¬ËµÃ÷·ÖÅä³É¹¦£¬Òò´Ë¾ÍÖ´ÐÐbreakÓï¾äÍÆ³öforÑ­»·£¬·µ»ØËù·ÖÅäµÄresource½á¹¹µÄÖ¸Õ룬º¯Êý³É¹¦µØ½áÊø¡£

¡¡¡¡l Èç¹û__request_resource()º¯Êý·ÖÅä²»³É¹¦£¬Ôò½øÒ»²½ÅжÏËù·µ»ØµÄ³åÍ»×ÊÔ´½ÚµãÊÇ·ñ¾ÍÊǸ¸×ÊÔ´½Úµãparent¡£Èç¹û²»ÊÇ£¬Ôò½«·ÖÅäÐÐΪϽµÒ»¸ö²ã´Î£¬¼´ÊÔͼÔÚµ±Ç°³åÍ»µÄ×ÊÔ´½ÚµãÖнøÐзÖÅ䣨ֻÓÐÔÚ³åÍ»µÄ×ÊÔ´½ÚµãûÓÐÉèÖÃIORESOURCE_BUSYµÄÇé¿öϲſÉÒÔ£©£¬ÓÚÊÇÈÃparentÖ¸ÕëµÈÓÚconflict£¬²¢ÔÚconflict->flags&IORESOURCE_BUSYΪ0µÄÇé¿öÏÂÖ´ÐÐcontinueÓï¾ä¼ÌÐøforÑ­»·¡£

¡¡¡¡l ·ñÔòÈç¹ûÏà³åÍ»µÄ×ÊÔ´½Úµã¾ÍÊǸ¸½Úµãparent£¬»òÕßÏà³åÍ»×ÊÔ´½ÚµãÉèÖÃÁËIORESOURCE_BUSY±ê־룬ÔòÐû¸æ·ÖÅäʧ°Ü¡£ÓÚÊǵ÷ÓÃkfree£¨£©º¯ÊýÊÍ·ÅËù·ÖÅäµÄresource½á¹¹£¬²¢½«resÖ¸ÕëÖÃΪNULL£¬×îºóÓÃbreakÓï¾äÍÆ³öforÑ­»·¡£

¡¡¡¡¢Ü×îºó£¬·µ»ØËù·ÖÅäµÄresource½á¹¹µÄÖ¸Õë¡£

¡¡¡¡3£®3£®2 I/O RegionµÄÊÍ·Å

¡¡¡¡º¯Êý__release_region()ʵÏÖÔÚÒ»¸ö¸¸×ÊÔ´½ÚµãparentÖÐÊͷŸø¶¨·¶Î§µÄI/O Region¡£Êµ¼ÊÉϸú¯ÊýµÄʵÏÖ˼ÏëÓë__release_resource()ÏàÀàËÆ¡£ÆäÔ´´úÂëÈçÏ£º


void __release_region(struct resource *parent,
¡¡¡¡¡¡¡¡unsigned long start, unsigned long n)
{
        struct resource **p;
        unsigned long end;

        p = &parent->child;
        end = start + n - 1;

        for (;;) {
                struct resource *res = *p;

                if (!res)
                        break;
                if (res->start <= start && res->end >= end) {
                        if (!(res->flags & IORESOURCE_BUSY)) {
                                p = &res->child;
                                continue;
                        }
                        if (res->start != start'  'res->end != end)
                                break;
                        *p = res->sibling;
                        kfree(res);
                        return;
                }
                p = &res->sibling;
        }
        printk("Trying to free nonexistent resource <%08lx-%08lx>
", start, end);
}

¡¡¡¡ÀàËÆµØ£¬¸Ãº¯ÊýÒ²ÊÇͨ¹ýÒ»¸öforÑ­»·À´±éÀú¸¸×ÊÔ´parentµÄchildÁ´±í¡£Îª´Ë£¬ËüÈÃÖ¸ÕëresÖ¸Ïòµ±Ç°Õý±»É¨ÃèµÄ×Ó×ÊÔ´½Úµã£¬Ö¸ÕëpÖ¸Ïòǰһ¸ö×Ó×ÊÔ´½ÚµãµÄsibling³ÉÔ±±äÁ¿£¬pµÄ³õʼֵΪָÏòparent->child¡£ForÑ­»·ÌåµÄ²½ÖèÈçÏ£º

¡¡¡¡¢ÙÈÃresÖ¸ÕëÖ¸Ïòµ±Ç°±»É¨ÃèµÄ×Ó×ÊÔ´½Úµã£¨res£½*p£©¡£

¡¡¡¡¢ÚÈç¹ûresÖ¸ÕëΪNULL£¬ËµÃ÷ÒѾ­É¨ÃèÍêÕû¸öchildÁ´±í£¬ËùÒÔÍ˳öforÑ­»·¡£

¡¡¡¡¢ÛÈç¹ûresÖ¸Õ벻ΪNULL£¬Ôò¼ÌÐø¿´¿´ËùÖ¸¶¨µÄI/OÇøÓò·¶Î§ÊÇ·ñÍêÈ«°üº¬ÔÚµ±Ç°×ÊÔ´½ÚµãÖУ¬Ò²¼´¿´¿´[start,start+n-1]ÊÇ·ñ°üº¬ÔÚres->[start,end]ÖС£Èç¹û²»ÊôÓÚ£¬ÔòÈÃpÖ¸Ïòµ±Ç°×ÊÔ´½ÚµãµÄsibling³ÉÔ±£¬È»ºó¼ÌÐøforÑ­»·¡£Èç¹ûÊôÓÚ£¬ÔòÖ´ÐÐÏÂÁв½Ö裺

¡¡¡¡l ÏÈ¿´¿´µ±Ç°×ÊÔ´½ÚµãÊÇ·ñÉèÖÃÁËIORESOURCE_BUSY±ê־λ¡£Èç¹ûûÓÐÉèÖøñê־룬Ôò˵Ã÷¸Ã×ÊÔ´½ÚµãÏÂÃæ¿ÉÄÜ»¹»áÓÐ×ӽڵ㣬Òò´Ë½«É¨Ãè¹ý³ÌϽµÒ»¸ö²ã´Î£¬ÓÚÊÇÐÞ¸ÄpÖ¸Õ룬ʹËüÖ¸Ïòres->child£¬È»ºóÖ´ÐÐcontinueÓï¾ä¼ÌÐøforÑ­»·¡£

¡¡¡¡l Èç¹ûÉèÖÃÁËIORESOURCE_BUSY±ê־λ¡£ÔòÒ»¶¨ÒªÈ·±£µ±Ç°×ÊÔ´½Úµã¾ÍÊÇËùÖ¸¶¨µÄI/OÇøÓò£¬È»ºó½«µ±Ç°×ÊÔ´½Úµã´ÓÆä¸¸×ÊÔ´µÄchildÁ´±íÖÐÈ¥³ý¡£Õâ¿ÉÒÔͨ¹ýÈÃǰһ¸öÐÖµÜ×ÊÔ´½ÚµãµÄsiblingÖ¸ÕëÖ¸Ïòµ±Ç°×ÊÔ´½ÚµãµÄÏÂÒ»¸öÐÖµÜ×ÊÔ´½ÚµãÀ´ÊµÏÖ£¨¼´ÈÃ*p=res->sibling£©£¬×îºóµ÷ÓÃkfree£¨£©º¯ÊýÊͷŵ±Ç°×ÊÔ´½ÚµãµÄresource½á¹¹¡£È»ºóº¯Êý¾Í¿ÉÒԳɹ¦·µ»ØÁË¡£

¡¡¡¡3£®3£®3 ¼ì²éÖ¸¶¨µÄI/O RegionÊÇ·ñÒѱ»Õ¼ÓÃ

¡¡¡¡º¯Êý__check_region()¼ì²éÖ¸¶¨µÄI/O RegionÊÇ·ñÒѱ»Õ¼Óá£ÆäÔ´´úÂëÈçÏ£º


int __check_region(struct resource *parent, unsigned long start, unsigned long n)
{
        struct resource * res;

        res = __request_region(parent, start, n, "check-region");
        if (!res)
                return -EBUSY;

        release_resource(res);
        kfree(res);
        return 0;
}

¡¡¡¡¸Ãº¯ÊýµÄʵÏÖÓë__check_resource()µÄʵÏÖ˼ÏëÀàËÆ¡£Ê×ÏÈ£¬Ëüͨ¹ýµ÷ÓÃ__request_region()º¯ÊýÊÔͼÔÚ¸¸×ÊÔ´parentÖзÖÅäÖ¸¶¨µÄI/O Region¡£Èç¹û·ÖÅä²»³É¹¦£¬½«·µ»ØNULL£¬Òò´Ë´Ëʱº¯Êý·µ»Ø´íÎóÖµ£­EBUSY±íʾËùÖ¸¶¨µÄI/O RegionÒѱ»Õ¼Óá£Èç¹ûresÖ¸Õ벻Ϊ¿ÕÔò˵Ã÷ËùÖ¸¶¨µÄI/O RegionûÓб»Õ¼Óá£ÓÚÊǵ÷ÓÃ__release_resource()º¯Êý½«¸Õ¸Õ·ÖÅäµÄ×ÊÔ´Êͷŵô£¨Êµ¼ÊÉÏÊǽ«res½á¹¹´ÓparentµÄchildÁ´±íÈ¥³ý£©£¬È»ºóµ÷ÓÃkfree£¨£©º¯ÊýÊÍ·Åres½á¹¹ËùÕ¼ÓõÄÄÚ´æ¡£×îºó£¬·µ»Ø0Öµ±íʾָ¶¨µÄI/O RegionûÓб»Õ¼Óá£

3£®4 ¹ÜÀíI/O¶Ë¿Ú×ÊÔ´

¡¡¡¡ÎÒÃǶ¼ÖªµÀ£¬²ÉÓÃI/OÓ³É䷽ʽµÄX86´¦ÀíÆ÷ΪÍâÉèʵÏÖÁËÒ»¸öµ¥¶ÀµÄµØÖ·¿Õ¼ä£¬Ò²¼´¡°I/O¿Õ¼ä¡±£¨I/O Space£©»ò³ÆÎª¡°I/O¶Ë¿Ú¿Õ¼ä¡±£¬Æä´óСÊÇ64KB£¨0x0000£­0xffff£©¡£LinuxÔÚÆäËùÖ§³ÖµÄËùÓÐÆ½Ì¨É϶¼ÊµÏÖÁË¡°I/O¶Ë¿Ú¿Õ¼ä¡±ÕâÒ»¸ÅÄî¡£

¡¡¡¡ÓÉÓÚI/O¿Õ¼ä·Ç³£Ð¡£¬Òò´Ë¼´Ê¹ÍâÉè×ÜÏßÓÐÒ»¸öµ¥¶ÀµÄI/O¶Ë¿Ú¿Õ¼ä£¬È´Ò²²»ÊÇËùÓеÄÍâÉè¶¼½«ÆäI/O¶Ë¿Ú£¨Ö¸¼Ä´æÆ÷£©Ó³Éäµ½¡°I/O¶Ë¿Ú¿Õ¼ä¡±ÖС£±ÈÈ磬´ó¶àÊýPCI¿¨¶¼Í¨¹ýÄÚ´æÓ³É䷽ʽÀ´½«ÆäI/O¶Ë¿Ú»òÍâÉèÄÚ´æÓ³Éäµ½CPUµÄRAMÎïÀíµØÖ·¿Õ¼äÖС£¶øÀÏʽµÄISA¿¨Í¨³£½«ÆäI/O¶Ë¿ÚÓ³Éäµ½I/O¶Ë¿Ú¿Õ¼äÖС£

¡¡¡¡LinuxÊÇ»ùÓÚ¡°I/O Region¡±ÕâÒ»¸ÅÄîÀ´ÊµÏÖ¶ÔI/O¶Ë¿Ú×ÊÔ´£¨I/O£­mapped »ò Memory£­mapped£©µÄ¹ÜÀíµÄ¡£

¡¡¡¡3£®4£®1 ×ÊÔ´¸ù½ÚµãµÄ¶¨Òå

¡¡¡¡LinuxÔÚkernel/Resource.cÎļþÖж¨ÒåÁËÈ«¾Ö±äÁ¿ioport_resourceºÍiomem_resource£¬À´·Ö±ðÃèÊö»ùÓÚI/OÓ³É䷽ʽµÄÕû¸öI/O¶Ë¿Ú¿Õ¼äºÍ»ùÓÚÄÚ´æÓ³É䷽ʽµÄI/OÄÚ´æ×ÊÔ´¿Õ¼ä£¨°üÀ¨I/O¶Ë¿ÚºÍÍâÉèÄڴ棩¡£Æä¶¨ÒåÈçÏ£º


struct resource ioport_resource =
¡¡¡¡¡¡¡¡{ "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO };
struct resource iomem_resource =
¡¡¡¡¡¡¡¡{ "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM };

¡¡¡¡ÆäÖУ¬ºêIO_SPACE_LIMIT±íʾÕû¸öI/O¿Õ¼äµÄ´óС£¬¶ÔÓÚX86ƽ̨¶øÑÔ£¬ËüÊÇ0xffff£¨¶¨ÒåÔÚinclude/asm-i386/io.hÍ·ÎļþÖУ©¡£ÏÔÈ»£¬I/OÄÚ´æ¿Õ¼äµÄ´óСÊÇ4GB¡£

¡¡¡¡3£®4£®2 ¶ÔI/O¶Ë¿Ú¿Õ¼äµÄ²Ù×÷

¡¡¡¡»ùÓÚI/O RegionµÄ²Ù×÷º¯Êý__XXX_region()£¬LinuxÔÚÍ·Îļþinclude/linux/ioport.hÖж¨ÒåÁËÈý¸ö¶ÔI/O¶Ë¿Ú¿Õ¼ä½øÐвÙ×÷µÄºê£º¢Ùrequest_region()ºê£¬ÇëÇóÔÚI/O¶Ë¿Ú¿Õ¼äÖзÖÅäÖ¸¶¨·¶Î§µÄI/O¶Ë¿Ú×ÊÔ´¡£¢Úcheck_region()ºê£¬¼ì²éI/O¶Ë¿Ú¿Õ¼äÖеÄÖ¸¶¨I/O¶Ë¿Ú×ÊÔ´ÊÇ·ñÒѱ»Õ¼ÓᣢÛrelease_region()ºê£¬ÊÍ·ÅI/O¶Ë¿Ú¿Õ¼äÖеÄÖ¸¶¨I/O¶Ë¿Ú×ÊÔ´¡£ÕâÈý¸öºêµÄ¶¨ÒåÈçÏ£º


#define request_region(start,n,name)
        __request_region(&ioport_resource, (start), (n), (name))
#define check_region(start,n)
        __check_region(&ioport_resource, (start), (n))
#define release_region(start,n)
        __release_region(&ioport_resource, (start), (n))

¡¡¡¡ÆäÖУ¬ºê²ÎÊýstartÖ¸¶¨I/O¶Ë¿Ú×ÊÔ´µÄÆðʼÎïÀíµØÖ·£¨ÊÇI/O¶Ë¿Ú¿Õ¼äÖеÄÎïÀíµØÖ·£©£¬ºê²ÎÊýnÖ¸¶¨I/O¶Ë¿Ú×ÊÔ´µÄ´óС¡£

¡¡¡¡3£®4£®3 ¶ÔI/OÄÚ´æ×ÊÔ´µÄ²Ù×÷

¡¡¡¡»ùÓÚI/O RegionµÄ²Ù×÷º¯Êý__XXX_region()£¬LinuxÔÚÍ·Îļþinclude/linux/ioport.hÖж¨ÒåÁËÈý¸ö¶ÔI/OÄÚ´æ×ÊÔ´½øÐвÙ×÷µÄºê£º¢Ùrequest_mem_region()ºê£¬ÇëÇó·ÖÅäÖ¸¶¨µÄI/OÄÚ´æ×ÊÔ´¡£¢Úcheck_ mem_region()ºê£¬¼ì²éÖ¸¶¨µÄI/OÄÚ´æ×ÊÔ´ÊÇ·ñÒѱ»Õ¼ÓᣢÛrelease_ mem_region()ºê£¬ÊÍ·ÅÖ¸¶¨µÄI/OÄÚ´æ×ÊÔ´¡£ÕâÈý¸öºêµÄ¶¨ÒåÈçÏ£º


#define request_mem_region(start,n,name)
¡¡¡¡__request_region(&iomem_resource, (start), (n), (name))
#define check_mem_region(start,n)
        __check_region(&iomem_resource, (start), (n))
#define release_mem_region(start,n)
        __release_region(&iomem_resource, (start), (n))

¡¡¡¡ÆäÖУ¬²ÎÊýstartÊÇI/OÄÚ´æ×ÊÔ´µÄÆðʼÎïÀíµØÖ·£¨ÊÇCPUµÄRAMÎïÀíµØÖ·¿Õ¼äÖеÄÎïÀíµØÖ·£©£¬²ÎÊýnÖ¸¶¨I/OÄÚ´æ×ÊÔ´µÄ´óС¡£

¡¡¡¡3£®4£®4 ¶Ô/proc/ioportsºÍ/proc/iomemµÄÖ§³Ö

¡¡¡¡LinuxÔÚioport.hÍ·ÎļþÖж¨ÒåÁËÁ½¸öºê£º

¡¡¡¡get_ioport_list()ºÍget_iomem_list()£¬·Ö±ðÓÃÀ´ÊµÏÖ/proc/ioportsÎļþºÍ/proc/iomemÎļþ¡£Æä¶¨ÒåÈçÏ£º


#define get_ioport_list(buf) get_resource_list(&ioport_resource, buf, PAGE_SIZE)
#define get_mem_list(buf)        get_resource_list(&iomem_resource, buf, PAGE_SIZE)

3£®5 ·ÃÎÊI/O¶Ë¿Ú¿Õ¼ä

¡¡¡¡ÔÚÇý¶¯³ÌÐòÇëÇóÁËI/O¶Ë¿Ú¿Õ¼äÖеĶ˿Ú×ÊÔ´ºó£¬Ëü¾Í¿ÉÒÔͨ¹ýCPUµÄIOÖ¸¶¨À´¶ÁдÕâЩI/O¶Ë¿ÚÁË¡£ÔÚ¶ÁдI/O¶Ë¿ÚʱҪעÒâµÄÒ»µã¾ÍÊÇ£¬´ó¶àÊýƽ̨¶¼Çø·Ö8λ¡¢16λºÍ32λµÄ¶Ë¿Ú£¬Ò²¼´Òª×¢ÒâI/O¶Ë¿ÚµÄ¿í¶È¡£

¡¡¡¡LinuxÔÚinclude/asm/io.hÍ·Îļþ£¨¶ÔÓÚi386ƽ̨¾ÍÊÇinclude/asm-i386/io.h£©Öж¨ÒåÁËһϵÁжÁд²»Í¬¿í¶ÈI/O¶Ë¿ÚµÄºêº¯Êý¡£ÈçÏÂËùʾ£º

¡¡¡¡¢Å¶Áд8λ¿íµÄI/O¶Ë¿Ú


¡¡¡¡unsigned char inb£¨unsigned port£©£»
¡¡¡¡void outb£¨unsigned char value£¬unsigned port£©£»

¡¡¡¡ÆäÖУ¬port²ÎÊýÖ¸¶¨I/O¶Ë¿Ú¿Õ¼äÖеĶ˿ڵØÖ·¡£ÔÚ´ó¶àÊýƽ̨ÉÏ£¨Èçx86£©Ëü¶¼ÊÇunsigned shortÀàÐ͵쬯äËüµÄһЩƽ̨ÉÏÔòÊÇunsigned intÀàÐ͵ġ£ÏÔÈ»£¬¶Ë¿ÚµØÖ·µÄÀàÐÍÊÇÓÉI/O¶Ë¿Ú¿Õ¼äµÄ´óСÀ´¾ö¶¨µÄ¡£

¡¡¡¡¢Æ¶Áд16λ¿íµÄI/O¶Ë¿Ú


¡¡¡¡unsigned short inw£¨unsigned port£©£»
¡¡¡¡void outw£¨unsigned short value£¬unsigned port£©£»

¡¡¡¡¢Ç¶Áд32λ¿íµÄI/O¶Ë¿Ú


¡¡¡¡unsigned int inl£¨unsigned port£©£»
¡¡¡¡void outl£¨unsigned int value£¬unsigned port£©£»

¡¡¡¡3£®5£®1 ¶ÔI/O¶Ë¿ÚµÄ×Ö·û´®²Ù×÷

¡¡¡¡³ýÁËÉÏÊöÕâЩ¡°µ¥·¢¡±£¨single£­shot£©µÄI/O²Ù×÷Í⣬ijЩCPUÒ²Ö§³Ö¶Ôij¸öI/O¶Ë¿Ú½øÐÐÁ¬ÐøµÄ¶Áд²Ù×÷£¬Ò²¼´¶Ôµ¥¸öI/O¶Ë¿Ú¶Á»òдһϵÁÐ×Ö½Ú¡¢×Ö»ò32λÕûÊý£¬Õâ¾ÍÊÇËùνµÄ¡°×Ö·û´®I/OÖ¸Á£¨String Instruction£©¡£ÕâÖÖÖ¸ÁîÔÚËÙ¶ÈÉÏÏÔȻҪ±ÈÓÃÑ­»·À´ÊµÏÖͬÑùµÄ¹¦ÄÜÒª¿ìµÃ¶à¡£

¡¡¡¡LinuxͬÑùÔÚio.hÎļþÖж¨ÒåÁË×Ö·û´®I/O¶Áдº¯Êý£º

¡¡¡¡¢Å8λ¿íµÄ×Ö·û´®I/O²Ù×÷


¡¡¡¡void insb£¨unsigned port£¬void * addr£¬unsigned long count£©£»
¡¡¡¡void outsb£¨unsigned port £¬void * addr£¬unsigned long count£©£»

¡¡¡¡¢Æ16λ¿íµÄ×Ö·û´®I/O²Ù×÷


¡¡¡¡void insw£¨unsigned port£¬void * addr£¬unsigned long count£©£»
¡¡¡¡void outsw£¨unsigned port £¬void * addr£¬unsigned long count£©£»

¡¡¡¡¢Ç32λ¿íµÄ×Ö·û´®I/O²Ù×÷


¡¡¡¡void insl£¨unsigned port£¬void * addr£¬unsigned long count£©£»
¡¡¡¡void outsl£¨unsigned port £¬void * addr£¬unsigned long count£©£»

¡¡¡¡3£®5£®2 Pausing I/O


¡¡¡¡ÔÚһЩƽ̨ÉÏ£¨µäÐ͵ØÈçX86£©£¬¶ÔÓÚÀÏʽ×ÜÏߣ¨ÈçISA£©ÉϵÄÂýËÙÍâÉèÀ´Ëµ£¬Èç¹ûCPU¶ÁдÆäI/O¶Ë¿ÚµÄËÙ¶ÈÌ«¿ì£¬ÄǾͿÉÄܻᷢÉú¶ªÊ§Êý¾ÝµÄÏÖÏó¡£¶ÔÓÚÕâ¸öÎÊÌâµÄ½â¾ö·½·¨¾ÍÊÇÔÚÁ½´ÎÁ¬ÐøµÄI/O²Ù×÷Ö®¼ä²åÈëÒ»¶Î΢СµÄʱÑÓ£¬ÒÔ±ãµÈ´ýÂýËÙÍâÉè¡£Õâ¾ÍÊÇËùνµÄ¡°Pausing I/O¡±¡£

¡¡¡¡¶ÔÓÚPausing I/O£¬LinuxÒ²ÔÚio.hÍ·ÎļþÖж¨ÒåÁËËüµÄI/O¶Áдº¯Êý£¬¶øÇÒ¶¼ÒÔXXX_pÃüÃû£¬±ÈÈ磺inb_p()¡¢outb_p()µÈµÈ¡£ÏÂÃæÎÒÃǾÍÒÔout_p()ΪÀý½øÐзÖÎö¡£

¡¡¡¡½«io.hÖеĺ궨Òå__OUT(b,¡±b¡±char)Õ¹¿ªºó¿ÉµÃÈç϶¨Ò壺


extern inline void outb(unsigned char value, unsigned short port) {
        __asm__ __volatile__ ("outb %" "b " "0,%" "w" "1"
                                : : "a" (value), "Nd" (port));
}

extern inline void outb_p(unsigned char value, unsigned short port) {
        __asm__ __volatile__ ("outb %" "b " "0,%" "w" "1"
                                __FULL_SLOW_DOWN_IO
                                : : "a" (value), "Nd" (port));
}

¡¡¡¡¿ÉÒÔ¿´³ö£¬outb_p()º¯ÊýµÄʵÏÖÖб»²åÈëÁ˺ê__FULL_SLOWN_DOWN_IO£¬ÒÔʵÏÖ΢СµÄÑÓʱ¡£ºê__FULL_SLOWN_DOWN_IOÔÚÍ·Îļþio.hÖÐÒ»¿ªÊ¼¾Í±»¶¨Ò壺


#ifdef SLOW_IO_BY_JUMPING
#define __SLOW_DOWN_IO "
jmp 1f
1:        jmp 1f
1:"
#else
#define __SLOW_DOWN_IO "
outb %%al,$0x80"
#endif

#ifdef REALLY_SLOW_IO
#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
¡¡¡¡__SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
#else
#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
#endif

¡¡¡¡ÏÔÈ»£¬__FULL_SLOW_DOWN_IO¾ÍÊÇÒ»¸ö»òËĸö__SLOW_DOWN_IO£¨¸ù¾ÝÊÇ·ñ¶¨ÒåÁ˺êREALLY_SLOW_IOÀ´¾ö¶¨£©£¬¶øºê__SLOW_DOWN_IOÔò±»¶¨Òå³ÉºÁÎÞÒâÒåµÄÌø×ªÓï¾ä»òд¶Ë¿Ú0x80µÄ²Ù×÷£¨¸ù¾ÝÊÇ·ñ¶¨ÒåÁ˺êSLOW_IO_BY_JUMPINGÀ´¾ö¶¨£©¡£

3£®6 ·ÃÎÊI/OÄÚ´æ×ÊÔ´

¡¡¡¡¾¡¹ÜI/O¶Ë¿Ú¿Õ¼äÔøÒ»¶ÈÔÚx86ƽ̨Éϱ»¹ã·ºÊ¹Ó㬵«ÊÇÓÉÓÚËü·Ç³£Ð¡£¬Òò´Ë´ó¶àÊýÏÖ´ú×ÜÏßµÄÉ豸¶¼ÒÔÄÚ´æÓ³É䷽ʽ£¨Memory£­mapped£©À´Ó³ÉäËüµÄI/O¶Ë¿Ú£¨Ö¸I/O¼Ä´æÆ÷£©ºÍÍâÉèÄÚ´æ¡£»ùÓÚÄÚ´æÓ³É䷽ʽµÄI/O¶Ë¿Ú£¨Ö¸I/O¼Ä´æÆ÷£©ºÍÍâÉèÄÚ´æ¿ÉÒÔͨ³ÆÎª¡°I/OÄڴ桱×ÊÔ´£¨I/O Memory£©¡£ÒòΪÕâÁ½ÕßÔÚÓ²¼þʵÏÖÉϵIJîÒì¶ÔÓÚÈí¼þÀ´ËµÊÇÍêȫ͸Ã÷µÄ£¬ËùÒÔÇý¶¯³ÌÐò¿ª·¢ÈËÔ±¿ÉÒÔ½«ÄÚ´æÓ³É䷽ʽµÄI/O¶Ë¿ÚºÍÍâÉèÄÚ´æÍ³Ò»¿´×÷ÊÇ¡°I/OÄڴ桱×ÊÔ´¡£

¡¡¡¡´Óǰ¼¸½ÚµÄ²ûÊöÎÒÃÇÖªµÀ£¬I/OÄÚ´æ×ÊÔ´ÊÇÔÚCPUµÄµ¥Ò»ÄÚ´æÎïÀíµØÖ·¿Õ¼äÄÚ½øÐбàÖ·µÄ£¬Ò²¼´ËüºÍϵͳRAMͬ´¦ÔÚÒ»¸öÎïÀíµØÖ·¿Õ¼äÄÚ¡£Òò´Ëͨ¹ýCPUµÄ·ÃÄÚÖ¸Áî¾Í¿ÉÒÔ·ÃÎÊI/OÄÚ´æ×ÊÔ´¡£

¡¡¡¡Ò»°ãÀ´Ëµ£¬ÔÚϵͳÔËÐÐʱ£¬ÍâÉèµÄI/OÄÚ´æ×ÊÔ´µÄÎïÀíµØÖ·ÊÇÒÑÖªµÄ£¬Õâ¿ÉÒÔͨ¹ýϵͳ¹Ì¼þ£¨ÈçBIOS£©ÔÚÆô¶¯Ê±·ÖÅäµÃµ½£¬»òÕßͨ¹ýÉ豸µÄÓ²Á¬Ïߣ¨hardwired£©µÃµ½¡£±ÈÈ磬PCI¿¨µÄI/OÄÚ´æ×ÊÔ´µÄÎïÀíµØÖ·¾ÍÊÇÔÚϵͳÆô¶¯Ê±ÓÉPCI BIOS·ÖÅ䲢дµ½PCI¿¨µÄÅäÖÿռäÖеÄBARÖеġ£¶øISA¿¨µÄI/OÄÚ´æ×ÊÔ´µÄÎïÀíµØÖ·ÔòÊÇͨ¹ýÉ豸ӲÁ¬ÏßÓ³Éäµ½640KB£­1MB·¶Î§Ö®Äڵġ£µ«ÊÇCPUͨ³£²¢Ã»ÓÐΪÕâЩÒÑÖªµÄÍâÉèI/OÄÚ´æ×ÊÔ´µÄÎïÀíµØÖ·Ô¤¶¨ÒåÐéÄâµØÖ··¶Î§£¬ÒòΪËüÃÇÊÇÔÚϵͳÆô¶¯ºó²ÅÒÑÖªµÄ£¨Ä³ÖÖÒâÒåÉϽ²ÊǶ¯Ì¬µÄ£©£¬ËùÒÔÇý¶¯³ÌÐò²¢²»ÄÜÖ±½Óͨ¹ýÎïÀíµØÖ··ÃÎÊI/OÄÚ´æ×ÊÔ´£¬¶ø±ØÐ뽫ËüÃÇÓ³Éäµ½ºËÐÄÐ鵨ַ¿Õ¼äÄÚ£¨Í¨¹ýÒ³±í£©£¬È»ºó²ÅÄܸù¾ÝÓ³ÉäËùµÃµ½µÄºËÐÄÐ鵨ַ·¶Î§£¬Í¨¹ý·ÃÄÚÖ¸Áî·ÃÎÊÕâЩI/OÄÚ´æ×ÊÔ´¡£

¡¡¡¡3£®6£®1 Ó³ÉäI/OÄÚ´æ×ÊÔ´

¡¡¡¡LinuxÔÚio.hÍ·ÎļþÖÐÉùÃ÷Á˺¯Êýioremap£¨£©£¬ÓÃÀ´½«I/OÄÚ´æ×ÊÔ´µÄÎïÀíµØÖ·Ó³Éäµ½ºËÐÄÐ鵨ַ¿Õ¼ä£¨3GB£­4GB£©ÖУ¬ÈçÏ£º


void * ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
void iounmap(void * addr);

¡¡¡¡º¯ÊýÓÃÓÚÈ¡Ïûioremap£¨£©Ëù×öµÄÓ³É䣬²ÎÊýaddrÊÇÖ¸ÏòºËÐÄÐ鵨ַµÄÖ¸Õë¡£ÕâÁ½¸öº¯Êý¶¼ÊÇʵÏÖÔÚmm/ioremap.cÎļþÖС£¾ßÌåʵÏֿɲο¼¡¶Çé¾°·ÖÎö¡·Ò»Êé¡£

¡¡¡¡3£®6£®2 ¶ÁдI/OÄÚ´æ×ÊÔ´

¡¡¡¡ÔÚ½«I/OÄÚ´æ×ÊÔ´µÄÎïÀíµØÖ·Ó³Éä³ÉºËÐÄÐ鵨ַºó£¬ÀíÂÛÉϽ²ÎÒÃǾͿÉÒÔÏó¶ÁдRAMÄÇÑùÖ±½Ó¶ÁдI/OÄÚ´æ×ÊÔ´ÁË¡£µ«ÊÇ£¬ÓÉÓÚÔÚijЩƽ̨ÉÏ£¬¶ÔI/OÄÚ´æºÍϵͳÄÚ´æÓв»Í¬µÄ·ÃÎÊ´¦Àí£¬Òò´ËΪÁËÈ·±£¿çƽ̨µÄ¼æÈÝÐÔ£¬LinuxʵÏÖÁËһϵÁжÁдI/OÄÚ´æ×ÊÔ´µÄº¯Êý£¬ÕâЩº¯ÊýÔÚ²»Í¬µÄƽ̨ÉÏÓв»Í¬µÄʵÏÖ¡£µ«ÔÚx86ƽ̨ÉÏ£¬¶ÁдI/OÄÚ´æÓë¶ÁдRAMÎÞÈκβî±ð¡£ÈçÏÂËùʾ£¨include/asm-i386/io.h£©£º


#define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
#define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
#define readl(addr) (*(volatile unsigned int *) __io_virt(addr))

#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))

#define memset_io(a,b,c)        memset(__io_virt(a),(b),(c))
#define memcpy_fromio(a,b,c) memcpy((a),__io_virt(b),(c))
#define memcpy_toio(a,b,c)        memcpy(__io_virt(a),(b),(c))

¡¡¡¡ÉÏÊö¶¨ÒåÖеĺê__io_virt()½ö½ö¼ì²éÐ鵨ַaddrÊÇ·ñÊǺËÐĿռäÖеÄÐ鵨ַ¡£¸ÃºêÔÚÄÚºË2.4.0ÖеÄʵÏÖÊÇÁÙʱÐԵġ£¾ßÌåµÄʵÏÖº¯ÊýÔÚarch/i386/lib/Iodebug.cÎļþ¡£

¡¡¡¡ÏÔÈ»£¬ÔÚx86ƽ̨ÉÏ·ÃÎÊI/OÄÚ´æ×ÊÔ´Óë·ÃÎÊϵͳÖ÷´æRAMÊÇÎÞ²î±ðµÄ¡£µ«ÊÇΪÁ˱£Ö¤Çý¶¯³ÌÐòµÄ¿çƽ̨µÄ¿ÉÒÆÖ²ÐÔ£¬ÎÒÃÇÓ¦¸ÃʹÓÃÉÏÃæµÄº¯ÊýÀ´·ÃÎÊI/OÄÚ´æ×ÊÔ´£¬¶ø²»Ó¦¸Ãͨ¹ýÖ¸ÏòºËÐÄÐ鵨ַµÄÖ¸ÕëÀ´·ÃÎÊ¡£


[Ŀ¼]


from smth

[Ŀ¼]


»ù±¾½á¹¹

1.UNIXÏÂÉ豸Çý¶¯³ÌÐòµÄ»ù±¾½á¹¹
    ÔÚUNIXϵͳÀ¶ÔÓû§³ÌÐò¶øÑÔ£¬É豸Çý¶¯³ÌÐòÒþ²ØÁËÉ豸µÄ¾ßÌåϸ½Ú£¬¶Ô¸÷ÖÖ²»Í¬É豸ÌṩÁËÒ»ÖµĽӿڣ¬Ò»°ãÀ´ËµÊǰÑÉ豸ӳÉäΪһ¸öÌØÊâµÄÉ豸Îļþ£¬Óû§³ÌÐò¿ÉÒÔÏó¶ÔÆäËüÎļþÒ»Ñù¶Ô´ËÉ豸Îļþ½øÐвÙ×÷¡£UNIX¶ÔÓ²¼þÉ豸֧³ÖÁ½¸ö±ê×¼½Ó¿Ú£º¿éÌØ±ðÉ豸ÎļþºÍ×Ö·ûÌØ±ðÉ豸Îļþ£¬Í¨¹ý¿é£¨×Ö·û£©Ìرð É豸Îļþ´æÈ¡µÄÉ豸³ÆÎª¿é£¨×Ö·û£©É豸»ò¾ßÓп飨×Ö·û£©É豸½Ó¿Ú¡£ ¿éÉ豸½Ó¿Ú½öÖ§³ÖÃæÏò¿éµÄI/O²Ù×÷£¬ËùÓÐI/O²Ù×÷¶¼Í¨¹ýÔÚÄں˵ØÖ·¿Õ¼äÖеÄI/O»º³åÇø½øÐУ¬Ëü¿ÉÒÔÖ§³Ö¼¸ºõÈÎÒⳤ¶ÈºÍÈÎÒâλÖÃÉϵÄI/OÇëÇ󣬼´Ìá¹©Ëæ»ú´æÈ¡µÄ¹¦ÄÜ¡£

    ×Ö·ûÉ豸½Ó¿ÚÖ§³ÖÃæÏò×Ö·ûµÄI/O²Ù×÷£¬Ëü²»¾­¹ýϵͳµÄ¿ìËÙ»º´æ£¬ËùÒÔËüÃǸºÔð¹ÜÀí×Ô¼ºµÄ»º³åÇø½á¹¹¡£×Ö·ûÉ豸½Ó¿ÚÖ»Ö§³Ö˳Ðò´æÈ¡µÄ¹¦ÄÜ£¬Ò»°ã²»ÄܽøÐÐÈÎÒⳤ¶ÈµÄI/OÇëÇ󣬶øÊÇÏÞÖÆI/OÇëÇóµÄ³¤¶È±ØÐëÊÇÉ豸ҪÇóµÄ»ù±¾¿é³¤µÄ±¶Êý¡£ÏÔÈ»£¬±¾³ÌÐòËùÇý¶¯µÄ´®Ðп¨Ö»ÄÜÌṩ˳Ðò´æÈ¡µÄ¹¦ÄÜ£¬ÊôÓÚÊÇ×Ö·ûÉ豸£¬Òò´ËºóÃæµÄÌÖÂÛÔÚÁ½ÖÖÉ豸ÓÐËùÇø±ðʱ¶¼Ö»Éæ¼°×Ö·ûÐÍÉ豸½Ó¿Ú¡£É豸ÓÉÒ»¸öÖ÷É豸ºÅºÍÒ»¸ö´ÎÉ豸ºÅ±êʶ¡£Ö÷É豸ºÅΨһ±êʶÁËÉ豸ÀàÐÍ£¬¼´É豸Çý¶¯³ÌÐòÀàÐÍ£¬ËüÊÇ¿éÉ豸±í»ò×Ö·ûÉ豸±íÖÐÉ豸±íÏîµÄË÷Òý¡£´ÎÉ豸ºÅ½öÓÉÉ豸Çý¶¯³ÌÐò½âÊÍ£¬Ò»°ãÓÃÓÚʶ±ðÔÚÈô¸É¿ÉÄܵÄÓ²¼þÉ豸ÖУ¬I/OÇëÇóËùÉæ¼°µ½µÄÄǸöÉ豸¡£

É豸Çý¶¯³ÌÐò¿ÉÒÔ·ÖΪÈý¸öÖ÷Òª×é³É²¿·Ö£º

    (1) ×Ô¶¯ÅäÖúͳõʼ»¯×Ó³ÌÐò£¬¸ºÔð¼ì²âËùÒªÇý¶¯µÄÓ²¼þÉ豸ÊÇ·ñ´æÔÚºÍÊÇ·ñÄÜÕý³£¹¤×÷¡£Èç¹û¸ÃÉ豸Õý³££¬Ôò¶ÔÕâ¸öÉ豸¼°ÆäÏà¹ØµÄ¡¢É豸Çý¶¯³ÌÐòÐèÒªµÄÈí¼þ״̬½øÐгõʼ»¯¡£Õⲿ·ÖÇý¶¯³ÌÐò½öÔÚ³õʼ»¯µÄʱºò±»µ÷ÓÃÒ»´Î¡£
    (2) ·þÎñÓÚI/OÇëÇóµÄ×Ó³ÌÐò£¬ÓÖ³ÆÎªÇý¶¯³ÌÐòµÄÉϰ벿·Ö¡£µ÷ÓÃÕⲿ·ÖÊÇÓÉÓÚϵͳµ÷ÓõĽá¹û¡£Õⲿ·Ö³ÌÐòÔÚÖ´ÐеÄʱºò£¬ÏµÍ³ÈÔÈÏΪÊǺͽøÐе÷ÓõĽø³ÌÊôÓÚͬһ¸ö½ø³Ì£¬Ö»ÊÇÓÉÓû§Ì¬±ä³ÉÁ˺ËÐÄ̬£¬¾ßÓнøÐдËϵͳµ÷ÓõÄÓû§³ÌÐòµÄÔËÐл·¾³£¬Òò´Ë¿ÉÒÔÔÚÆäÖе÷ÓÃsleep()µÈÓë½ø³ÌÔËÐл·¾³Óйصĺ¯Êý¡£
    (3) ÖжϷþÎñ×Ó³ÌÐò£¬ÓÖ³ÆÎªÇý¶¯³ÌÐòµÄϰ벿·Ö¡£ÔÚUNIXϵͳÖУ¬²¢²»ÊÇÖ±½Ó´ÓÖжÏÏòÁ¿±íÖе÷ÓÃÉ豸Çý¶¯³ÌÐòµÄÖжϷþÎñ×Ó³ÌÐò£¬¶øÊÇÓÉUNIXϵͳÀ´½ÓÊÕÓ²¼þÖжϣ¬ÔÙÓÉϵͳµ÷ÓÃÖжϷþÎñ×Ó³ÌÐò¡£ÖжϿÉÒÔ²úÉúÔÚÈκÎÒ»¸ö½ø³ÌÔËÐеÄʱºò£¬Òò´ËÔÚÖжϷþÎñ³ÌÐò±»µ÷ÓõÄʱºò£¬²»ÄÜÒÀÀµÓÚÈκνø³ÌµÄ״̬£¬Ò²¾Í²»Äܵ÷ÓÃÈκÎÓë½ø³ÌÔËÐл·¾³Óйصĺ¯Êý¡£ÒòΪÉ豸Çý¶¯³ÌÐòÒ»°ãÖ§³ÖͬһÀàÐ͵ÄÈô¸ÉÉ豸£¬ËùÒÔÒ»°ãÔÚϵͳµ÷ÓÃÖжϷþÎñ×Ó³ÌÐòµÄʱºò£¬¶¼´øÓÐÒ»¸ö»ò¶à¸ö²ÎÊý£¬ÒÔΨһ±êʶÇëÇó·þÎñµÄÉ豸¡£

    ÔÚϵͳÄÚ²¿£¬I/OÉ豸µÄ´æÈ¡Í¨¹ýÒ»×é¹Ì¶¨µÄÈë¿ÚµãÀ´½øÐУ¬Õâ×éÈë¿ÚµãÊÇÓÉÿ¸öÉ豸µÄÉ豸Çý¶¯³ÌÐòÌṩµÄ¡£Ò»°ãÀ´Ëµ£¬×Ö·ûÐÍÉ豸Çý¶¯³ÌÐòÄܹ»ÌṩÈçϼ¸¸öÈë¿Úµã£º
(1) openÈë¿Úµã¡£´ò¿ªÉ豸׼±¸I/O²Ù×÷¡£¶Ô×Ö·ûÌØ±ðÉ豸Îļþ½øÐдò¿ª²Ù×÷£¬¶¼»áµ÷ÓÃÉ豸µÄopenÈë¿Úµã¡£open×Ó³ÌÐò±ØÐë¶Ô½«Òª½øÐеÄI/O²Ù×÷×öºÃ±ØÒªµÄ×¼±¸¹¤×÷£¬ÈçÇå³ý»º³åÇøµÈ¡£Èç¹ûÉ豸ÊǶÀÕ¼µÄ£¬¼´Í¬Ò»Ê±¿ÌÖ»ÄÜÓÐÒ»¸ö³ÌÐò·ÃÎÊ´ËÉ豸£¬Ôòopen×Ó³ÌÐò±ØÐëÉèÖÃһЩ±êÖ¾ÒÔ±íʾÉ豸´¦ÓÚæ״̬¡£
(2) closeÈë¿Úµã¡£¹Ø±ÕÒ»¸öÉ豸¡£µ±×îºóÒ»´ÎʹÓÃÉ豸ÖÕ½áºó£¬µ÷ÓÃclose×Ó³ÌÐò¡£¶ÀÕ¼É豸±ØÐë±ê¼ÇÉ豸¿ÉÔÙ´ÎʹÓá£
(3) readÈë¿Úµã¡£´ÓÉ豸É϶ÁÊý¾Ý¡£¶ÔÓÚÓлº³åÇøµÄI/O²Ù×÷£¬Ò»°ãÊÇ´Ó»º³åÇøÀï¶ÁÊý¾Ý¡£¶Ô×Ö·ûÌØ±ðÉ豸Îļþ½øÐжÁ²Ù×÷½«µ÷ÓÃread×Ó³ÌÐò¡£
(4) writeÈë¿Úµã¡£ÍùÉ豸ÉÏдÊý¾Ý¡£¶ÔÓÚÓлº³åÇøµÄI/O²Ù×÷£¬Ò»°ãÊǰÑÊý¾ÝдÈ뻺³åÇøÀï¡£¶Ô×Ö·ûÌØ±ðÉ豸Îļþ½øÐÐд²Ù×÷½«µ÷ÓÃwrite×Ó³ÌÐò¡£
(5) ioctlÈë¿Úµã¡£Ö´ÐжÁ¡¢Ð´Ö®ÍâµÄ²Ù×÷¡£
(6) selectÈë¿Úµã¡£¼ì²éÉ豸£¬¿´Êý¾ÝÊÇ·ñ¿É¶Á»òÉ豸ÊÇ·ñ¿ÉÓÃÓÚдÊý¾Ý¡£selectϵͳµ÷ÓÃÔÚ¼ì²éÓëÉè±¸ÌØ±ðÎļþÏà¹ØµÄÎļþÃèÊö·ûʱʹÓÃselectÈë¿Úµã¡£Èç¹ûÉ豸Çý¶¯³ÌÐòûÓÐÌṩÉÏÊöÈë¿ÚµãÖеÄijһ¸ö£¬ÏµÍ³»áÓÃȱʡµÄ×Ó³ÌÐòÀ´´úÌæ¡£¶ÔÓÚ²»Í¬µÄϵͳ£¬Ò²»¹ÓÐһЩÆäËüµÄÈë¿Úµã¡£


[Ŀ¼]


Çý¶¯³ÌÐò

2.LINUXϵͳϵÄÉ豸Çý¶¯³ÌÐò
    ¾ßÌåµ½LINUXϵͳÀÉ豸Çý¶¯³ÌÐòËùÌṩµÄÕâ×éÈë¿ÚµãÓÉÒ»¸ö½á¹¹À´Ïòϵͳ½øÐÐ˵Ã÷£¬´Ë½á¹¹¶¨ÒåΪ£º

#include <linux/fs.h>
struct file_operations {
        int (*lseek)(struct inode *inode,struct file *filp,
                off_t off,int pos);
        int (*read)(struct inode *inode,struct file *filp,
                char *buf, int count);
        int (*write)(struct inode *inode,struct file *filp,
                char *buf,int count);
        int (*readdir)(struct inode *inode,struct file *filp,
                struct dirent *dirent,int count);
        int (*select)(struct inode *inode,struct file *filp,
                int sel_type,select_table *wait);
        int (*ioctl) (struct inode *inode,struct file *filp,
                unsigned int cmd,unsigned int arg);
        int (*mmap) (void);

        int (*open) (struct inode *inode, struct file *filp);
        void (*release) (struct inode *inode, struct file *filp);
        int (*fsync) (struct inode *inode, struct file *filp);
};

ÆäÖУ¬struct inodeÌṩÁ˹ØÓÚÌØ±ðÉ豸Îļþ/dev/driver£¨¼ÙÉè´ËÉ豸ÃûΪdriver£©µÄÐÅÏ¢£¬ËüµÄ¶¨ÒåΪ£º

#include <linux/fs.h>
struct inode {
        dev_t           i_dev;
        unsigned long    i_ino;  /* Inode number */
        umode_t        i_mode; /* Mode of the file */
        nlink_t          i_nlink;
        uid_t           i_uid;
        gid_t           i_gid;
        dev_t           i_rdev;  /* Device major and minor numbers*/
        off_t            i_size;
        time_t          i_atime;
        time_t          i_mtime;
        time_t          i_ctime;
        unsigned long   i_blksize;
        unsigned long   i_blocks;
        struct inode_operations * i_op;
      struct super_block * i_sb;
        struct wait_queue * i_wait;
        struct file_lock * i_flock;
        struct vm_area_struct * i_mmap;
        struct inode * i_next, * i_prev;
        struct inode * i_hash_next, * i_hash_prev;
        struct inode * i_bound_to, * i_bound_by;
        unsigned short i_count;
        unsigned short i_flags;  /* Mount flags (see fs.h) */
        unsigned char i_lock;
        unsigned char i_dirt;
        unsigned char i_pipe;
        unsigned char i_mount;
        unsigned char i_seek;
        unsigned char i_update;
        union {
                struct pipe_inode_info pipe_i;
                struct minix_inode_info minix_i;
                struct ext_inode_info ext_i;
                struct msdos_inode_info msdos_i;
                struct iso_inode_info isofs_i;
                struct nfs_inode_info nfs_i;
        } u;
};

struct fileÖ÷ÒªÓÃÓÚÓëÎļþϵͳ¶ÔÓ¦µÄÉ豸Çý¶¯³ÌÐòʹÓᣵ±È»£¬ÆäËüÉ豸Çý¶¯³ÌÐòÒ²¿ÉÒÔʹÓÃËü¡£ËüÌṩ¹ØÓÚ±»´ò¿ªµÄÎļþµÄÐÅÏ¢£¬¶¨ÒåΪ£º#include <linux/fs.h>
struct file {
        mode_t f_mode;
        dev_t f_rdev;             /* needed for /dev/tty */
        off_t f_pos;              /* Curr. posn in file */
        unsigned short f_flags;   /* The flags arg passed to open */
        unsigned short f_count;   /* Number of opens on this file */
        unsigned short f_reada;
        struct inode *f_inode;    /* pointer to the inode struct */
        struct file_operations *f_op;/* pointer to the fops struct*/
};

    Ôڽṹfile_operationsÀָ³öÁËÉ豸Çý¶¯³ÌÐòËùÌṩµÄÈë¿ÚµãλÖ㬷ֱðÊÇ
(1) lseek£¬Òƶ¯ÎļþÖ¸ÕëµÄλÖã¬ÏÔȻֻÄÜÓÃÓÚ¿ÉÒÔËæ»ú´æÈ¡µÄÉ豸¡£
(2) read£¬½øÐжÁ²Ù×÷£¬²ÎÊýbufΪ´æ·Å¶ÁÈ¡½á¹ûµÄ»º³åÇø£¬countΪËùÒª¶ÁÈ¡µÄÊý¾Ý³¤¶È¡£·µ»ØÖµÎª¸º±íʾ¶ÁÈ¡²Ù×÷·¢Éú´íÎ󣬷ñÔò·µ»ØÊµ¼Ê¶ÁÈ¡µÄ×Ö½ÚÊý¡£¶ÔÓÚ×Ö·ûÐÍ£¬ÒªÇó¶ÁÈ¡µÄ×Ö½ÚÊýºÍ·µ»ØµÄʵ¼Ê¶ÁÈ¡×Ö½ÚÊý¶¼±ØÐëÊÇinode->i_blksizeµÄµÄ±¶Êý¡£
(3) write£¬½øÐÐд²Ù×÷£¬ÓëreadÀàËÆ¡£
(4) readdir£¬È¡µÃÏÂÒ»¸öĿ¼Èë¿Úµã£¬Ö»ÓÐÓëÎļþϵͳÏà¹ØµÄÉ豸Çý¶¯³ÌÐò²ÅʹÓá£
(5) selec£¬½øÐÐÑ¡Ôñ²Ù×÷£¬Èç¹ûÇý¶¯³ÌÐòûÓÐÌṩselectÈë¿Ú£¬select²Ù×÷½«»áÈÏΪÉ豸ÒѾ­×¼±¸ºÃ½øÐÐÈκεÄI/O²Ù×÷¡£
(6) ioctl£¬½øÐжÁ¡¢Ð´ÒÔÍâµÄÆäËü²Ù×÷£¬²ÎÊýcmdΪ×Ô¶¨ÒåµÄµÄÃüÁî¡£
(7) mmap£¬ÓÃÓÚ°ÑÉ豸µÄÄÚÈÝÓ³Éäµ½µØÖ·¿Õ¼ä£¬Ò»°ãÖ»ÓпéÉ豸Çý¶¯³ÌÐòʹÓá£
(8) open£¬´ò¿ªÉ豸׼±¸½øÐÐI/O²Ù×÷¡£·µ»Ø0±íʾ´ò¿ª³É¹¦£¬·µ»Ø¸ºÊý±íʾʧ°Ü¡£Èç¹ûÇý¶¯³ÌÐòûÓÐÌṩopenÈë¿Ú£¬ÔòÖ»Òª/dev/driverÎļþ´æÔÚ¾ÍÈÏΪ´ò¿ª³É¹¦¡£
(9) release£¬¼´close²Ù×÷¡£
    É豸Çý¶¯³ÌÐòËùÌṩµÄÈë¿Úµã£¬ÔÚÉ豸Çý¶¯³ÌÐò³õʼ»¯µÄʱºòÏòϵͳ½øÐеǼǣ¬ÒÔ±ãϵͳÔÚÊʵ±µÄʱºòµ÷Óá£LINUXϵͳÀͨ¹ýµ÷ÓÃregister_chrdevÏòϵͳע²á×Ö·ûÐÍÉ豸Çý¶¯³ÌÐò¡£register_chrdev¶¨ÒåΪ£º

#include <linux/fs.h>
#include <linux/errno.h>
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);

    ÆäÖУ¬majorÊÇΪÉ豸Çý¶¯³ÌÐòÏòϵͳÉêÇëµÄÖ÷É豸ºÅ£¬Èç¹ûΪ0ÔòϵͳΪ´ËÇý¶¯³ÌÐò¶¯Ì¬µØ·ÖÅäÒ»¸öÖ÷É豸ºÅ¡£nameÊÇÉ豸Ãû¡£fops¾ÍÊÇÇ°ÃæËù˵µÄ¶Ô¸÷¸öµ÷ÓõÄÈë¿ÚµãµÄ˵Ã÷¡£´Ëº¯Êý·µ»Ø0±íʾ³É¹¦¡£·µ»Ø-EINVAL±íʾÉêÇëµÄÖ÷É豸ºÅ·Ç·¨£¬Ò»°ãÀ´ËµÊÇÖ÷É豸ºÅ´óÓÚϵͳËùÔÊÐíµÄ×î´óÉ豸ºÅ¡£·µ»Ø-EBUSY±íʾËùÉêÇëµÄÖ÷É豸ºÅÕýÔÚ±»ÆäËüÉ豸Çý¶¯³ÌÐòʹÓá£Èç¹ûÊǶ¯Ì¬·ÖÅäÖ÷É豸ºÅ³É¹¦£¬´Ëº¯Êý½«·µ»ØËù·ÖÅäµÄÖ÷É豸ºÅ¡£Èç¹ûregister_chrdev²Ù×÷³É¹¦£¬É豸Ãû¾Í»á³öÏÖÔÚ/proc/devicesÎļþÀï¡£
    ³õʼ»¯²¿·ÖÒ»°ã»¹¸ºÔð¸øÉ豸Çý¶¯³ÌÐòÉêÇëϵͳ×ÊÔ´£¬°üÀ¨ÄÚ´æ¡¢Öжϡ¢Ê±ÖÓ¡¢I/O¶Ë¿ÚµÈ£¬ÕâЩ×ÊÔ´Ò²¿ÉÒÔÔÚopen×Ó³ÌÐò»ò±ðµÄµØ·½ÉêÇë¡£ÔÚÕâЩ×ÊÔ´²»ÓõÄʱºò£¬Ó¦¸ÃÊÍ·ÅËüÃÇ£¬ÒÔÀûÓÚ×ÊÔ´µÄ¹²Ïí¡£ÔÚUNIXϵͳÀ¶ÔÖжϵĴ¦ÀíÊÇÊôÓÚϵͳºËÐĵIJ¿·Ö£¬Òò´ËÈç¹ûÉ豸Óëϵͳ֮¼äÒÔÖжϷ½Ê½½øÐÐÊý¾Ý½»»»µÄ»°£¬¾Í±ØÐë°Ñ¸ÃÉ豸µÄÇý¶¯³ÌÐò×÷ΪϵͳºËÐĵÄÒ»²¿·Ö¡£É豸Çý¶¯³ÌÐòͨ¹ýµ÷ÓÃrequest_irqº¯ÊýÀ´ÉêÇëÖжϣ¬Í¨¹ýfree_irqÀ´ÊÍ·ÅÖжϡ£ËüÃǵ͍ÒåΪ£º

#include <linux/sched.h>
int request_irq(unsigned int irq,
            void (*handler)(int irq,void dev_id,struct pt_regs *regs),
            unsigned long flags,
            const char *device,
            void *dev_id);
void free_irq(unsigned int irq, void *dev_id);

    ²ÎÊýirq±íʾËùÒªÉêÇëµÄÓ²¼þÖжϺš£handlerΪÏòϵͳµÇ¼ÇµÄÖжϴ¦Àí×Ó³ÌÐò£¬ÖжϲúÉúʱÓÉϵͳÀ´µ÷Ó㬵÷ÓÃʱËù´ø²ÎÊýirqΪÖжϺţ¬dev_idΪÉêÇëʱ¸æËßϵͳµÄÉ豸±êʶ£¬regsΪÖжϷ¢Éúʱ¼Ä´æÆ÷ÄÚÈÝ¡£deviceΪÉ豸Ãû£¬½«»á³öÏÖÔÚ/proc/interruptsÎļþÀï¡£flagÊÇÉêÇëʱµÄÑ¡ÏËü¾ö¶¨Öжϴ¦Àí³ÌÐòµÄÒ»Ð©ÌØÐÔ£¬ÆäÖÐ×îÖØÒªµÄÊÇÖжϴ¦Àí³ÌÐòÊÇ¿ìËÙ´¦Àí³ÌÐò£¨flagÀïÉèÖÃÁËSA_INTERRUPT£©»¹ÊÇÂýËÙ´¦Àí³ÌÐò£¨²»ÉèÖÃSA_INTERRUPT£©£¬¿ìËÙ´¦Àí³ÌÐòÔËÐÐʱ£¬ËùÓÐÖж϶¼±»ÆÁ±Î£¬¶øÂýËÙ´¦Àí³ÌÐòÔËÐÐʱ£¬³ýÁËÕýÔÚ´¦ÀíµÄÖжÏÍ⣬ÆäËüÖж϶¼Ã»Óб»ÆÁ±Î¡£

    ÔÚLINUXϵͳÖУ¬ÖжϿÉÒÔ±»²»Í¬µÄÖжϴ¦Àí³ÌÐò¹²Ïí£¬ÕâÒªÇóÿһ¸ö¹²Ïí´ËÖжϵĴ¦Àí³ÌÐòÔÚÉêÇëÖжÏʱÔÚflagsÀïÉèÖÃSA_SHIRQ£¬ÕâЩ´¦Àí³ÌÐòÖ®¼äÒÔdev_idÀ´Çø·Ö¡£Èç¹ûÖжÏÓÉij¸ö´¦Àí³ÌÐò¶ÀÕ¼£¬Ôòdev_id¿ÉÒÔΪNULL¡£request_irq·µ»Ø0±íʾ³É¹¦£¬·µ»Ø-INVAL±íʾirq>15»òhandler==NULL£¬·µ»Ø-EBUSY±íʾÖжÏÒѾ­±»Õ¼ÓÃÇÒ²»Äܹ²Ïí¡£×÷ΪϵͳºËÐĵÄÒ»²¿·Ö£¬É豸Çý¶¯³ÌÐòÔÚÉêÇëºÍÊÍ·ÅÄÚ´æÊ±²»Êǵ÷ÓÃmallocºÍfree£¬¶ø´úÖ®ÒÔµ÷ÓÃkmallocºÍkfree£¬ËüÃDZ»¶¨ÒåΪ£º

#include <linux/kernel.h>
void * kmalloc(unsigned int len, int priority);
void kfree(void * obj);

    ²ÎÊýlenΪϣÍûÉêÇëµÄ×Ö½ÚÊý£¬objΪҪÊͷŵÄÄÚ´æÖ¸Õë¡£priorityΪ·ÖÅäÄÚ´æ²Ù×÷µÄÓÅÏȼ¶£¬¼´ÔÚûÓÐ×ã¹»¿ÕÏÐÄÚ´æÊ±ÈçºÎ²Ù×÷£¬Ò»°ãÓÃGFP_KERNEL¡£ÓëÖжϺÍÄڴ治ͬ£¬Ê¹ÓÃÒ»¸öûÓÐÉêÇëµÄI/O¶Ë¿Ú²»»áʹCPU²úÉúÒì³££¬Ò²¾Í²»»áµ¼ÖÂÖîÈç¡°segmentation fault"Ò»ÀàµÄ´íÎó·¢Éú¡£Èκνø³Ì¶¼¿ÉÒÔ·ÃÎÊÈκÎÒ»¸öI/O¶Ë¿Ú¡£´ËʱϵͳÎÞ·¨±£Ö¤¶ÔI/O¶Ë¿ÚµÄ²Ù×÷²»»á·¢Éú³åÍ»£¬ÉõÖÁ»áÒò´Ë¶øÊ¹ÏµÍ³±ÀÀ£¡£Òò´Ë£¬ÔÚʹÓÃI/O¶Ë¿Úǰ£¬Ò²Ó¦¸Ã¼ì²é´ËI/O¶Ë¿ÚÊÇ·ñÒÑÓбðµÄ³ÌÐòÔÚʹÓã¬ÈôûÓУ¬ÔٰѴ˶˿ڱê¼ÇΪÕýÔÚʹÓã¬ÔÚʹÓÃÍêÒÔºóÊÍ·ÅËü¡£ÕâÑùÐèÒªÓõ½Èçϼ¸¸öº¯Êý£º

int check_region(unsigned int from, unsigned int extent);
void request_region(unsigned int from, unsigned int extent, const char *name);
void release_region(unsigned int from, unsigned int extent);

    µ÷ÓÃÕâЩº¯ÊýʱµÄ²ÎÊýΪ£ºfrom±íʾËùÉêÇëµÄI/O¶Ë¿ÚµÄÆðʼµØÖ·£»extentΪËùÒªÉêÇëµÄ´Ófrom¿ªÊ¼µÄ¶Ë¿ÚÊý£»nameΪÉ豸Ãû£¬½«»á³öÏÖÔÚ/proc/ioportsÎļþÀï¡£check_region·µ»Ø0±íʾI/O¶Ë¿Ú¿ÕÏУ¬·ñÔòΪÕýÔÚ±»Ê¹Óá£
ÔÚÉêÇëÁËI/O¶Ë¿ÚÖ®ºó£¬¾Í¿ÉÒÔÈçϼ¸¸öº¯ÊýÀ´·ÃÎÊI/O¶Ë¿Ú£º

#include <asm/io.h>
inline unsigned int inb(unsigned short port);
inline unsigned int inb_p(unsigned short port);
inline void outb(char value, unsigned short port);
inline void outb_p(char value, unsigned short port);

    ÆäÖÐinb_pºÍoutb_p²åÈëÁËÒ»¶¨µÄÑÓʱÒÔÊÊӦijЩÂýµÄI/O¶Ë¿Ú¡£ÔÚÉ豸Çý¶¯³ÌÐòÀһ°ã¶¼ÐèÒªÓõ½¼ÆÊ±»úÖÆ¡£ÔÚLINUXϵͳÖУ¬Ê±ÖÓÊÇÓÉϵͳ½Ó¹Ü£¬É豸Çý¶¯³ÌÐò¿ÉÒÔÏòϵͳÉêÇëʱÖÓ¡£ÓëʱÖÓÓйصÄϵͳµ÷ÓÃÓУº

#include <asm/param.h>
#include <linux/timer.h>
void add_timer(struct timer_list * timer);
int  del_timer(struct timer_list * timer);
inline void init_timer(struct timer_list * timer);

struct timer_listµÄ¶¨ÒåΪ£º

struct timer_list {
               struct timer_list *next;
               struct timer_list *prev;
               unsigned long expires;
               unsigned long data;
               void (*function)(unsigned long d);
       };

    ÆäÖÐexpiresÊÇÒªÖ´ÐÐfunctionµÄʱ¼ä¡£ÏµÍ³ºËÐÄÓÐÒ»¸öÈ«¾Ö±äÁ¿JIFFIES±íʾµ±Ç°Ê±¼ä£¬Ò»°ãÔÚµ÷ÓÃadd_timerʱjiffies=JIFFIES+num,±íʾÔÚnum¸öϵͳ×îСʱ¼ä¼ä¸ôºóÖ´ÐÐfunction¡£ÏµÍ³×îСʱ¼ä¼ä¸ôÓëËùÓõÄÓ²¼þƽ̨Óйأ¬ÔÚºËÐÄÀﶨÒåÁ˳£ÊýHZ±íʾһÃëÄÚ×îСʱ¼ä¼ä¸ôµÄÊýÄ¿£¬Ôònum*HZ±íʾnumÃ롣ϵͳ¼ÆÊ±µ½Ô¤¶¨Ê±¼ä¾Íµ÷ÓÃfunction£¬²¢°Ñ´Ë×Ó³ÌÐò´Ó¶¨Ê±¶ÓÁÐÀïɾ³ý£¬Òò´ËÈç¹ûÏëҪÿ¸ôÒ»¶¨Ê±¼ä¼ä¸ôÖ´ÐÐÒ»´ÎµÄ»°£¬¾Í±ØÐëÔÚfunctionÀïÔÙÒ»´Îµ÷ÓÃadd_timer¡£functionµÄ²ÎÊýd¼´ÎªtimerÀïÃæµÄdataÏî¡£ÔÚÉ豸Çý¶¯³ÌÐòÀ»¹¿ÉÄÜ»áÓõ½ÈçϵÄһЩϵͳº¯Êý£º

#include <asm/system.h>
#define cli() __asm__ __volatile__ ("cli"::)
#define sti() __asm__ __volatile__ ("sti"::)

ÕâÁ½¸öº¯Êý¸ºÔð´ò¿ªºÍ¹Ø±ÕÖжÏÔÊÐí¡£

#include <asm/segment.h>
void memcpy_fromfs(void * to,const void * from,unsigned long n);
void memcpy_tofs(void * to,const void * from,unsigned long n);

    ÔÚÓû§³ÌÐòµ÷ÓÃread ¡¢writeʱ£¬ÒòΪ½ø³ÌµÄÔËÐÐ״̬ÓÉÓû§Ì¬±äΪºËÐÄ̬£¬µØÖ·¿Õ¼äÒ²±äΪºËÐĵØÖ·¿Õ¼ä¡£¶øread¡¢writeÖвÎÊýbufÊÇÖ¸ÏòÓû§³ÌÐòµÄ˽ÓеØÖ·¿Õ¼äµÄ£¬ËùÒÔ²»ÄÜÖ±½Ó·ÃÎÊ£¬±ØÐëͨ¹ýÉÏÊöÁ½¸öϵͳº¯ÊýÀ´·ÃÎÊÓû§³ÌÐòµÄ˽ÓеØÖ·¿Õ¼ä¡£memcpy_fromfsÓÉÓû§³ÌÐòµØÖ·¿Õ¼äÍùºËÐĵØÖ·¿Õ¼ä¸´ÖÆ£¬memcpy_tofsÔò·´Ö®¡£²ÎÊýtoΪ¸´ÖƵÄÄ¿µÄÖ¸Õ룬fromΪԴָÕ룬nΪҪ¸´ÖƵÄ×Ö½ÚÊý¡£ÔÚÉ豸Çý¶¯³ÌÐòÀ¿ÉÒÔµ÷ÓÃprintkÀ´´òӡһЩµ÷ÊÔÐÅÏ¢£¬Ó÷¨ÓëprintfÀàËÆ¡£printk´òÓ¡µÄÐÅÏ¢²»½ö³öÏÖÔÚÆÁÄ»ÉÏ£¬Í¬Ê±»¹¼Ç¼ÔÚÎļþsyslogÀï¡£


[Ŀ¼]


¾ßÌåʵÏÖ

3.LINUXϵͳϵľßÌåʵÏÖ
    ÔÚLINUXÀ³ýÁËÖ±½ÓÐÞ¸ÄϵͳºËÐĵÄÔ´´úÂ룬°ÑÉ豸Çý¶¯³ÌÐò¼Ó½øºËÐÄÀïÒÔÍ⣬»¹¿ÉÒÔ°ÑÉ豸Çý¶¯³ÌÐò×÷Ϊ¿É¼ÓÔØµÄÄ£¿é£¬ÓÉϵͳ¹ÜÀíÔ±¶¯Ì¬µØ¼ÓÔØËü£¬Ê¹Ö®³ÉΪºËÐĵØÒ»²¿·Ö¡£Ò²¿ÉÒÔÓÉϵͳ¹ÜÀíÔ±°ÑÒѼÓÔØµØÄ£¿é¶¯Ì¬µØÐ¶ÔØÏÂÀ´¡£

    LINUXÖУ¬Ä£¿é¿ÉÒÔÓÃCÓïÑÔ±àд£¬ÓÃgcc±àÒë³ÉÄ¿±êÎļþ£¨²»½øÐÐÁ´½Ó£¬×÷Ϊ*.oÎļþ´æÔÚ£©£¬Îª´ËÐèÒªÔÚgccÃüÁîÐÐÀï¼ÓÉÏ-cµÄ²ÎÊý¡£ÔÚ±àÒëʱ£¬»¹Ó¦¸ÃÔÚgccµÄÃüÁîÐÐÀï¼ÓÉÏÕâÑùµÄ²ÎÊý£º-D__KERNEL__ -DMODULE¡£ÓÉÓÚÔÚ²»Á´½Óʱ£¬gccÖ»ÔÊÐíÒ»¸öÊäÈëÎļþ£¬Òò´ËÒ»¸öÄ£¿éµÄËùÓв¿·Ö¶¼±ØÐëÔÚÒ»¸öÎļþÀïʵÏÖ¡£±àÒëºÃµÄÄ£¿é*.o·ÅÔÚ/lib/modules/xxxx/miscÏ£¨xxxx±íʾºËÐİ汾£¬ÈçÔÚºËÐİ汾Ϊ2.0.30ʱӦ¸ÃΪ/lib/modules/2.0.30/misc£©£¬È»ºóÓÃdepmod -aʹ´ËÄ£¿é³ÉΪ¿É¼ÓÔØÄ£¿é¡£Ä£¿éÓÃinsmodÃüÁî¼ÓÔØ£¬ÓÃrmmodÃüÁîÀ´Ð¶ÔØ£¬²¢¿ÉÒÔÓÃlsmodÃüÁîÀ´²é¿´ËùÓÐÒѼÓÔØµÄÄ£¿éµÄ״̬¡£

    ±àдģ¿é³ÌÐòµÄʱºò£¬±ØÐëÌṩÁ½¸öº¯Êý£¬Ò»¸öÊÇint init_module(void)£¬¹©insmodÔÚ¼ÓÔØ´ËÄ£¿éµÄʱºò×Ô¶¯µ÷Ó㬸ºÔð½øÐÐÉ豸Çý¶¯³ÌÐòµÄ³õʼ»¯¹¤×÷¡£init_module·µ»Ø0ÒÔ±íʾ³õʼ»¯³É¹¦£¬·µ»Ø¸ºÊý±íʾʧ°Ü¡£ÁíÒ»¸öº¯ÊýÊÇvoidcleanup_module (void)£¬ÔÚÄ£¿é±»Ð¶ÔØÊ±µ÷Ó㬸ºÔð½øÐÐÉ豸Çý¶¯³ÌÐòµÄÇå³ý¹¤×÷¡£

    Ôڳɹ¦µÄÏòϵͳע²áÁËÉ豸Çý¶¯³ÌÐòºó£¨µ÷ÓÃregister_chrdev³É¹¦ºó£©£¬¾Í¿ÉÒÔÓÃmknodÃüÁîÀ´°ÑÉ豸ӳÉäΪһ¸öÌØ±ðÎļþ£¬ÆäËü³ÌÐòʹÓÃÕâ¸öÉ豸µÄʱºò£¬Ö»Òª¶Ô´ËÌØ±ðÎļþ½øÐвÙ×÷¾ÍÐÐÁË¡£

[Ŀ¼]


PCI

    PCIÊÇÒ»Öֹ㷺²ÉÓõÄ×ÜÏß±ê×¼£¬ËüÌṩÁËÓÅÓÚÆäËû×ÜÏß±ê×¼£¨±ÈÈçEISA£©µÄÌØÐÔ¡£ÔÚ´ó¶àÊý±¼ÌÚÖ÷°åÉÏ£¬PCIÊǸßËÙ¡¢¸ß´ø¿í£¨32-bitºÍ64-bit£©¡¢´¦ÀíÆ÷Î޹صÄ×ÜÏß¡£¶ÔPCIµÄÖ§³ÖµÚÒ»´Î¼ÓÈëLinuxÖÐʱ£¬ÆäÄں˽ӿÚÊÇPCI BIOS32º¯ÊýµÄ¶ÑÆö¡£ÕâÑù×öÓм¸¸öÎÊÌ⣺

* PCI BIOS½ö´æÔÚÓÚPCÉÏ£»
* PCI BIOSÖ»´ú±íÌØ¶¨µÄ½á¹¹£¬·ÇPCÀà»úÆ÷µÄijЩPCIÉèÖò»ÄÜÓÃPCI BIOSÀ´ÃèÊö£»
* ¸ö±ð»ú×ÓµÄPCI BIOSº¯Êý²»ÏóÔ¤ÆÚµÄÄÇÑù¹¤×÷¡£

    Linux 2.2ÌṩÁËÒ»¸öͨÓõÄPCI½Ó¿Ú¡£Linux x86ÄÚºËʵ¼ÊÉÏŬÁ¦Ö±½ÓÇý¶¯Ó²¼þ£¬Ö»Óе±Ëü·¢ÏÖijЩ¶«Î÷²»ÄÜÀí½âʱ£¬Ëü²Å»áµ÷ÓÃPCI BIOS32º¯Êý¡£
Çý¶¯³ÌÐò¿ÉÒÔ¼ÌÐøÊ¹ÓÃÀϵÄPCI½Ó¿Ú£¬µ«ÊÇΪÁ˼æÈݽ«À´µÄÄںˣ¬¿ÉÄÜÐèÒª¸üС£
    Èç¹ûÇý¶¯³ÌÐò½«Òª¿çƽ̨¹¤×÷£¬ÄǾ͸ü¼ÓÐèÒª¸üÐÂÁË¡£¶àÊýС¢ÀϺ¯ÊýÓмòµ¥µÄ¶ÔÓ¦¹ØÏµ¡£PCI BIOS»ùÓÚ×ÜÏߺÅ/É豸ºÅ/¹¦ÄܺŵÄ˼Ï룬¶øÐµĴúÂëʹÓÃpci_busºÍpci_dev½á¹¹¡£µÚÒ»¸öÐÂPCIº¯ÊýÊÇ£º

pci_present()

    Õâ¸öº¯Êý¼ì²é»úÆ÷ÊÇ·ñ´æÔÚÒ»Ìõ»ò¸ü¶àµÄPCI×ÜÏß¡£ÀÏÄÚºËÓÐÒ»¸öpcibios_present()º¯Êý£¬ËüÃǵÄÓ÷¨ÍêÈ«Ïàͬ¡£

    È·ÈÏPCI´æÔÚÖ®ºó£¬Äã¿ÉÒÔɨÃèPCI×ÜÏßÀ´²éÕÒÉ豸¡£PCIÉ豸ͨ¹ý¼¸¸öÅäÖüĴæÆ÷À´±êʶ£¬Ö÷ÒªÊǹ©Ó¦ÉÌIDºÍÉ豸ID¡£Ã¿¸ö¹©Ó¦É̱»·ÖÅäÁËÒ»¸öΨһµÄ±êʶ£¨ID£©£¬²¢ÇÒ¼ÙÉ蹩ӦÉ̸øËûÃǵÄÉ豸£¨°å×Ó¡¢Ð¾Æ¬µÈ£©·ÖÅäΨһµÄÉ豸ID¡£PCIµÄÒ»¸öºÃ´¦ÊÇËüÌṩÁ˰汾ºÍ±à³Ì½Ó¿ÚÐÅÏ¢£¬Òò´Ë¿ÉÒÔ·¢ÏÖ°å×ӵı仯¡£

    ÔÚLinux 2.2ÖУ¬É¨ÃèPCI×ÜÏßÒ»°ãÓÃpci_find_device()º¯Êý¡£·¶ÀýÈçÏ£º

struct pci_dev *pdev = NULL;
while ((pdev = pci_find_device(PCI_MY_VENDOR,
PCI_MY_DEVICE, pdev)) != NULL)
{
/* Found a device */
setup_device(pdev);
}

    pci_find_device()ÓÐ3¸ö²ÎÊý£ºµÚÒ»¸öÊǹ©Ó¦ÉÌID£¬µÚ¶þ¸öÊÇÉ豸ID£¬µÚÈý¸öÊǺ¯ÊýµÄ·µ»ØÖµ£¬NULL±íʾÄãÏë´ÓÍ·¿ªÊ¼²éÕÒ¡£ÔÚÕâ¸öÀý×ÓÖУ¬¶ÔÕÒµ½µÄÉ豸µ÷ÓÃsetup_device()À´½øÐÐÉèÖá£

    ÁíÒ»¸öÖµµÃ¸ßÐ˵ÄÊÂÇ飬ÊÇPCIΪÄã´¦ÀíÁËËùÓÐ×ÊÔ´ÅäÖù¤×÷¡£Ò»°ãÀ´ËµPCI BIOS¾ßÌå×öÕâЩ¹¤×÷£¬µ«ÊÇÔÚÆäËûƽ̨ÉÏ£¬ÕâÏ×÷Óɹ̼þ»òÕßÌåϵ½á¹¹Ïà¹ØµÄLinux´úÂëÀ´×ö¡£µ½ÄãµÄÇý¶¯³ÌÐò²éÕÒPCI¿¨µÄʱºò£¬ËüÒѾ­±»·ÖÅäÁËϵͳ×ÊÔ´¡£

    LinuxÔÚpci_dev½á¹¹ÖÐÌṩÁËPCIÏà¹ØµÄºËÐÄÐÅÏ¢¡£Í¬Ê±»¹ÔÊÐí¶Áдÿ¸ö¿¨µÄPCIÅäÖÿռ䡣µ±Äã¿ÉÒÔÖ±½Ó²éÕÒ×ÊÔ´Êý¾ÝʱӦ¸ÃСÐÄ£¬¶ÔÐí¶àϵͳÀ´Ëµ£¬¿¨ÉÏÅäÖõÄÊý¾ÝÓëÄÚºËÌṩµÄÊý¾Ý²¢²»Ïà·û¡£ÒòΪÐí¶à·ÇPC»úÆ÷ÓжàÌõPCI×ÜÏߣ¬PCI×ÜÏßÒÔÉ豸¿¨²»ÖªµÀµÄ·½Ê½Ó³É䵽ϵͳÖС£

    LinuxÖ±½ÓÌṩÁËIRQºÍPCI BARs£¨»ùÖ·¼Ä´æÆ÷£©¡£ÎªÁ˱ÜÃâ´úÂëÔÚ·ÇPCƽ̨ÉϳöÏÖÒâÍ⣬ÄãÓ¦¸Ã×ÜÊÇʹÓÃÄÚºËÌṩµÄÊý¾Ý¡£ÏÂÃæ´úÂëÁгöÁËsetup_device()Àý³Ì£º

Listing One: The setup_device () Function
void setup_device(struct pci_dev *dev)
{
int io_addr = dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
int irq = dev->irq;
u8 rev;

pci_read_config_byte(dev, PCI_REVISION_ID, &rev);

if (rev<64)
printk("Found a WonderWidget 500 at I/O 0x%04X, IRQ %d.\n",
io_addr, irq);
else
printk("Found a WonderWidget 600 at I/O 0x%04X, IRQ %d.\n",
io_addr, irq);

/* Check for a common BIOS problem - if you
* expect an IRQ you might not get it */
if (irq==0)
{
printk(KERN_ERR "BIOS has not assigned the WonderWidget"
" an interrupt.\n");
return;
}

/* Now do the board initialization knowing the resources */
init_device(io_addr, irq, rev<64 ? 0 : 1);

pci_set_master(dev);
}

    µ±ÄãµÄ¿¨±»BIOSÅäÖúó£¬Ä³Ð©ÌØÐÔ¿ÉÄܻᱻÆÁ±Îµô¡£±ÈÈ磬¶àÊýBIOS¶¼»áÇåµô¡°master¡±Î»£¬Õâµ¼Ö°忨²»ÄÜËæÒâÏòÖ÷´æÖп½±´Êý¾Ý¡£Linux 2.2ÌṩÁËÒ»¸ö¸¨Öúº¯Êý£º

pci_set_master(struct pci_dev *)

    Õâ¸öº¯Êý»á¼ì²éÊÇ·ñÐèÒªÉèÖñê־룬Èç¹ûÐèÒª£¬Ôò»á½«¡°master¡±Î»ÖÃλ¡£Àý×Óº¯Êýsetup_device»¹Ê¹ÓÃÁËpci_read_config_byteÀ´¶ÁÈ¡ÅäÖÿռäÊý¾Ý¡£ÄÚºËÌṩÁËÒ»ÕûÌ×ÓëÅäÖÿռäÏà¹ØµÄº¯Êý£º

pci_read_config_byte£¬
pci_read_config_word£¬
ºÍpci_read_config_dword

·Ö±ð´ÓÅäÖÿռä»ñÈ¡8£¬16ºÍ32λÊý¾Ý£»

pci_write_config_byte£¬
pci_write_config_word£¬
ºÍpci_write_config_dword

·Ö±ðÏòÅäÖÿռäдÈë8£¬16ºÍ32λÊý¾Ý¡£PCIÅäÖÿռä¶ÀÁ¢ÓÚI/OºÍÄÚ´æ¿Õ¼ä£¬Ö»ÄÜͨ¹ýÕâЩº¯Êý·ÃÎÊ¡£

    ×îºóÒ»×éÓÐÓõÄPCIº¯ÊýÒÔ²»Í¬µÄ·½Ê½É¨ÃèPCI×ÜÏß¡£pci_find_class²éÕÒ·ûºÏ¸ø¶¨Àà±ð£¨class£©µÄÉ豸¡£PCI¹æ·¶°ÑÉ豸·ÖΪ²»Í¬µÄÀà±ð£¬Äã¿ÉÒÔ¸ù¾ÝÀà±ð²éÕÒÉ豸¡£ÀýÈ磬ΪÁ˲éÕÒÒ»¸öUSB¿ØÖÆÆ÷£¬¿ÉÒÔÓÃ

struct pci_dev *pdev = NULL;
while((pdev=pci_find_class
(PCI_CLASS_SERIAL_USB <<8, pdev))!=NULL)
{
u8 type;
pci_read_config_byte(dev,
PCI_CLASS_PROG, &type);
if(type!=0)
continue;
/* FOUND IT */
}

    ÁíÒ»¸öÀý×ÓÊÇI2O¡£Õâʱ£¬¹©Ó¦ÉÌIDÖ»ÓÃÀ´È·¶¨°å¿¨µÄʵ¼ÊÀàÐÍ£¨type£©£¬Å¼¶ûÓÃÀ´¶Ô¸¶Ìض¨°å¿¨µÄbug¡£

    ɨÃèPCIÉ豸µÄ×îºóÒ»ÖÖ;¾¶ÊÇpci_find_slot£¬Ê¹Äã°´ÕÕÌØ¶¨µÄ˳ÐòɨÃèPCI²å²ÛºÍ¹¦ÄÜ¡£ËüºÜÉÙʹÓ㬵«ÊÇ£¬Èç¹ûÄãÒª¿ØÖƲéÕÒijһÀàÐÍÉ豸ʱɨÃèPCI×ÜÏßµÄ˳Ðò£¬Äã¿ÉÒÔÓÃËü¡£ÕâÖÖÇé¿öͨ³£³öÏÖÔÚÄãÐèÒª×ñÕÕÖ÷°åBIOS±¨¸æÉ豸µÄ˳Ðòʱ£¬»òÕßÄãÏëʹLinuxºÍ·ÇLinuxÇý¶¯³ÌÐòÒÔÏàͬµÄ˳Ðò±¨¸æÉ豸ʱ¡£´«µÝ¸øpci_find_slot()µÄÊÇ×ÜÏߺÅslotºÍÉ豸-¹¦ÄܺÅfunction£¨slot<<3 | function£©¡£

PCIÖÐ¶ÏºÍÆäËû×¢ÒâÊÂÏî

    PCI×ÜÏßÒ»¸öÖØÒªµÄ¸ÅÄîÊǹ²ÏíÖжϴ¦Àí£¬ÕâÔÚISA×ÜÏßÉ豸ÖÐÒ»°ãÊÇ¿´²»µ½µÄ¡£PCI×ÜÏßÖжÏÒ²ÊÇµçÆ½´¥·¢µÄ£¨level-triggered£©£¬Ò²¾ÍÊÇ˵£¬ÖжÏÒ»Ö±ÔÚÄÇÀֱµ½É豸ȥÇå³ýËü¡£ÕâÐ©ÌØÐÔ¸øÇý¶¯³ÌÐò´¦ÀíÖжϼÓÉÏÁËÒ»Ð©ÖØÒªµÄÏÞÖÆ¡£

    Çý¶¯³ÌÐò×¢²áPCIÖжÏʱ£¬×ÜÊÇÓ¦¸Ã´øÉÏSA_SHIRQ±êÖ¾£¬ÓÃÀ´Ö¸Ã÷ÖжÏÏßÊÇ¿ÉÒÔ¹²ÏíµÄ¡£Èç¹û²»ÕâÑù×ö£¬ÄÇôϵͳÖÐµÄÆäËûÉ豸ÓпÉÄܲ»ÄÜÕý³£¹¤×÷£¬Óû§Ò²¿ÉÄÜÓöµ½Âé·³¡£

    ÓÉÓÚÖжÏÊǹ²ÏíµÄ£¬PCIÉ豸Çý¶¯³ÌÐòºÍÄں˶¼ÐèÒªÓëÿ¸öÖжϴ¦ÀíÀý³Ì½øÐйµÍ¨µÄ·½·¨¡£Äã±ØÐëÓÃÒ»¸ö·Ç¿Õ£¨non-NULL£©µÄdev_idÀ´×¢²á¹²ÏíÖжϣ¬·ñÔò£¬µ±ÄãÐèÒªÓÃfree_irqÀ´ÊÍ·ÅÒ»¸öÖжÏʱ£¬Äں˲»ÄÜÇø·Ö²»Í¬µÄÖжϴ¦ÀíÀý³Ì¡£dev_id±»Ë͵½Öжϴ¦ÀíÀý³Ì£¬Òò´ËËü·Ç³£ÖØÒª¡£ÀýÈ磬Äã¿ÉÒÔÕâÑù£º

if (request_irq(dev->irq, dev_interrupt,
SA_SHIRQ, "wonderwidget",
dev))
return -EAGAIN;

½áÊøÊ±£¬ÓÃÏÂÃæµÄÓï¾äÀ´ÕýÈ·ÊÍ·ÅÖжϣº

free_irq(dev->irq, dev)

Öжϴ¦ÀíÀý³Ì±»µ÷ÓÃʱÊÕµ½dev²ÎÊý£¬ÕâʹÊÂÇéºÜ¼òµ¥ÁË¡£Äã²»±ØËÑѰʹÓøÃÖжϵÄÉ豸£¬Í¨³£¿ÉÒÔÕâÑù×ö£º

Listing Two: Using the dev_id
static void dev_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct wonderwidget *dev = dev_id;
u32 status;

/* It is important to exit interrupt handlers
* that are not for us as fast as possible */

if((status=inl(dev->port))==0) /* Not our interrupt */
return;

if(status&1)
handle_rx_intr(dev);
....
}

    Äã±ØÐë×ÜÊÇСÐÄ´¦ÀíÖжϡ£ÓÀÔ¶²»ÒªÔÚ°²×°Öжϴ¦ÀíÀý³Ì֮ǰ²úÉúÖжϡ£ÒòΪPCIÖжÏÊÇµçÆ½´¥·¢µÄ£¬Èç¹ûÄã²úÉúÁËÖж϶øÓÖ²»ÄÜ´¦ÀíËü£¬¿ÉÄܻᵼÖÂËÀ»ú¡£ÕâÒâζ×Åд³õʼ»¯´úÂëʱ±ØÐëÌØ±ðСÐÄ£¬Äã±ØÐëÔÚ´ò¿ªÉ豸µÄÖжÏ֮ǰע²áÖжϴ¦ÀíÀý³Ì¡£Í¬Ñù£¬¹Ø±Õʱ±ØÐëÔÚ×¢ÏúÖжϴ¦ÀíÀý³Ì֮ǰÆÁ±ÎÉ豸µÄÖжϡ£ÓëISA×ÜÏßÏà±È£¬Linux¶ÔPCI×ÜÏßµÄÖ§³ÖÓõ½½Ï¶àµÄº¯Êý£¬²¢ÇÒҪСÐÄ´¦ÀíÖжϡ£
    ×÷Ϊ»Ø±¨£¬²»ÐèÒªÄãµÄ½éÈ룬ϵͳ°ÑÒ»Çж¼ÅäÖúÃÁË¡£

[Ŀ¼]


loopback

¸÷λ´óÏÀ£¬×î½üÎÒ¿´LinuxÔ´ÂëÖеÄÍøÂçÇý¶¯²¿·Ö¡£
ÏÈ´Óloopback.cÈëÊֵġ£
loopback.cÖеÄloopback_xmitº¯ÊýÖÐÓÐÕâôһ¶Î£º
static int loopback_xmit(struct sk_buff * skb,struct net_device * dev)
{
        struct net_device_stats * stats = (struct net_device_stats *)dev_priv;

        if (atomic_read(&skb->users)!=1){

/*ÅжÏÓм¸¸öÈËÓÃskb. ÊÇ»áÓжà³öÓÃskb,ÀýÈçÒ»±ßÔËÐÐÒ»±ßsniff.ÓÐЩʱºò»áÐÞ¸Äskb, Õâ¾ÍÒªclone,Èç¹ûÕâ/¸öskbÒ²±»ÆäËûÈËÓÃÁË.. */

                struct sk_buff * skb2 = skb;
                skb=skb_clone(skb,GFP_ATOMIC);
                if(skb==NULL){
                        kfree_skb(skb2);
                        return 0;/*ÕâÀïϵͳÄÚ´æ²»×㣬Ϊʲô²»±¨´í£¿ÒòΪ¶ÔkernelÀ´Ëµ,mem ²»¹»²»ÊÇ´í,ÊÇ»á³öÏÖµÄʵ¼ÊÇé¿ö,. ÔÚÕâÀïµÄ´¦Àí·½Ê½¾ÍÊǰÑÕâ¸ö°üdropµ÷.²»loopbackÁË. */
                }
                kfree_skb(skb2);
        }
        else
                skb_orphan(skb);/*²é<linux/skbuff.h>Öж¨Ò壺
                                skb_orphan ---- orphan a buffer
                                @skb: buffer to orphan
                                If a buffer currently has an owner then we
                                call the owner's destructor function and
                                make the @skb unowned.The buffer continues
                                to exist but is no longer charged to its
                                former owner
                                ÄÇôskb_orphanÒÔºó£¬Ô­À´skbËùÖ¸ÏòµÄsk_buff
                                ½á¹¹ÈçºÎʹÓÃÄØ£¿skbÊÇ·ñ³ÉÁËÒ»¸ö¿ÕÖ¸Õ룿
                                skb_orphanºÍkfree_skbÓÐʲô±¾ÖʵÄÇø±ð£¿
                                ÆäʵÕâÀïÓ¦¸Ã²»ÊÇfreeµ÷µÄ.»¹ÊÇ¿ÉÒÔÓõÄ.µ«ÊÇÈ¡Ïû
                                Ô­À´µÄownerµÄÒýÓöøÒÑ. */
        .
        .
        .
}

[Ŀ¼]


Sis 900

SIS 900 ÊÇÒ»¸ö¿ÉÒÔÓÃÀ´Êµ×÷ 10/100 ÍøÂ翨µÄ¿ØÖÆÐ¾Æ¬¡£ËüÌṩÁË¶Ô PCI mastermode , MII, 802.3x Á÷Á¿¿ØÖƵȸ÷ÖÖ±ê×¼µÄÖ§Ô®¡£ÕâÆªÎÄÕ½«¸æËß´ó¼Ò£¬ÈçºÎдһ¸ö Linux µÄÍøÂçÇý¶¯³ÌÐò£¬Ëü½«±È´ó¼ÒÏëÏñÖмòµ¥ºÜ¶à¡£ÕâÆªÎÄÕ½«ÒÔ Linux 2.4 °æÎª¶ÔÏó£¬ 2.2 °æÌṩµÄ½çÃæÂÔÓв»Í¬£¬µ«²î±ð²¢²»Ì«´ó£¬¶ÁÍê±¾ÎĺóÔÙ¶Á 2.2 °æµÄ³ÌÐòÂëÓ¦¸Ã²»»áÓÐÌ«´óÀ§ÄѲÅÊÇ¡£ ±¾ÎÄËù²Î¿¼µÄÇý¶¯³ÌÐòÊÇÔÚ 2.4.3 °æÖÐ drivers/net/sis900.c Õâ¸öµµ°¸¡£Äã¿ÉÒÔÔÚ http://xxx.xxx.xxx.xxx/linux-2.4.3/drivers/net/sis900.c ÕÒµ½Ëü¡£Èç¹ûÄãÄÜÓÐÒ»·ÝÓ²¼þµÄ databook ÔÚÊֱߣ¬¶ÁÆðÇý¶¯³ÌÐòµÄÂë¿ÉÄÜ»á¸ü¼òµ¥¡£ SIS900µÄ databook ¿ÉÒÔÖ±½ÓÔÚhttp://www.sis.com.tw/ftp/Databook/900/sis900.exeÏÂÔØ¡£

PCI Çý¶¯³ÌÐò
¶ÔÒ»¸ö PCI Çý¶¯³ÌÐò¶øÑÔ£¬ Linux ÌṩÁ˺ÜÍêÕûµÄÖ§Ô®£¬´ó²¿·ÝµÄ PCI ×ÊѶ¶¼ÓÉÄÚ½¨µÄ³ÌÐò¶Á³ö¡£¶Ô¸ö±ðµÄÇý¶¯³ÌÐò¶øÑÔÖ±½ÓʹÓþͿÉÒÔÁË¡£ËùÒÔÔÚÕâ¸ö²¿·Ý£¬Î¨Ò»Òª×öµÄÊÂÖ»ÊǸæÖª PCI ×Óϵͳһ¸öеÄÇý¶¯³ÌÐò¼º¾­±»¼ÓÈëϵͳ֮ÖÐÁË¡£ÔÚµµ°¸µÄ×îÄ©¶Ë£¬Äã»á¿´µ½ÏÂÃæµÄ³ÌÐò£¬

static struct pci_driver sis900_pci_driver = {
        name:           SIS900_MODULE_NAME,
        id_table:       sis900_pci_tbl,
        probe:          sis900_probe,
        remove:         sis900_remove,
};
static int __init sis900_init_module(void)
{
        printk(KERN_INFO "%s", version);
        return pci_module_init(&sis900_pci_driver);
}
static void __exit sis900_cleanup_module(void)
{
        pci_unregister_driver(&sis900_pci_driver);
}

pci_module_init ÊÇÓÃÀ´Ïò PCI ×Óϵͳע²áÒ»¸ö PCI Çý¶¯³ÌÐò¡£¸ù¾Ý id_table ÖÐËùÌṩµÄ×ÊÁÏ£¬ PCI ×Óϵͳ»áÔÚ·¢ÏÖ·ûºÏÇý¶¯³ÌÐòÒªÇóµÄ×°ÖÃʱʹÓÃËü¡£ÄÇ PCI ×ÓϵͳÈçºÎ×öµ½Õâ¼þÊÂÄØ ? ÎÒÃÇÏÈ¿´Ò»Ï id_table µÄÄÚÈݾͺÜÇå³þÁË¡£

static struct pci_device_id sis900_pci_tbl [] __devinitdata = {
        {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_900,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_900},
        {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_7016},
        {0,}
};
MODULE_DEVICE_TABLE (pci, sis900_pci_tbl);

¿´¶®ÁËÂð ? àÅ£¬ÎÒÏëÄã¶®ÁË¡£²»¹ýÎÒ»¹ÊǽâÊÍһϡ£Ç°ÃæËĸö·Ö±ðÊÇ

vendor id : PCI_VENDOR_ID_SI
device id : PCI_DEVICE_ID_SI_900
sub vendor id : PCI_ANY_ID
sub device id : PCI_ANY_ID

Òâ˼ÊÇ˵Õâ¸öÇý¶¯³ÌÐòÖ§Ô® SIS ³öµÄ SIS900 ϵÁÐËùÓеÄÓ²¼þ£¬ÎÒÃDz»½éÒâ subvendor id ºÍ sub device id ¡£Äã¿ÉÒÔ¼ÓÈëÈκÎÄãÏëÒªµÄÏîÄ¿¡£¶ÔÓÚ²»Í¬µÄÍøÂç¿¨ÖÆÔìÉÌ£¬ËüÃÇ¿ÉÄÜ»áÓв»Í¬µÄ sub vendor id ºÍ sub device id ¡£µ«Ö»ÒªËüÃÇÓÃSIS900 Õâ¸öоƬ£¬ÄÇÕâ¸öÇý¶¯³ÌÐò¾Í¿ÉÄÜÊÊÓá£ÎÒÃÇ¿ÉÒÔ˵ÕâÊÇÒ»¸ö¡º¹«°æ¡»µÄÇý¶¯³ÌÐò¡£³õʼ»¯ºÃÁË£¬ÄÇÆäËüµÄ²¿·ÝÄØ ? »¹¼ÇÒâ sis900_pci_driver ÖÐÆäËüµÄ¶þ¸öÏîÄ¿ probe ºÍremove Âð ? ËüÃÇÊÇÓÃÀ´³õʼ»¯ºÍÒÆ³ýÒ»¸öÇý¶¯³ÌÐòµÄºô½Ð¡£Äã¿ÉÒÔ°ÑËüÃÇÏë³ÉÇý¶¯³ÌÐòÎï¼þµÄ constructor ºÍ destructor ¡£ÔÚ probe ÖУ¬ÄãÓ¦¸ÃÓÉÓ²¼þÖаÑһЩ½«À´¿ÉÄÜ»áÓõ½µÄ×ÊѶ׼±¸ºÃ¡£ÓÉÓÚÕâÊÇÒ»¸ö PCI Çý¶¯³ÌÐò£¬Äã²»±ØÌØÒâÈ¥¼ì²é×°ÖÃÊÇ·ñÕæµÄ´æÔÚ¡£µ«Èç¹ûÄãµÄÇý¶¯³ÌÐòÖ»Ö§Ô®Ä³Ð©ÌØ¶¨µÄÓ²¼þ£¬»òÊÇÄãÏëÒª¼ì²éϵͳÖÐÊÇ·ñÓÐÒ»Ð©ÌØ±ðµÄÓ²¼þ´æÔÚ£¬Äã¿ÉÒÔÔÚÕâÀï×ö¡£ÀýÈçÔÚÕâ¸öÇý¶¯³ÌÐòÖУ¬¶Ô²»Í¬°æ±¾µÄÓ²¼þ£¬ÎÒÃÇÓò»
ͬµÄ·½·¨È¥¶ÁËüµÄ MAC λַ¡£
         pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
        if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV)
                ret = sis630e_get_mac_addr(pci_dev, net_dev);
        else if (revision == SIS630S_900_REV)
                ret = sis630e_get_mac_addr(pci_dev, net_dev);
        else
                ret = sis900_get_mac_addr(pci_dev, net_dev);
¶ÔÓÚ SIS630E SIS630EA1 ºÍ SIS630S ÕâЩÕûºÏʽоƬ¶øÑÔ£¬Æä MAC λַ±»´¢´æÔÚ APC CMOS RAM Ö®ÖС£µ«¶ÔÆäËü¶ÀÁ¢µÄоƬ¶øÑÔÔòÊÇ´æÔÚÍøÂ翨µÄ EEPROM Ö®ÉÏ¡£ÎªÁ˲»ÒªÈÃÕâÆªÎÄÕÂÏñÁ÷Ë®ÕÊÒ»°ã£¬ÎÒ²»×ÐϸµÄ˵Ã÷ probe µÄ¹ý³Ì¡£´ó¼Ò×Ô¼º´§ÃþÒ»Ï塃 !

ÔÚ probe Öл¹ÓÐÒ»¶Î±È½ÏºÍºóÎÄÓйصijÌÐòÂë
         net_dev->open = &sis900_open;
        net_dev->hard_start_xmit = &sis900_start_xmit;
        net_dev->stop = &sis900_close;
        net_dev->get_stats = &sis900_get_stats;
        net_dev->set_config = &sis900_set_config;
        net_dev->set_multicast_list = &set_rx_mode;
        net_dev->do_ioctl = &mii_ioctl;
        net_dev->tx_timeout = sis900_tx_timeout;
        net_dev->watchdog_timeo = TX_TIMEOUT;
ÎÒÏëÕâºÜÇå³þ£¬ÎÒÃÇ͸¹ý net_dev Õâ¸ö½á¹¹¸æËß Linux ÍøÂç×ÓϵͳÈçºÎÀ´²Ù×÷Õâ¸ö×°Öᣵ±ÄãʹÓà ifconfig Õâ¸ö R Áîʱ£¬ÏµÍ³»áʹÓà sis900_open ´ò¿ªÕâ¸öÇý¶¯³ÌÐò£¬²¢Ê¹Óà set_config À´Ëµ¶¨×°ÖõIJÎÊý£¬Èç IP address ¡£µ±ÓÐ×ÊÁÏÐèÒª±»´«ËÍʱ£¬ sis900_start_xmit ±»ÓÃÀ´½«×ÊÁÏËÍÈë×°ÖÃÖ®ÖС£½ÓÏÂÀ´£¬ÎÒÃǾÍÒ»Ò»µÄ¼ìÊÓÕâЩº¯Êý¡£

³õʼ»¯×°ÖÃ
sis900_open(struct net_device *net_dev);

Õâ¸öº¯Êý»áÔÚÎÒÃÇʹÓà ifconfig ½«Ò»ÍøÂç×°Öü¤»îʱ±»ºô½Ð¡£µ±Çý¶¯³ÌÐò±»²åÈëϵͳ֮ºó£¬Í¨³£²¢²»»áÂíÉÏ¿ªÊ¼½ÓÊÕ»ò´«ËÍ·â°ü¡£Ò»°ãÀ´Ëµ£¬ÔÚ probe µÄ½×¶Î£¬ÎÒÃÇÖ»Êǵ¥´¿µÄÅжÏ×°ÖÃÊÇ·ñ´æÔÚ¡£Êµ¼Ê¼¤»îÓ²¼þµÄ¶¯×÷ÔÚÕâÀï²Å»á±»Êµ¼ÊÖ´ÐС£ÒÔ SIS900 ΪÀý£¬ÔÚÆäÓ²¼þÖÐÖ»ÓÐÒ»¸ö´óÔ¼ 2K µÄ»º³åÇø¡£Ò²¾ÍÊÇ˵ÔÚ×°ÖÃÉÏÖ»ÓÐÒ»¸ö
·â°üµÄ»º³åÇø¡£µ±Ò»¸ö·â°ü±»´«Ëͺó£¬×°ÖñØÐë²úÉúÒ»¸öÖжÏÒªÇó²Ù×÷ϵͳ½«ÏÂÒ»¸ö·â°ü´«Èë¡£Èç¹ûÓÉÖжϵ½ÖжÏÇý¶¯³ÌÐò±»Ö´ÐÐÐèÒª 5ms µÄʱ¼ä£¬ÄÇÒ»ÃëÖÁ¶àÎÒÃÇ¿ÉÒÔËͳö 200 ¸ö·â°ü¡£Ò²¾ÍÊÇËµÍøÂç´«ËÍÊDz»¿ÉÄÜ´óÓÚ 400K/s £¬Õâ¶ÔÓÚÒ»°ãµÄÇé¿öÏÂÊDz»Ì«¿ÉÄܽÓÊܵÄÊ¡£SIS900 ËäÈ»ÔÚ×°ÖÃÉÏÖ»ÓкÜСµÄ»º³åÇø£¬µ«Ëü¿ÉÒÔ͸¹ý PCI master ģʽֱ½Ó¿ØÖÆÖ÷»ú°åÉϵļÇÒäÌå¡£ÊÂʵÉÏ£¬ËüʹÓÃÏÂÃæµÄ·½Ê½À´´«ËÍ×ÊÁÏ¡£Äã±ØÐëÔÚ¼ÇÒäÌåÖзÖÅäÒ»×é´®½Ó³É»·×´´®ÁеĻº³åÇø£¬È»ºó½« TXDP Ö¸Ïò»º³åÇøµÄµÚÒ»¸öλַ¡£ SIS900 »áÔÚµÚÒ»¸ö»º³åÇø´«ËÍÍêºó×Ô¶¯µÄÓɵڶþ¸ö»º³åÇøÈ¡×ÊÁÏ£¬²¢¸üмÇÒäÖеÄ×ÊÁϽ«¼º´«ËÍÍ껺³åÇøµÄ OWN λԪÇå³ý¡£µ± CPU ½«»º³åÇø´®ÁÐÉ趨Íê³Éºó£¬Õâ¸ö¶¯×÷¿ÉÒÔÔÚÍêȫûÓÐ CPU µÄ½éÈëÏÂÍê³É¡£ËùÒÔÓ²¼þ²»±ØµÈ´ý×÷ҵϵͳ½«ÐµÄ×ÊÁÏËÍÈ룬¶ø¿ÉÒÔÁ¬ÐøµÄËͳö¶à¸ö·â°ü¡£²Ù×÷ϵͳֻҪÄÜÀ´µÄ¼°Èû·×´´®Áв»»á½øÈë¿ÕµÄ״̬¾Í¿ÉÒÔÁË¡£

ͬÑùµÄ£¬ÎÒÃÇÒ²ÐèÒªÒ»¸ö½ÓÊÕ»º³åÇø£¬Ê¹ÓýøÀ´µÄ·â°ü²»ÖÁÒò²Ù×÷ϵͳÀ´²»¼°´¦Àí¶øÒÅʧ¡£ÔÚ sis900_open ÖУ¬ sis900_init_rx_ring ºÍ sis900_init_tx_ring ¾ÍÊÇÓÃÀ´¸º´¦³õʼ»¯Õâ¶þ¸ö´®ÁС£
ÔÚ³õʼ»¯´®ÁÐÖ®ºó£¬ÎÒÃDZã¿ÉÒÔÒªÇó SIS900 ¿ªÊ¼½ÓÊÕ·â°ü¡£ÏÂÃæ¶þÐгÌÐòÂë±ãÊÇÓÃÀ´×öÕâ¼þÊ¡£

  outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
  outl(RxENA, ioaddr + cr);
  outl(IE, ioaddr + ier);

µÚÒ»ÐÐÉ趨Ӳ¼þÔÚÏÂÁÐÇé¿ö·¢³öÒ»¸öϵͳÖжϣ¬
½ÓÊÕʧ°Üʱ
½ÓÊճɹ¦ ʱ
´«ËÍʧ°Üʱ
ËùÓлº³åÇøÖеÄ×ÊÁ϶¼´«ËÍÍêʱ
µÚ¶þÐÐÔò¸æËßÓ²¼þ²Ù×÷ϵͳ¼º¾­×¼±¸ºÃÒª½ÓÊÕ×ÊÁÏÁË¡£µÚÈýÐÐÔòʱӲ¼þʵ¼Ê¿ªÊ¼ËͳöÖжϡ£
ÔÚÕâ¸öº¯ÊýµÄ×îºó£¬ÎÒÃǰ²×°Ò»¸öÿÃëÖ´ÐÐÎå´ÎµÄ timer ¡£ÔÚËüµÄ´¦Àíº¯Êý sis900_timer ÖУ¬ÎÒÃÇ»á¼ì²éĿǰµÄÁ¬½á״̬£¬Õâ°üÀ¨ÁËÁ¬½áµÄÖÖÀà (10/100)ºÍÁ¬½ÓµÄ״̬ ( ÍøÂ翨ÊÇ·ñÖ±µÄ±»½Óµ½ÍøÂçÉÏÈ¥ ) ¡£
Èç¹û¸÷λÓùý Window 2000 £¬ÁíÈËÓ¡Ïó×îÉî¿ÌµÄÊǵ±Äã½«ÍøÂçÏ߰γöʱ£¬ GUI »á×Ô¶¯¾¯ÑÔÍøÂ缺¾­Öжϡ£Æäʵ Linux Ò²¿ÉÒÔ×öµ½Õâ¼þÊ£¬Ö»ÊÇÄãÐèÒªÒ»¸ö±È½ÏºÃµÄͼÐνçÃæ¾ÍÊÇÁË¡£
´«ËÍÒ»¸ö·â°üµÄ descriptor ¸øÍøÂ翨

sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev);

Õâ¸öº¯ÊýÊÇÓÃÀ´½«Ò»¸öÓÉ skb ÃèÊöµÄÍøÂç×ÊÁÏ»º³åÇøËͽø´«ËÍ»º³åÇøÖÐ×¼±¸´«ËÍ¡£ÆäÖÐ×îÖØÒªµÄ³ÌÐòÂëΪ

    sis_priv->tx_ring[entry].bufptr = virt_to_bus(skb->data);
    sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
    outl(TxENA, ioaddr + cr);

SIS900 »áʹÓà DMA ÓÉ»º³åÇøÖÐÈ¡µÃ·â°üµÄ×ÊÁÏ¡£ÓÉÓÚ»º³åÇøµÄÊýÄ¿ÓÐÏÞ£¬ÎÒÃDZØÐëÔÚ»º³åÇøÓÃÍêµÄʱºó¸æËßÉϲãµÄÍøÂçЭ¶¨²»ÒªÔÙÍùÏÂËÍ×ÊÁÏÁË¡£ÔÚÕâÀïÎÒÃÇÓÃÏÂÃæµÄ³ÌÐòÀ´×öÕâ¼þÊ¡£

     if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {
        netif_start_queue(net_dev);
    } else {
        sis_priv->tx_full = 1;
        netif_stop_queue(net_dev);
    }

netif_start_queue ÓÃÀ´¸æËßÉϲãÍøÂçЭ¶¨Õâ¸öÇý¶¯³ÌÐò»¹ÓпյĻº³åÇø¿ÉÓã¬Çë°ÑÏÂÒ»¸ö·â°üËͽøÀ´¡£ netif_stop_queue ÔòÊÇÓÃÀ´¸æËßÉϲãÍøÂçЭ¶¨ËùÓеķâ°ü¶¼ÓÃÍêÁË£¬Çë²»ÒªÔÙËÍ¡£

½ÓÊÕÒ»¸ö»ò¶à¸ö·â°ü
int sis900_rx(struct net_device *net_dev);

Õâ¸öº¯Ê½ÔÚ»áÔÚÓзâ°ü½øÈëϵͳʱ±»ºô½Ð£¬ÒòΪ¿ÉÄÜÓжàÓÚÒ»¸öµÄ·â°üÔÚ»º³åÇøÖ®ÖС£Õâ¸öº¯Êý»áÖðÒ»¼ì²éËùÓеĻº³åÇø£¬Ö±µ½Óöµ½Ò»¸ö¿ÕµÄ»º³åÇøÎªÖ¹¡£µ±ÎÒÃÇ·¢ÏÖÒ»¸öÓÐ×ÊÁϵĻº³åÇøÊ±£¬ÎÒÃÇÐèÒª×ö¶þ¼þÊ¡£Ê×ÏÈÊǸæÖªÉϲãÍøÂçЭ¶¨ÓÐÒ»¸öеķâ°ü½øÈëϵͳ£¬Õâ¼þÊÂÓÉÏÂÃæµÄ³ÌÐòÍê³É

               skb = sis_priv->rx_skbuff[entry];
               skb_put(skb, rx_size);
               skb->protocol = eth_type_trans(skb, net_dev);
               netif_rx(skb);
ǰÈýÐиù¾Ý·â°üµÄÄÚÈݸüРskbuff ÖеĵµÍ·¡£×îºóÒ»ÐÐÔòÊÇÕýʽ֪ͨÉϲ㴦Àí·â°ü¡£

Çë×¢Òâ Linux ΪÁËÔö¼Ó´¦ÀíЧÄÜ£¬ÔÚ netif_rx ²¢²»»áÕæµÄ×öÍêÕû½ÓÊÕ·â°üµÄ¶¯×÷£¬¶øÖ»Êǽ«Õâ¸ö·â°ü¼ÇÏÂÀ´¡£ÕæÊµµÄ¶¯×÷ÊÇÔÚ bottom half ÖвÅÈ¥´¦Àí¡£ÒòΪÈç´Ë£¬Ô­ÏÈ´¢´æ·â°üµÄ»º³åÇøÔÝʱ²»ÄÜÔÙ±»Ê¹Óã¬ÎÒÃDZØÐëÖØÐ·ÖÅäÒ»¸öÐµĻº³åÇø¹©ÏÂÒ»¸ö·â°üʹÓá£ÏÂÃæµÄ³ÌÐòÂëÊÇÓÃÀ´È¡µÃÒ»¸öÐµĻº³åÇø¡£

      if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
          sis_priv->rx_skbuff[entry] = NULL;
          sis_priv->rx_ring[entry].cmdsts = 0;
          sis_priv->rx_ring[entry].bufptr = 0;
          sis_priv->stats.rx_dropped++;
          break;
     }
     skb->dev = net_dev;
     sis_priv->rx_skbuff[entry] = skb;
     sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
     sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail);
     sis_priv->dirty_rx++;

Õâ¸öº¯ÊýÆäâŵIJ¿·ÝÆäʵֻÊÇÓÃÀ´¼Ç¼һЩͳ¼Æ×ÊÁ϶ø¼º¡£
´«ËÍÏÂÒ»¸ö·â°ü

void sis900_finish_xmit (struct net_device *net_dev);

Õâ¸öº¯ÊýÓÃÀ´´¦Àí´«ËÍÖжϡ£ÔÚÊÕµ½Ò»¸ö TX Öжϣ¬±íʾÓÐÒ»¸ö»ò¶àÊý»º³åÇøÖеÄ×ÊÁϼº¾­´«ËÍÍê³É¡£ÎÒÃÇ¿ÉÒÔ°ÑÔ­ÏȵĻº³åÇøÊͳöÀ´¹©ÆäËüµÄ·â°üʹÓ㬲¢ÇÒÓÃÏÂÃæµÄ³ÌÐò¸æËßÉϲãЭ¶¨¿ÉÒÔËÍеķâ°üÏÂÀ´ÁË¡£

     if (sis_priv->tx_full && netif_queue_stopped(net_dev) &&
        sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
        sis_priv->tx_full = 0;
        netif_wake_queue (net_dev);
    }

netif_wake_queue() »áʹµÃÉϲãЭ¶¨¿ªÊ¼´«ËÍеÄ×ÊÁÏÏÂÀ´¡£

¸Ä±ä×°ÖõÄÉ趨

int sis900_set_config(struct net_device *dev, struct ifmap *map);

´¦ÀíÓÉ ifconfig ËÍÀ´µÄÃüÁÔÚÇý¶¯³ÌÐòÖÐÎÒÃÇͨ³£Ö»´¦Àí media typeµÄ¸Ä±ä¡£Õâ¸öº¯Êý»á¸ù¾Ý ifconfig ËÍÀ´µÄÖµ¸Ä±ä MII ¿ØÖÆÆ÷µÄ media tyep £¬Äã¿ÉÒÔʹÓÃ

     # ifconfig eth0 media 10basT

½«Ä¿Ç°µÄÊä³öÈë½çÃæÇ¿ÆÈ¸Äµ½ 10basT ¡£¶ÔÓÚijЩ×Ô¶¯Ã½Ìå¼ì²â×öµÄÓÐÎÊÌâµÄswitch ¶øÑÔÕâ¿ÉÄÜÊDZØÒªµÄÉ趨£¬µ«Ò»°ã¶øÑÔĬÈ쵀 auto ÊÇ×îºÃµÄÉ趨¡£Ó²¼þ»á×Ô¶¯¾ö¶¨ÒªÊ¹ÓÃÄÇÒ»¸ö½çÃæ£¬Ê¹ÓÃÕßÍêÈ«²»±Øµ£ÐÄ£¬µ±ÊµÌå²ãµÄÉ趨¸Ä±ä ( ÀýÈç½«ÍøÂçÏ߲嵽²»Í¬µÄµØ·½ ) £¬Ó²¼þ»á×Ô¶¯Õì²â²¢¸Ä±äÉ趨¡£

void set_rx_mode(struct net_device *net_dev);

¸Ä±äĿǰ·â°ü¹ýÂËÆ÷µÄģʽ¡£µ±ÄãʹÓÃ

      # ifconfig eth0 promisc
      # ifconfig eth0 multicast

µÈÃüÁîʱ»á±»ºô½Ð¡£Ò»°ã¶øÑÔ£¬Çý¶¯³ÌÐòµÄĬÈÏÖµÊÇÖ»½ÓÊÜÄ¿µÄλַºÍÍøÂ翨µÄ MAC address ÏàͬµÄ·â°ü¡£Äã¿ÉÒÔ͸¹ý ifconfig ÃüÁî¿ØÖÆÇý¶¯³ÌÐò½ÓÊÜÆäËüÖÖÀàµÄ·â°ü¡£½áÓïºÃÁË ! ÎÒ¼º¾­½âÎöÍêÕû¸öÍøÂ翨µÄÇý¶¯³ÌÐòÁË¡£µ±ÄãÁ˽âÕâ¸öÇý¶¯³ÌÐòºó£¬ÔÙÈ¥Á˽âÆäËüµÄÇý¶¯³ÌÐò±ä³ÉÒ»¼þºÜ¼òµ¥µÄÊÂÇé¡£´ó²¿·ÝÍøÂçÇý¶¯³ÌÐòµÄ¼Ü¹¹Æäʵ¶¼ºÜÀàËÆ¡£ÊÂʵÉÏ£¬ Linux ÔçÆÚµÄÍøÂ翨Çý¶¯³ÌÐò¼¸ºõÊÇÓÉͬһ¸öÈËÍê³ÉµÄ¡£¶øºóÀ´µÄÇý¶¯³ÌÐòÒ²¼¸ºõ
¶¼ÒÔÕâЩÇý¶¯³ÌÐòΪÀ¶±¾£¬ËùÒÔ¿´ÆðÀ´¶¼ºÜÀàËÆ¡£ÄãÒª²»ÒªÒ²ÊÔÖøÔÙÈ¥¶ÁÁíÒ»¸öÍøÂçÇý¶¯³ÌÐòµÄÔ´´úÂëÄØ ? Ò²Ðí Äã»á¿ªÊ¼±§Ô¹ÔõôдÇý¶¯³ÌÐòÕâôÉñÃØµÄ¶«Î÷Ôõô±äµÃÈç´Ë¼òµ¥ÁË !

¶àâŵÄÒ»½Ú
ÕâÒ»½Ú¶àâŵģ¬Äã²»Ïë¿´¾ÍËãÁË :-) ΪÁËÖ¤Ã÷ÍøÂçÇý¶¯³ÌÐòÖ®¼äÓжàÀàËÆÎÒÔÙ¼òÂÔµÄtrace Intel eepro100 µÄÇý³Ì³ÌÐò¸ø´ó¼Ò¿´¡£²»ÂÞËô£¬ÂíÉÏ¿ªÊ¼¡£

³õʼ»¯
static struct pci_device_id eepro100_pci_tbl[] __devinitdata = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_4,
                PCI_ANY_ID, PCI_ANY_ID, },
        { 0,}
};
MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
tatic struct pci_driver eepro100_driver = {
        name:           "eepro100",
        id_table:       eepro100_pci_tbl,
        probe:          eepro100_init_one,
        remove:         eepro100_remove_one,
#ifdef CONFIG_EEPRO100_PM
        suspend:        eepro100_suspend,
        resume:         eepro100_resume,
#endif
};
return pci_module_init(&eepro100_driver);

àÅ ! Ò»Çж¼²»³öÒâÀàÖ®Í⣬ÊÇ°É !
³õʼ»¯×°ÖÃ

eepro100_init_one()

Õâ¸ö¿´ÆðÀ´±È SIS900 µÄ¸´ÔÓ¶àÁË¡£²»¹ý¼¸¸ö¹Ø¼øµÄº¯Êý»¹ÊÇÒ»Ñù£¬Ö»ÊÇËüµÄ³ÌÐòÂë¿´Æð±È½ÏÂÒ¡£ BSD µÄÈËϲ»¶Ëµ Linux µÄ³ÌÐòÂëÌ«ÂÒ ! àÅ£¬ºÃÏñ²»³ÐÈϲ»ÐÐ :-) ²»¹ýÎÒ˵ËüÂҵĺܿɰ®£¬ÐÐÁ衃 !

´«ËÍ·â°ü
speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)

Õâ¸öº¯ÊýÏàËÆµ½ÎÒ²»±Ø×öÈκν²½â£¬Ò²²»±ØÓÐÈκÎÎļþÄã¾Í¿ÉÒÔÖªµÀËüÔÚ×öЩʲôÊÂÁË ! ³ÌÐòÂ뼸ºõµ½ÁËÒ»ÐжÔÒ»ÐÐµÄ³Ì¶È ( ¿äÕÅÁËÒ»µã ! ²»¹ýºÜ½Ó½üÊÂʵ¡£ÎÒÐÅÏà SIS900 µÄ driver ÊǺÜÕû¸ö³ÌÐò copy ¹ýÈ¥ÔÙÐÞ¸ÄµÄ )

Öжϴ¦Àí

void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);

Õâ¸öº¯Êý£¬ÎÒÔÙϲ»¶ Linux Ò²²»µÃ²»±§Ô¹Ò»ÏÂÁË¡£ Donald Becker ÏÈÉú£¬ÄÜÂé·³³ÌÐòдµÄºÃ¿´Ò»µãºÃÂð ?
»ù±¾ÉÏ£¬Ëü°Ñ sis900_rx µÄÄÚÈÝÖ±½Ó·ÅÔÚÖжϴ¦Àíº¯ÊýÖ®ÖС£²»¹ýÎÒÏë·Ö¿ª»¹ÊÇ»áÇå³þһЩ¡£

speedo_tx_buffer_gc »ù±¾ÉϾÍÊÇ sis900_finish_xmit ¡£ÏÂÃæµÄ³ÌÐòÊDz»ÊǺÜÑÛÊìÄØ ?

     dirty_tx = sp->dirty_tx;
     while ((int)(sp->cur_tx - dirty_tx) > 0) {
        int entry = dirty_tx % TX_RING_SIZE;
        int status = le32_to_cpu(sp->tx_ring[entry].status);
        }

Á¬±äÊýÃû×Ö¶¼ºÜÏñÄØ !

²»¹ý eepro100 µÄÇý¶¯³ÌÐòûÓÐʵ×÷ set_config µÄ½çÃæ£¬ËùÒÔÄã²»ÄÜÓÃifconfig À´¸Ä±ä media type ¡£²»¹ý eepro100 ÌṩÁËÓÉÄ£¿éÃüÁîÁÐÑ¡Ïî¸Ä±äµÄ¹¦ ÄÜ£¬µ±È»ËüÊDz»¼° set_config À´µÄ·½±ã¾ÍÊÇÁË¡£
»¹ÒªÔÙÀ´Ò»¸öÂð ? Äã×Ô¼ºÈ¥×ö°É !


[Ŀ¼]


ISA×ÜÏßDMAµÄʵÏÖ

Linux¶ÔISA×ÜÏßDMAµÄʵÏÖ

¡¡¡¡£¨By Õ²ÈÙ¿ª£¬NUDT dep3£©

¡¡¡¡Copyright ? 2002 by Õ²ÈÙ¿ª
¡¡¡¡E-mail:zhanrk@sohu.com
¡¡¡¡Linux-2.4.0 Version 1.0.0£¬2002-10-16

¡¡¡¡¹Ø¼ü´Ê£ºLinux¡¢I/O¡¢ISA×ÜÏß¡¢É豸Çý¶¯³ÌÐò

¡¡¡¡ÉêÃ÷£ºÕâ·ÝÎĵµÊǰ´ÕÕ×ÔÓÉÈí¼þ¿ª·ÅÔ´´úÂëµÄ¾«Éñ·¢²¼µÄ£¬ÈκÎÈË¿ÉÒÔÃâ·Ñ»ñµÃ¡¢Ê¹ÓúÍÖØÐ·¢²¼£¬µ«ÊÇÄãûÓÐÏÞÖÆ±ðÈËÖØÐ·¢²¼Äã·¢²¼ÄÚÈݵÄȨÀû¡£·¢²¼±¾ÎĵÄÄ¿µÄÊÇÏ£ÍûËüÄܶԶÁÕßÓÐÓ㬵«Ã»ÓÐÈκε£±££¬ÉõÖÁûÓÐÊʺÏÌØ¶¨Ä¿µÄµÄÒþº¬µÄµ£±£¡£¸üÏêϸµÄÇé¿öÇë²ÎÔÄGNUͨÓù«¹²Ðí¿ÉÖ¤(GPL)£¬ÒÔ¼°GNU×ÔÓÉÎĵµÐ­Òé(GFDL)¡£

¡¡¡¡ÄãÓ¦¸ÃÒѾ­ºÍÎĵµÒ»ÆðÊÕµ½Ò»·ÝGNUͨÓù«¹²Ðí¿ÉÖ¤(GPL)µÄ¸±±¾¡£Èç¹û»¹Ã»ÓУ¬Ð´ÐŸø£ºThe Free Software Foundation, Inc., 675 Mass Ave, Cambridge,MA02139, USA

¡¡¡¡»¶Ó­¸÷λָ³öÎĵµÖеĴíÎóÓëÒÉÎÊ¡£

----------------------------------------------------

¡¡¡¡DMAÊÇÒ»ÖÖÎÞÐèCPUµÄ²ÎÓë¾Í¿ÉÒÔÈÃÍâÉèÓëϵͳRAMÖ®¼ä½øÐÐË«Ïò£¨to device »ò from device£©Êý¾Ý´«ÊäµÄÓ²¼þ»úÖÆ¡£Ê¹ÓÃDMA¿ÉÒÔʹϵͳCPU´Óʵ¼ÊµÄI/OÊý¾Ý´«Êä¹ý³ÌÖаÚÍѳöÀ´£¬´Ó¶ø´ó´óÌá¸ßϵͳµÄÍÌÍÂÂÊ£¨throughput£©¡£

¡¡¡¡ÓÉÓÚDMAÊÇÒ»ÖÖÓ²¼þ»úÖÆ£¬Òò´ËËüͨ³£ÓëÓ²¼þÌåϵ½á¹¹ÊÇÏà¹ØµÄ£¬ÓÈÆäÊÇÒÀÀµÓÚÍâÉèµÄ×ÜÏß¼¼Êõ¡£±ÈÈ磺ISA¿¨µÄDMA»úÖÆ¾ÍÓëPCI¿¨µÄDMA»úÖÆÓÐÇø±ð¡£±¾Õ¾Ö÷ÒªÌÖÂÛISA×ÜÏßµÄDMA¼¼Êõ¡£

1.DMA¸ÅÊö

¡¡¡¡DMAÊÇÍâÉèÓëÖ÷´æÖ®¼äµÄÒ»ÖÖÊý¾Ý´«Êä»úÖÆ¡£Ò»°ãÀ´Ëµ£¬ÍâÉèÓëÖ÷´æÖ®¼ä´æÔÚÁ½ÖÖÊý¾Ý´«Êä·½·¨£º£¨1£©Pragrammed I/O£¨PIO£©·½·¨£¬Ò²¼´ÓÉCPUͨ¹ýÄÚ´æ¶ÁдָÁî»òI/OÖ¸ÁîÀ´³ÖÐøµØ¶ÁдÍâÉèµÄÄÚ´æµ¥Ôª£¨8λ¡¢16λ»ò32룩£¬Ö±µ½Õû¸öÊý¾Ý´«Êä¹ý³ÌÍê³É¡££¨2£©DMA£¬¼´ÓÉDMA¿ØÖÆÆ÷£¨DMA Controller£¬¼ò³ÆDMAC£©À´Íê³ÉÕû¸öÊý¾Ý´«Êä¹ý³Ì¡£ÔÚ´ËÆÚ¼ä£¬CPU¿ÉÒÔ²¢·¢µØÖ´ÐÐÆäËûÈÎÎñ£¬µ±DMA½áÊøºó£¬DMACͨ¹ýÖжÏ֪ͨCPUÊý¾Ý´«ÊäÒѾ­½áÊø£¬È»ºóÓÉCPUÖ´ÐÐÏàÓ¦µÄISR½øÐкó´¦Àí¡£

¡¡¡¡DMA¼¼Êõ²úÉúʱÕýÊÇISA×ÜÏßÔÚPCÖÐÁ÷ÐеÄʱºî¡£Òò´Ë£¬ISA¿¨µÄDMAÊý¾Ý´«ÊäÊÇͨ¹ýISA×ÜÏß¿ØÖÆÐ¾Æ¬×éÖеÄÁ½¸ö¼¶Áª8237 DMACÀ´ÊµÏֵġ£ÕâÖÖDMA»úÖÆÒ²³ÆÎª¡°±ê×¼DMA¡±£¨standard DMA£©¡£±ê×¼DMAÓÐʱҲ³ÆÎª¡°µÚÈý·½DMA¡±£¨third-party DMA£©£¬ÕâÊÇÒòΪ£ºÏµÍ³DMACÍê³Éʵ¼ÊµÄ´«Êä¹ý³Ì£¬ËùÒÔËüÏà¶ÔÓÚ´«Êä¹ý³ÌµÄ¡°Ç°Á½·½¡±£¨´«ÊäµÄ·¢ËÍÕߺͽÓÊÕÕߣ©À´ËµÊÇ¡°µÚÈý·½¡±¡£

¡¡¡¡±ê×¼DMA¼¼ÊõÖ÷ÒªÓÐÁ½¸öȱµã£º£¨1£©8237 DMACµÄÊý¾Ý´«ÊäËÙ¶ÈÌ«Âý£¬²»ÄÜÓë¸ü¸ßËÙµÄ×ÜÏߣ¨ÈçPCI£©ÅäºÏʹÓᣣ¨2£©Á½¸ö8237 DMACÒ»ÆðÖ»ÌṩÁË8¸öDMAͨµÀ£¬ÕâÒ²³ÉΪÁËÏÞÖÆÏµÍ³I/OÍÌÍÂÂÊÌáÉýµÄÆ¿¾±¡£

¡¡¡¡¼øÓÚÉÏÊöÁ½¸öÔ­Òò£¬PCI×ÜÏßÌåϵ½á¹¹Éè¼ÆÒ»ÖÖ³ÉΪ¡°µÚÒ»·½DMA¡±£¨first-party DMA£©µÄDMA»úÖÆ£¬Ò²³ÆÎª¡°Bus Mastering¡±£¨×ÜÏßÖ÷¿Ø£©¡£ÔÚÕâÖÖÇé¿öÏ£¬½øÐд«ÊäµÄPCI¿¨±ØÐëÈ¡µÃϵͳ×ÜÏßµÄÖ÷¿ØÈ¨ºó²ÅÄܽøÐÐÊý¾Ý´«Ê䡣ʵ¼ÊµÄ´«ÊäÒ²²»½èÖúÂýËÙµÄISA DMACÀ´½øÐУ¬¶øÊÇÓÉÄÚǶÔÚPCI¿¨ÖеÄDMAµç·£¨±È´«Í³µÄISA DMACÒª¿ì£©À´Íê³É¡£Bus Mastering·½Ê½µÄDMA¿ÉÒÔÈÃPCIÍâÉèµÃµ½ËüÃÇÏëÒªµÄ´«Êä´ø¿í£¬Òò´ËËü±È±ê×¼DMA¹¦ÄÜÂú×ãÏÖ´ú¸ßÐÔÄÜÍâÉèµÄÒªÇó¡£

¡¡¡¡Ëæ×żÆËã»úÍâÉè¼¼ÊõµÄ²»¶Ï·¢Õ¹£¬ÏÖ´úÄÜÌṩ¸ü¿ì´«ÊäËÙÂʵÄUltra DMA£¨UDMA£©Ò²ÒѾ­±»¹ã·ºÊ¹ÓÃÁË¡£±¾ÎªËæºóµÄƪ·ùÖ»ÌÖÂÛISA×ÜÏߵıê×¼DMA¼¼ÊõÔÚLinuxÖеÄʵÏÖ¡£¼Çס£ºISA¿¨¼¸ºõ²»Ê¹ÓÃBus MasteringģʽµÄDMA£»¶øPCI¿¨Ö»Ê¹ÓÃBus MasteringģʽµÄDMA£¬Ëü´Ó²»Ê¹Óñê×¼DMA¡£

2.Intel 8237 DMAC

¡¡¡¡×î³õµÄIBM PC£¯XTÖÐÖ»ÓÐÒ»¸ö8237 DMAC£¬ËüÌṩÁË4¸ö8λµÄDMAͨµÀ£¨DMA channel 0£­3£©¡£´ÓIBM AT¿ªÊ¼£¬ÓÖÔö¼ÓÁËÒ»¸ö8237 DMAC£¨Ìṩ4¸ö16λµÄDMAͨµÀ£¬DMA channel 4£­7£©¡£Á½¸ö8237 DMACÒ»ÆðΪϵͳÌṩ8¸öDMAͨµÀ¡£ÓëÖжϿØÖÆÆ÷8259µÄ¼¶Áª·½Ê½Ïà·´£¬µÚÒ»¸öDMAC±»¼¶Áªµ½µÚ¶þ¸öDMACÉÏ£¬Í¨µÀ4±»ÓÃÓÚDMAC¼¶Áª£¬Òò´ËËü¶ÔÍâÉèÀ´ËµÊDz»¿ÉÓõġ£µÚÒ»¸öDMACÒ²³ÆÎª¡°slave DAMC¡±£¬µÚ¶þ¸öDMACÒ²³ÆÎª¡°Master DMAC¡±¡£

¡¡¡¡ÏÂÃæÎÒÃÇÀ´ÏêϸÐðÊöÒ»ÏÂIntel 8237Õâ¸öDMACµÄ½á¹¹¡£

¡¡¡¡Ã¿¸ö8237 DMAC¶¼Ìṩ4¸öDMAͨµÀ£¬Ã¿¸öDMAͨµÀ¶¼Óи÷×ԵļĴæÆ÷£¬¶ø8237±¾ÉíÒ²ÓÐÒ»×é¿ØÖÆ¼Ä´æÆ÷£¬ÓÃÒÔ¿ØÖÆËüËùÌṩµÄËùÓÐDMAͨµÀ¡£

¡¡¡¡2£®1 DMAͨµÀµÄ¼Ä´æÆ÷

¡¡¡¡8237 DMACÖеÄÿ¸öDMAͨµÀ¶¼ÓÐ5¸ö¼Ä´æÆ÷£¬·Ö±ðÊÇ£ºµ±Ç°µØÖ·¼Ä´æÆ÷¡¢µ±Ç°¼ÆÊý¼Ä´æÆ÷¡¢µØÖ·¼Ä´æÆ÷£¨Ò²³ÆÎªÆ«ÒƼĴæÆ÷£©¡¢¼ÆÊý¼Ä´æÆ÷ºÍÒ³¼Ä´æÆ÷¡£ÆäÖУ¬Ç°Á½¸öÊÇ8237µÄÄÚ²¿¼Ä´æÆ÷£¬¶ÔÍⲿÊDz»¿É¼ûµÄ¡£

¡¡¡¡£¨1£©µ±Ç°µØÖ·¼Ä´æÆ÷£¨Current Address Register£©£ºÃ¿¸öDMAͨµÀ¶¼ÓÐÒ»¸ö16λµÄµ±Ç°µØÖ·¼Ä´æÆ÷£¬±íʾһ¸öDMA´«ÊäÊÂÎñ£¨Transfer Transaction£©ÆÚ¼äµ±Ç°DMA´«Êä²Ù×÷µÄDMAÎïÀíÄÚ´æµØÖ·¡£ÔÚÿ¸öDMA´«Ê俪ʼǰ£¬8237¶¼»á×Ô¶¯µØÓøÃͨµÀµÄAddress RegisterÖеÄÖµÀ´³õʼ»¯Õâ¸ö¼Ä´æÆ÷£»ÔÚ´«ÊäÊÂÎñÆÚ¼äµÄÿ´ÎDMA´«Êä²Ù×÷Ö®ºó¸Ã¼Ä´æÆ÷µÄÖµ¶¼»á±»×Ô¶¯µØÔö¼Ó»ò¼õС¡£

¡¡¡¡£¨2£©µ±Ç°¼ÆÊý¼Ä´æÆ÷£¨Current Count Register£©£ºÃ¿¸öÿ¸öDMAͨµÀ¶¼ÓÐÒ»¸ö16λµÄµ±Ç°¼ÆÊý¼Ä´æÆ÷£¬±íʾµ±Ç°DMA´«ÊäÊÂÎñ»¹Ê£Ï¶àÉÙδ´«ÊäµÄÊý¾Ý¡£ÔÚÿ¸öDMA´«ÊäÊÂÎñ¿ªÊ¼Ö®Ç°£¬8237¶¼»á×Ô¶¯µØÓøÃͨµÀµÄCount RegisterÖеÄÖµÀ´³õʼ»¯Õâ¸ö¼Ä´æÆ÷¡£ÔÚ´«ÊäÊÂÎñÆÚ¼äµÄÿ´ÎDMA´«Êä²Ù×÷Ö®ºó¸Ã¼Ä´æÆ÷µÄÖµ¶¼»á±»×Ô¶¯µØÔö¼Ó»ò¼õС£¨²½³¤Îª1£©¡£

¡¡¡¡£¨3£©µØÖ·¼Ä´æÆ÷£¨Address Register£©»òÆ«ÒÆ¼Ä´æÆ÷£¨Offset Register£©£ºÃ¿¸öDMAͨµÀ¶¼ÓÐÒ»¸ö16λµÄµØÖ·¼Ä´æÆ÷£¬±íʾϵͳRAMÖеÄDMA»º³åÇøµÄÆðʼλÖÃÔÚÒ³Ä򵀮«ÒÆ¡£

¡¡¡¡£¨4£©¼ÆÊý¼Ä´æÆ÷£¨Count Register£©£ºÃ¿¸öDMAͨµÀ¶¼ÓÐÒ»¸ö16λµÄ¼ÆÊý¼Ä´æÆ÷£¬±íʾDMA»º³åÇøµÄ´óС¡£

¡¡¡¡£¨5£©Ò³¼Ä´æÆ÷£¨Page Register£©£º¸Ã¼Ä´æÆ÷¶¨ÒåÁËDMA»º³åÇøµÄÆðʼλÖÃËùÔÚÎïÀíÒ³µÄ»ùµØÖ·£¬¼´Ò³ºÅ¡£Ò³¼Ä´æÆ÷ÓеãÀàËÆÓÚPCÖеĶλùÖ·¼Ä´æÆ÷¡£

¡¡¡¡2£®2 8237 DAMCµÄ¿ØÖƼĴæÆ÷

¡¡¡¡£¨1£©ÃüÁî¼Ä´æÆ÷£¨Command Register£©

¡¡¡¡Õâ¸ö8λµÄ¼Ä´æÆ÷ÓÃÀ´¿ØÖÆ8237оƬµÄ²Ù×÷¡£Æä¸÷λµÄ¶¨ÒåÈçÏÂͼËùʾ£º

¡¡¡¡£¨2£©Ä£Ê½¼Ä´æÆ÷£¨Mode Register£©

¡¡¡¡ÓÃÓÚ¿ØÖƸ÷DMAͨµÀµÄ´«Êäģʽ£¬ÈçÏÂËùʾ£º

¡¡¡¡£¨3£©ÇëÇó¼Ä´æÆ÷£¨Request Register£©

¡¡¡¡ÓÃÓÚÏò¸÷DMAͨµÀ·¢³öDMAÇëÇ󡣸÷λµÄ¶¨ÒåÈçÏ£º

¡¡¡¡£¨4£©ÆÁ±Î¼Ä´æÆ÷£¨Mask Register£©

¡¡¡¡ÓÃÀ´ÆÁ±Îij¸öDMAͨµÀ¡£µ±Ò»¸öDMAͨµÀ±»ÆÁ±Îºó£¬Ëü¾Í²»ÄÜÔÚ·þÎñÓÚDMAÇëÇó£¬Ö±µ½Í¨µÀµÄÆÁ±ÎÂë±»Çå³ý¡£¸÷λµÄ¶¨ÒåÈçÏ£º

¡¡¡¡ÉÏÊöÆÁ±Î¼Ä´æÆ÷Ò²³ÆÎª¡°µ¥Í¨µÀÆÁ±Î¼Ä´æÆ÷¡±£¨Single Channel Mask Register£©£¬ÒòΪËüÒ»´ÎÖ»ÄÜÆÁ±ÎÒ»¸öͨµÀ¡£´ËÍ⺬ÓÐÒ»¸öÆÁ±Î¼Ä´æÆ÷£¬¿ÉÒÔʵÏÖÒ»´ÎÆÁ±ÎËùÓÐ4¸öDMAͨµÀ£¬ÈçÏ£º

¡¡¡¡£¨5£©×´Ì¬¼Ä´æÆ÷£¨Status Register£©

¡¡¡¡Ò»¸öÖ»¶ÁµÄ8λ¼Ä´æÆ÷£¬±íʾ¸÷DMAͨµÀµÄµ±Ç°×´Ì¬¡£±ÈÈ磺DMAͨµÀÊÇ·ñÕý·þÎñÓÚÒ»¸öDMAÇëÇ󣬻òÕßij¸öDMAͨµÀÉϵÄDMA´«ÊäÊÂÎñÒѾ­Íê³É¡£¸÷λµÄ¶¨ÒåÈçÏ£º

¡¡¡¡2£®3 8237 DMACµÄI/O¶Ë¿ÚµØÖ·

¡¡¡¡Ö÷¡¢´Ó8237 DMACµÄ¸÷¸ö¼Ä´æÆ÷¶¼ÊDZàÖ·ÔÚI/O¶Ë¿Ú¿Õ¼äµÄ¡£¶øÇÒÆäÖÐÓÐЩI/O¶Ë¿ÚµØÖ·¶ÔÓÚI/O¶Á¡¢Ð´²Ù×÷Óв»Í¬µÄ±íʾº¬Òå¡£ÈçϱíʾËùʾ£º


Slave DMAC¡¯s I/O port        Master DMAC¡¯sI/O port        read        write
0x000        0x0c0        Channel 0/4 µÄAddress Register
0x001        0x0c1        Channel 0£¯4µÄCount Register
0x002        0x0c2        Channel 1£¯5 µÄAddress Register
0x003        0x0c3        Channel 1£¯5µÄCount Register
0x004        0x0c4        Channel 2£¯6µÄAddress Register
0x005        0x0c5        Channel 2£¯6µÄCount Register
0x006        0x0c6        Channel 3£¯7µÄAddress Register
0x007        0x0c7        Channel 3£¯7µÄCount Register
0x008        0x0d0        Status Register        Command Register
0x009        0x0d2                Request Register
0x00a        0x0d4                Single Channel Mask Register
0x00b        0x0d6                Mode Register
0x00c        0x0d8                Clear Flip-Flop Register
0x00d        0x0da        Temporary Register        Reset DMA controller
0x00e        0x0dc                Reset all channel masks
0x00f        0x0de                all-channels Mask Register

¡¡¡¡¸÷DMAͨµÀµÄPage RegisterÔÚI/O¶Ë¿Ú¿Õ¼äÖеĵØÖ·ÈçÏ£º


DMA channel        Page Register¡¯sI/O port address
0        0x087
1        0x083
2        0x081
3        0x082
4        0x08f
5        0x08b
6        0x089
7        0x08a

¡¡¡¡×¢ÒâÁ½µã£º

¡¡¡¡1. ¸÷DMAͨµÀµÄAddress RegisterÊÇÒ»¸ö16λµÄ¼Ä´æÆ÷£¬µ«Æä¶ÔÓ¦µÄI/O¶Ë¿ÚÊÇ8λ¿í£¬Òò´Ë¶ÔÕâ¸ö¼Ä´æÆ÷µÄ¶Áд¾ÍÐèÒªÁ½´ÎÁ¬ÐøµÄI/O¶Ë¿Ú¶Áд²Ù×÷£¬µÍ8λÊ×Ïȱ»·¢ËÍ£¬È»ºó½ô½Ó×Å·¢Ë͸ß8λ¡£

¡¡¡¡2. ¸÷DMAͨµÀµÄCount Register£ºÕâÒ²ÊÇÒ»¸ö16λ¿íµÄ¼Ä´æÆ÷£¨ÎÞÂÛ¶ÔÓÚ8λDMA»¹ÊÇ16λDMA£©£¬µ«Ïà¶ÔÓ¦µÄI/O¶Ë¿ÚÒ²ÊÇ8λ¿í£¬Òò´Ë¶ÁдÕâ¸ö¼Ä´æÆ÷ͬÑùÐèÒªÁ½´ÎÁ¬ÐøµÄI/O¶Ë¿Ú¶Áд²Ù×÷£¬¶øÇÒͬÑùÊÇÏÈ·¢Ë͵Í8룬ÔÙ·¢Ë͸ß8λ¡£ÍùÕâ¸ö¼Ä´æÆ÷ÖÐдÈëµÄÖµÓ¦¸ÃÊÇʵ¼ÊÒª´«ÊäµÄÊý¾Ý³¤¶È¼õ1ºóµÄÖµ¡£ÔÚDMA´«ÊäÊÂÎñÆÚ¼ä£¬Õâ¸ö¼Ä´æÆ÷ÖеÄÖµÔÚÿ´ÎDMA´«Êä²Ù×÷ºó¶¼»á±»¼õ1£¬Òò´Ë¶ÁÈ¡Õâ¸ö¼Ä´æÆ÷ËùµÃµ½µÄÖµ½«Êǵ±Ç°DMAÊÂÎñËùÊ£ÓàµÄδ´«ÊäÊý¾Ý³¤¶È¼õ1ºóµÄÖµ¡£µ±DMA´«ÊäÊÂÎñ½áÊøÊ±£¬¸Ã¼Ä´æÆ÷ÖеÄÖµÓ¦¸Ã±»ÖÃΪ0¡£

¡¡¡¡2£®4 DMAͨµÀµÄµäÐÍʹÓÃ

¡¡¡¡ÔÚÒ»¸öµäÐ͵ÄPC»úÖУ¬Ä³Ð©DMAͨµÀͨ³£±»¹Ì¶¨µØÓÃÓÚһЩPC»úÖеıê×¼ÍâÉ裬ÈçÏÂËùʾ£º


Channel        Size        Usage
0        8-bit        Memory Refresh
1        8-bit        Free
2        8-bit        Floppy Disk Controller
3        8-bit        Free
4        16-bit        Cascading
5        16-bit        Free
6        16-bit        Free
7        16-bit        Free

¡¡¡¡2£®5 Æô¶¯Ò»¸öDMA´«ÊäÊÂÎñµÄ²½Öè

¡¡¡¡ÒªÆô¶¯Ò»¸öDMA´«ÊäÊÂÎñ±ØÐë¶Ô8237½øÐбà³Ì£¬ÆäµäÐͲ½ÖèÈçÏ£º

¡¡¡¡1.ͨ¹ýCLIÖ¸Áî¹Ø±ÕÖжϡ£
¡¡¡¡2.DisableÄǸö½«±»ÓÃÓÚ´Ë´ÎDMA´«ÊäÊÂÎñµÄDMAͨµÀ¡£
¡¡¡¡3.ÏòFlip-Flop¼Ä´æÆ÷ÖÐдÈë0Öµ£¬ÒÔÖØÖÃËü¡£
¡¡¡¡4.ÉèÖÃMode Register¡£
¡¡¡¡5.ÉèÖÃPage Register¡£
¡¡¡¡6.ÉèÖÃAddress Register¡£
¡¡¡¡7.ÉèÖÃCount Register¡£
¡¡¡¡8.EnableÄǸö½«±»ÓÃÓÚ´Ë´ÎDMA´«ÊäÊÂÎñµÄDMAͨµÀ¡£
¡¡¡¡9.ÓÃSTIÖ¸ÁÖжϡ£

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

¡¡¡¡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ͨµÀ½øÐÐģʽÉèÖá£

¡¡¡¡£¨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);
}

¡¡¡¡3£®3 ¶ÔDMACµÄ±£»¤

¡¡¡¡DMACÊÇÒ»ÖÖÈ«¾ÖµÄ¹²Ïí×ÊÔ´£¬ÎªÁ˱£Ö¤É豸Çý¶¯³ÌÐò¶ÔËüµÄ¶ÀÕ¼·ÃÎÊ£¬LinuxÔÚkernel£¯dma.cÎļþÖж¨ÒåÁË×ÔÐýËødma_spin_lockÀ´±£»¤Ëü£¨Êµ¼ÊÉÏÊDZ£»¤DMACµÄI/O¶Ë¿Ú×ÊÔ´£©¡£ÈκÎÏëÒª·ÃÎÊDMACµÄÉ豸Çý¶¯³ÌÐò¶¼Ê×ÏȱØÐëÏȳÖÓÐ×ÔÐýËødma_spin_lock¡£ÈçÏ£º


static __inline__ unsigned long claim_dma_lock(void)
{
        unsigned long flags;
        spin_lock_irqsave(&dma_spin_lock, flags); /* ¹ØÖжϣ¬¼ÓËø*/
        return flags;
}

static __inline__ void release_dma_lock(unsigned long flags)
{
        spin_unlock_irqrestore(&dma_spin_lock, flags);/* ¿ªÖжϣ¬¿ªËø*/
}

4 Linux¶ÔISA DMAͨµÀ×ÊÔ´µÄ¹ÜÀí

¡¡¡¡DMAͨµÀÊÇÒ»ÖÖϵͳȫ¾Ö×ÊÔ´¡£ÈκÎISAÍâÉèÏëÒª½øÐÐDMA´«Ê䣬Ê×Ïȶ¼±ØÐëÈ¡µÃij¸öDMAͨµÀ×ÊÔ´µÄʹÓÃȨ£¬²¢ÔÚ´«Êä½áÊøºóÊÍ·ÅËùʹÓÃDMAͨµÀ×ÊÔ´¡£´ÓÕâ¸ö½Ç¶È¿´£¬DMAͨµÀ×ÊÔ´ÊÇÒ»ÖÖ¹²ÏíµÄ¶ÀÕ¼ÐÍ×ÊÔ´¡£

¡¡¡¡LinuxÔÚkernel/Dma.cÎļþÖÐʵÏÖÁ˶ÔDMAͨµÀ×ÊÔ´µÄ¹ÜÀí¡£

¡¡¡¡4£®1 ¶ÔDMAͨµÀ×ÊÔ´µÄÃèÊö

¡¡¡¡LinuxÔÚkernel/Dma.cÎļþÖж¨ÒåÁËÊý¾Ý½á¹¹dma_chanÀ´ÃèÊöDMAͨµÀ×ÊÔ´¡£¸Ã½á¹¹ÀàÐ͵͍ÒåÈçÏ£º


struct dma_chan {
        int  lock;
        const char *device_id;
};

¡¡¡¡ÆäÖУ¬Èç¹û³ÉÔ±lock£¡£½0Ôò±íʾDMAͨµÀÕý±»Ä³¸öÉ豸ËùʹÓã»·ñÔò¸ÃDMAͨµÀ¾Í´¦ÓÚfree״̬¡£¶ø³ÉÔ±device_id¾ÍÖ¸ÏòʹÓøÃDMAͨµÀµÄÉ豸Ãû×Ö×Ö·û´®¡£

¡¡¡¡»ùÓÚÉÏÊö½á¹¹ÀàÐÍdma_chan£¬Linux¶¨ÒåÁËÈ«¾ÖÊý×édma_chan_busy£Û£Ý£¬ÒÔ·Ö±ðÃèÊö8¸öDMAͨµÀ×ÊÔ´¸÷×ÔµÄʹÓÃ״̬¡£ÈçÏ£º


static struct dma_chan dma_chan_busy[MAX_DMA_CHANNELS] = {
        { 0, 0 },
        { 0, 0 },
        { 0, 0 },
        { 0, 0 },
        { 1, "cascade" },
        { 0, 0 },
        { 0, 0 },
        { 0, 0 }
};

¡¡¡¡ÏÔÈ»£¬ÔÚ³õʼ״̬ʱ³ýÁËDMAͨµÀ4Í⣬ÆäÓàDMAͨµÀ½Ô´¦ÓÚfree״̬¡£

¡¡¡¡4£®2 DMAͨµÀ×ÊÔ´µÄÉêÇë

¡¡¡¡ÈκÎISA¿¨ÔÚʹÓÃij¸öDMAͨµÀ½øÐÐDMA´«Êä֮ǰ£¬ÆäÉ豸Çý¶¯³ÌÐò¶¼±ØÐëÏòÄÚºËÌá³öDMAͨµÀ×ÊÔ´µÄÉêÇë¡£Ö»ÓÐÉêÇë»ñµÃ³É¹¦ºó²ÅÄÜʹÓÃÏàÓ¦µÄDMAͨµÀ¡£·ñÔò¾Í»á·¢Éú×ÊÔ´³åÍ»¡£

¡¡¡¡º¯Êýrequest_dma£¨£©ÊµÏÖDMAͨµÀ×ÊÔ´µÄÉêÇë¡£ÆäÔ´ÂëÈçÏ£º


int request_dma(unsigned int dmanr, const char * device_id)
{
        if (dmanr >= MAX_DMA_CHANNELS)
                return -EINVAL;

        if (xchg(&dma_chan_busy[dmanr].lock, 1) != 0)
                return -EBUSY;

        dma_chan_busy[dmanr].device_id = device_id;

        /* old flag was 0, now contains 1 to indicate busy */
        return 0;
}

¡¡¡¡ÉÏÊöº¯ÊýµÄºËÐÄʵÏÖ¾ÍÊÇÓÃÔ­×Ó²Ù×÷xchg()ÈóÉÔ±±äÁ¿dma_chan_busy[dmanr].lockºÍÖµ1½øÐн»»»²Ù×÷£¬xchg()½«·µ»Ølock³ÉÔ±ÔÚ½»»»²Ù×÷֮ǰµÄÖµ¡£Òò´Ë£ºÈç¹ûxchg()·µ»Ø·Ç0Öµ£¬Õâ˵Ã÷dmanrËùÖ¸¶¨µÄDMAͨµÀÒѱ»ÆäËûÉ豸ËùÕ¼Óã¬ËùÒÔrequest_dma()º¯Êý·µ»Ø´íÎóÖµ£­EBUSY±íʾָ¶¨DMAͨµÀÕý棻·ñÔò£¬Èç¹ûxchg()·µ»Ø0Öµ£¬ËµÃ÷dmanrËùÖ¸¶¨µÄDMAͨµÀÕý´¦ÓÚfree״̬£¬ÓÚÊÇxchg()½«Æälock³ÉÔ±ÉèÖ