| Çý¶¯ |
Linuxϵͳ֧³Ö¶àÖÖÉ豸£¬ÕâЩÉ豸µÄÇý¶¯³ÌÐòÖ®¼äÓÐһЩ¹²Í¬µÄÌØµã£º
* Äں˴úÂ룺É豸Çý¶¯³ÌÐòÊÇϵͳÄں˵ÄÒ»²¿·Ö£¬ËùÒÔÈç¹ûÇý¶¯³ÌÐò³öÏÖ´íÎóµÄ»°£¬½«¿ÉÄÜÑÏÖØµØÆÆ»µÕû¸öϵͳ¡£
* Äں˽ӿڣºÉ豸Çý¶¯³ÌÐò±ØÐëΪϵͳÄں˻òÕßËüÃǵÄ×ÓϵͳÌṩһ¸ö±ê×¼µÄ½Ó¿Ú¡£ÀýÈ磬һ¸öÖÕ¶ËÇý¶¯³ÌÐò±ØÐëΪLinuxÄÚºËÌṩһ¸öÎļþI/O½Ó¿Ú£»Ò»¸öSCSIÉ豸Çý¶¯³ÌÐòÓ¦¸ÃΪSCSI×ÓϵͳÌṩһ¸öSCSIÉ豸½Ó¿Ú£¬Í¬Ê±SCSI×ÓϵͳҲӦΪϵͳÄÚºËÌṩÎļþI/OºÍ»º³åÇø¡£
* Äں˻úÖÆºÍ·þÎñ£ºÉ豸Çý¶¯³ÌÐòÀûÓÃһЩ±ê×¼µÄÄں˷þÎñ£¬ÀýÈçÄÚ´æ·ÖÅäµÈ¡£
* ¿É×°È룺´ó¶àÊýµÄLinuxÉ豸Çý¶¯³ÌÐò¶¼¿ÉÒÔÔÚÐèҪʱװÈëÄںˣ¬ÔÚ²»ÐèÒªÊ±Ð¶ÔØ¡£
* ¿ÉÉèÖãºLinuxϵͳÉ豸Çý¶¯³ÌÐò¿ÉÒÔ¼¯³ÉΪϵͳÄں˵ÄÒ»²¿·Ö£¬ÖÁÓÚÄÄÒ»²¿·ÖÐèÒª¼¯³Éµ½ÄÚºËÖУ¬¿ÉÒÔÔÚϵͳ±àÒëʱÉèÖá£
¡¡¡¡ÉêÃ÷£ºÕâ·ÝÎĵµÊǰ´ÕÕ×ÔÓÉÈí¼þ¿ª·ÅÔ´´úÂëµÄ¾«Éñ·¢²¼µÄ£¬ÈκÎÈË¿ÉÒÔÃâ·Ñ»ñµÃ¡¢Ê¹ÓúÍÖØÐ·¢²¼£¬µ«ÊÇÄãûÓÐÏÞÖÆ±ðÈËÖØÐ·¢²¼Äã·¢²¼ÄÚÈݵÄȨÀû¡£·¢²¼±¾ÎĵÄÄ¿µÄÊÇÏ£ÍûËüÄܶԶÁÕßÓÐÓ㬵«Ã»ÓÐÈκε£±££¬ÉõÖÁûÓÐÊʺÏÌØ¶¨Ä¿µÄµÄÒþº¬µÄµ£±£¡£¸üÏêϸµÄÇé¿öÇë²ÎÔÄ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ÄÚ´æ×ÊÔ´£¬¶ø²»Ó¦¸Ãͨ¹ýÖ¸ÏòºËÐÄÐ鵨ַµÄÖ¸ÕëÀ´·ÃÎÊ¡£
×Ö·ûÉ豸½Ó¿ÚÖ§³ÖÃæÏò×Ö·ûµÄ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һ¸ö£¬ÏµÍ³»áÓÃȱʡµÄ×Ó³ÌÐòÀ´´úÌæ¡£¶ÔÓÚ²»Í¬µÄϵͳ£¬Ò²»¹ÓÐһЩÆäËüµÄÈë¿Úµã¡£
#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Àï¡£
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 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×ÜÏßµÄÖ§³ÖÓõ½½Ï¶àµÄº¯Êý£¬²¢ÇÒҪСÐÄ´¦ÀíÖжϡ£
×÷Ϊ»Ø±¨£¬²»ÐèÒªÄãµÄ½éÈ룬ϵͳ°ÑÒ»Çж¼ÅäÖúÃÁË¡£
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µÄÒýÓöøÒÑ. */
.
.
.
}
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 À´µÄ·½±ã¾ÍÊÇÁË¡£
»¹ÒªÔÙÀ´Ò»¸öÂð ? Äã×Ô¼ºÈ¥×ö°É !
¡¡¡¡£¨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״̬£¬ÓÚÊ