vxWorks网络设备驱动开发之-muxDevLoad

muxDevLoad是用来加载一个网络设备的,muxDevLoad成功执行后,我们就可以在shell里调用ifconfig命令来察看load的网卡设备了。

先看一下函数的调用流程,最后大概分析一下muxDevLoad的功能。

1726 /******************************************************************************
1727 *
1728 * usrNetInit - network intialization routine called from usrConfig.c
1729 * 
1730 */  
1731 STATUS usrNetInit
1732     (
1733     char *bootString
1734     )
1735     {
1736 #ifdef INCLUDE_BOOT_LINE_INIT
1737     usrBootLineParse(NULL);
1738 #endif /* INCLUDE_BOOT_LINE_INIT */ 
1739     networkinit ();
1740     return (OK);
1741     }

该函数位于"vxworks-6.8/target/src/config/usrNetwork.c", 调用netWorkInit()来初始化整个网络模块。

netWorkInit()

         ------->usrNetEndLibInit() : "vxworks-6.8/target/src/config/usrNetwork.c"

                       -------->vxbDevMethodRun((UINT32)&muxDevConnect_desc, NULL); "vxworks-6.8/target/src/config/usrNetwork.c"

通过上述函数流程,可以看到vxbDevMethodRun遍历所有的注册设备,对每个设备调用muxDevConnect_desc函数,看看muxDevConnect_desc函数是哪儿定义的。

下面这段代码是从驱动:vxworks-6.8/target/src/hwif/end/an983VxbEnd.c 摘出来的。

 141 LOCAL struct vxbDeviceMethod anMethods[] =
 142    {
 143    DEVMETHOD(miiRead,       anPhyRead),
 144    DEVMETHOD(miiWrite,      anPhyWrite),
 145    DEVMETHOD(miiMediaUpdate,    anLinkUpdate),
 146    DEVMETHOD(muxDevConnect, anMuxConnect),
 147    DEVMETHOD(vxbDrvUnlink,  anInstUnlink),
 148    { 0, 0 }
 149    }; 

anMethods是一个vxbDeviceMethod结构体数组,struct vxbDeviceMethod结构体定义如下:

266 /*
267  *  An alternative method for bus controllers to provide the
268  *  methods used by downstream devices.  This structure is
269  *  provided so that the controller can provide a null-terminated
270  *  list of method/handler pairs.
271  *
272  *  When a driver fetches the access methods, the standard methods
273  *  are used first.  If the method is not one of the standard
274  *  methods (specified in the vxbAccessList structure), or if the
275  *  method specified is NULL in the controller's standard methods,
276  *  then the vxbAccessMethodsGet() routine searches through any
277  *  methods listed in the pMethods field of the vxbAccessList
278  *  structure.
279  *
280  *  In addition, this structure is used by all devices to provide
281  *  services to OS modules such as power management.
282  */ 
283 
284 struct vxbDeviceMethod
285     {
286     UINT32      devMethodId;
287     FUNCPTR     handler;
288     };

宏DEVMETHOD的定义如下:

171 /* method related macros, for driver use and method caller use */
172 
173 #define DEVMETHOD(NAME, FUNC)         { (UINT32)&NAME##_desc, (FUNCPTR) FUNC }
174 #define DEVMETHOD_END                 { 0, NULL }
175 #define METHOD_DECL(NAME)             IMPORT char NAME##_desc[];
176 #define DEVMETHOD_DEF(METHOD, STRING) char METHOD##_desc[]=STRING; 
177 #define DEVMETHOD_CALL(METHOD)        ((UINT32)(&METHOD##_desc[0]))

从vxbDeviceMethod结构体可以看出,能通过vxbDevMethodRun函数调用的函数必须有一个函数ID,DEVMETHOD可以帮助生成vxDeviceMethod实例。

到这一步,已经可以调到一个具体驱动的muxDevConnect函数了,下面分析一个具体驱动的muxDevConnect函数。还是以an983VxbEnd.c为例,代码如下:

 855 /*****************************************************************************
 856 *
 857 * anMuxConnect - muxConnect method handler
 858 *
 859 * This function handles muxConnect() events, which may be triggered
 860 * manually or (more likely) by the bootstrap code. Most VxBus
 861 * initialization occurs before the MUX has been fully initialized,
 862 * so the usual muxDevLoad()/muxDevStart() sequence must be defered
 863 * until the networking subsystem is ready. This routine will ultimately
 864 * trigger a call to anEndLoad() to create the END interface instance.
 865 *
 866 * RETURNS: N/A
 867 *
 868 * ERRNO: N/A
 869 */
 870 
 871 LOCAL void anMuxConnect
 872     (
 873     VXB_DEVICE_ID pDev,
 874     void * unused
 875     )
 876     {
 877     AN_DRV_CTRL *pDrvCtrl;
 878 
 879     /*
 880      * Attach our ISR. For PCI, the index value is always
 881      * 0, since the PCI bus controller dynamically sets
 882      * up interrupts for us.
 883      */
 884 
 885     vxbIntConnect (pDev, 0, anEndInt, pDev->pDrvCtrl);
 886 
 887     pDrvCtrl = pDev->pDrvCtrl;
 888 
 889     /* Save the cookie. */
 890 
 891     pDrvCtrl->anMuxDevCookie = muxDevLoad (pDev->unitNumber,
 892         anEndLoad, "", TRUE, pDev);
 893 
 894     if (pDrvCtrl->anMuxDevCookie != NULL)
 895         muxDevStart (pDrvCtrl->anMuxDevCookie);
 896 
 897     if (_func_m2PollStatsIfPoll != NULL)
 898         endPollStatsInit (pDrvCtrl->anMuxDevCookie,
 899             _func_m2PollStatsIfPoll);
 900 
 901     return;
 902     }
anMuxConnect首先注册中断,紧接着调用muxDevLoad函数完成网络设备的加载,传入的参数分别为设备的单元号,当同种设备有多个实例时,可以通过pDev->unitNumber区分开来。第二个参数是驱动实现的endLoad函数。最后一个是pDev指向当前网卡的设备实例指针。这三个参数比较重要。下面给出完整的muxDevLoad函数代码,从中可以看出muxDevLoad分两次调用anEndLoad函数,最终完成设备注册,通过muxDevLoad代码,可以更清楚的看到网卡实例的结构体在内核中是如何存放的。
 503 /******************************************************************************
 504 * 
 505 * muxDevLoad - load a driver into the MUX
 506 * 
 507 * The muxDevLoad() routine loads a network driver into the MUX.  Internally, 
 508 * this routine calls the specified <endLoad> routine to initialize the
 509 * software state of the device.  After the device is initialized,
 510 * muxDevStart() must be called to start the device. 
 511 * .IP <unit> 15
 512 * Expects the unit number of the device. 
 513 * .IP <endLoad> 
 514 * Expects a pointer to the network driver's endLoad() or nptLoad() entry
 515 * point. 
 516 * .IP <pInitString> 
 517 * Expects a pointer to an initialization string, typically a colon-delimited
 518 * list of options.  The muxDevLoad() routine passes this along blindly to 
 519 * the <endLoad> function.
 520 * .IP <loaning> 
 521 * Currently unused. Expects a boolean value that tells the MUX whether the
 522 * driver supports buffer loaning on this device.  If the low-level device
 523 * cannot support buffer loaning, passing in TRUE has no effect.  
 524 * .IP <pBSP>
 525 * This argument is passed blindly to the driver, which may or may not use it.  
 526 * It is provided so that the BSP can pass in tables of functions that the
 527 * driver can use but that are specific to the particular BSP on which
 528 * it runs. 
 529 *   
 530 * RETURNS: A cookie representing the new device, or NULL if an error occurred.
 531 *   
 532 * ERRNO: S_muxLib_LOAD_FAILED
 533 */  
 534     535 DEV_COOKIE muxDevLoad
 536     (
 537     int       unit,                      /* unit number of device */
 538     END_OBJ * (*endLoad) (char*, void*), /* load function of the driver  */
 539     char *    pInitString,       /* init string for this driver  */
 540     BOOL      loaning,               /* we loan buffers  */
 541     void *    pBSP                       /* for BSP group  */
 542     )
 543     {
 544     END_OBJ *     pNew = NULL;
 545     END_TBL_ROW * pNode = NULL;
 546     NODE *    enode;
 547     DEV_OBJ       dev;
 548     char          initString [END_INIT_STR_MAX];
 549     int           endStyle;
 550     MUX_END_STYLE_INFO * style;
 551     int       j;
 552 
 553     bzero (initString, END_INIT_STR_MAX);
 554 
 555     /* Create a fake END placeholder, mark it as invalid */
 556 
 557     bzero ((caddr_t)&dev, sizeof (dev));
 558     dev.unit = unit;
 559     dev.muxFlags = MUX_END_FLAG_LOADING;
 560     dev.refs = 1;
 561 
 562     if (snprintf (initString, END_INIT_STR_MAX,
 563           "%d:%s", unit, pInitString) >= END_INIT_STR_MAX)
 564         goto muxDevLoad_errout;
 565 
 566     /*
 567      * Loading a device is a two pass algorithm.
 568      *
 569      * This is Pass 1.
 570      *
 571      * In the first pass we ask the device what its name is.
 572      * The END must respect the name length limits of dev.name,
 573      * END_NAME_MAX = 16 characters, including terminating NUL.
 574      * Actually, the network stack imposes tighter limits in
 575      * interface ioctls, for which the name (including unit number &
 576      * terminating NUL) must fit in 16 bytes.
 577      */
 578 
 579     if (endLoad (dev.name, NULL) != 0)
 580         goto muxDevLoad_errout;
 581 
 582     /*
 583      * Now we verify that the device hasn't already been loaded, and
 584      * to protect against concurrent loads of the same device, we
 585      * put a temporary placeholder for the END into the MUX list.
 586      *
 587      * We use the temporary placeholder rather than holding muxLock
 588      * across the END operations since we prefer not to establish
 589      * any mutex ordering between muxLock and any semaphores taken
 590      * by endLoad() or the device ioctl routine.
 591      */
 592 
 593     if (semTake (muxLock, WAIT_FOREVER) != OK)
 594     return NULL;
 595 
 596     /*
 597      * Consider replacing this data structure with a hash table.
 598      * Consider sorting so that an iterator could be defined that
 599      * traversed through the lists in a well-defined order.
 600      * Consider interface indexes managed by the MUX (& consistent
 601      * with the ipnet & other stacks).
 602      */
 603 
 604     for (pNode = (END_TBL_ROW *)lstFirst(&endList); pNode != NULL;
 605     pNode = (END_TBL_ROW *)lstNext(&pNode->node))
 606     {
 607     if (strcmp (pNode->name, dev.name) == 0)
 608             break;
 609     }
 610 
 611     if (pNode != NULL) /* there's already a row for this driver */
 612         {
 613         /* 
 614          * pNew is used temporarily here. We do not create a new END object
 615          * till later.
 616          */
 617 
 618         for (enode = lstFirst(&pNode->units); enode != NULL;
 619              enode = lstNext(enode))
 620             {
 621         pNew = member_to_object (enode, END_OBJ, devObject.node);
 622             if (pNew->devObject.unit == unit)
 623                 {
 624         if (_func_logMsg)
 625             _func_logMsg ("muxDevLoad: %s%d already loaded!\n",
 626                   dev.name, unit);
 627 
 628         semGive (muxLock);
 629         goto muxDevLoad_errout;
 630                 }
 631             }
 632         }
 633     else  /* There is no row yet for this device; add one. */
 634         {
 635     /* MEM */
 636         pNode = malloc (sizeof(END_TBL_ROW));
 637         if (pNode == NULL)
 638             {
 639         semGive (muxLock);
 640         return NULL;
 641             }
 642 
 643         bzero ((char *)pNode, sizeof(END_TBL_ROW));
 644         strncpy (pNode->name, dev.name, END_NAME_MAX - 1);
 645     pNode->name [END_NAME_MAX - 1] = EOS;
 646         lstAdd (&endList, &pNode->node);
 647         }
 648 
 649     /*
 650      * Add placeholder to list before unlocking, to protect against
 651      * concurrent loads of the same device.
 652      */
 653 
 654     lstAdd (&pNode->units, &dev.node);
 655 
 656     taskSafe ();  /* stay delete-safe after unlocking */
 657 
 658     semGive (muxLock);
 659 
 660     /*
 661      * This is Pass 2.
 662      *
 663      * Now that we can determine a unique number we assign that number to
 664      * the device and actually load it.
 665      */
 666 
 667     pNew = (END_OBJ *)endLoad ( (char *)initString, pBSP);
 668 
 669     if (pNew == NULL)
 670         goto muxLoadErr;
 671 
 672     if (pNew->pFuncTable == NULL || pNew->pFuncTable->ioctl == NULL)
 673         goto muxLoadErr;
 674 
 675     /* should this be done by END_OBJ_INIT() ? */
 676 
 677     pNew->devObject.dummyBinding = pNew;
 678     pNew->devObject.refs = 1;
 679     pNew->devObject.muxFlags = 0;
 680 
 681     pNew->unloadInfo = NULL;
 682 
 683     /*
 684      * There used to be stuff here to decide whether to set the
 685      * END_MIB_2233 flag in pNew->flags here; that's obsolete in
 686      * more ways than one. Removed it. (TODO: What to do instead?)
 687      */
 688 
 689     /*
 690      * Determine if driver uses END or NPT interface. Default is END.
 691      * END_STYLE_END2 (ipnet-native) drivers must support EIOCGSTYLE.
 692      */
 693 
 694     endStyle = END_STYLE_END;
 695 
 696     if (pNew->pFuncTable->ioctl (pNew, EIOCGSTYLE,
 697                  (caddr_t) &endStyle) != OK &&
 698     pNew->pFuncTable->ioctl (pNew, EIOCGNPT, NULL) == OK)
 699         {
 700     endStyle = END_STYLE_NPT;
 701         }
 702 
 703     pNew->endStyle = endStyle;
 704 
 705     /*
 706      * Set the native send routine and argument.
 707      *
 708      * TODO: may need a send wrapper to collect statistics for
 709      * ENDs that don't set the END_MIB_2233 flag. See the old
 710      * _muxTkSendEnd() and _muxTkSendNpt().
 711      *
 712      * Actually, endM2Init() sets END_MIB_2233 in each END
 713      * depending on whether RFC 2233 support is included in
 714      * the image (pMibRtn != NULL); that's independent of
 715      * the driver.  A few older drivers that don't call
 716      * endM2Init() might set END_MIB_2233 themselves.
 717      */
 718     pNew->send[endStyle].func = pNew->pFuncTable->send;
 719     pNew->send[endStyle].arg = pNew;
 720 
 721     pNew->pollSend[endStyle].func = pNew->pFuncTable->pollSend;
 722     pNew->pollSend[endStyle].arg = pNew;
 723 
 724     pNew->pollRecv[endStyle].func = pNew->pFuncTable->pollRcv;
 725     pNew->pollRecv[endStyle].arg = pNew;
 726 
 727     style = &muxEndStyles[endStyle];
 728 
 729     if ((pNew->receiveRtn = style->rxRtn) == NULL)
 730     {
 731     if (_func_logMsg)
 732         _func_logMsg ("No support for end style %d, required by %s%n\n",
 733               endStyle, pNew->devObject.name, unit);
 734     }
 735     pNew->rxArg = pNew; /* do we need rxArg? */
 736 
 737     /*
 738      * Install wrapper send, polled send, and polled receive
 739      * functions for different supported styles
 740      */
 741     for (j = 0; j < NUM_END_STYLES; ++j)
 742     {
 743     if (j == endStyle) /* skip the native style */
 744         continue;
 745 
 746     if (style->sendWrappers[j] == NULL)
 747         continue;
 748 
 749     pNew->send[j].func = style->sendWrappers[j];
 750     pNew->send[j].arg = pNew;
 751     pNew->pollSend[j].func = style->pollSendWrappers[j];
 752     pNew->pollSend[j].arg = pNew;
 753     pNew->pollRecv[j].func = style->pollReceiveWrappers[j];
 754     pNew->pollRecv[j].arg = pNew;
 755     }
 756 
 757     semTake (muxLock, WAIT_FOREVER);
 758 
 759     taskUnsafe (); /* remove extra deletion safety count */
 760 
 761     /* remove placeholder */
 762 
 763     lstDelete (&pNode->units, &dev.node);
 764 
 765     lstAdd (&pNode->units, &pNew->devObject.node);
 766 
 767     semGive (muxLock);
 768 
 769     return (pNew);
 770 
 771 muxLoadErr:
 772     semTake (muxLock, WAIT_FOREVER);
 773 
 774     taskUnsafe (); /* remove extra deletion safety count */
 775 
 776     /* remove placeholder */
 777 
 778     lstDelete (&pNode->units, &dev.node);
 779 
 780     if (lstCount (&pNode->units) == 0)
 781         {
 782         lstDelete (&endList, &pNode->node);
 783         free (pNode);
 784         }
 785 
 786     semGive (muxLock);
 787 
 788 muxDevLoad_errout:
 789     errnoSet (S_muxLib_LOAD_FAILED);
 790     return (NULL);
 791     }

//TODO:以后再加详细注释

下面是具体驱动的andLoad函数实现:

1080 /*****************************************************************************
1081 *
1082 * anEndLoad - END driver entry point
1083 *
1084 * This routine initializes the END interface instance associated
1085 * with this device. In traditional END drivers, this function is
1086 * the only public interface, and it's typically invoked by a BSP
1087 * driver configuration stub. With VxBus, the BSP stub code is no
1088 * longer needed, and this function is now invoked automatically
1089 * whenever this driver's muxConnect() method is called.
1090 *
1091 * For older END drivers, the load string would contain various
1092 * configuration parameters, but with VxBus this use is deprecated.
1093 * The load string should just be an empty string. The second
1094 * argument should be a pointer to the VxBus device instance
1095 * associated with this device. Like older END drivers, this routine
1096 * will still return the device name if the init string is empty,
1097 * since this behavior is still expected by the MUX. The MUX will
1098 * invoke this function twice: once to obtain the device name,
1099 * and then again to create the actual END_OBJ instance.
1100 *
1101 * When this function is called the second time, it will initialize
1102 * the END object, perform MIB2 setup, allocate a buffer pool, and
1103 * initialize the supported END capabilities. The only special
1104 * capability we support is VLAN_MTU, since we can receive slightly
1105 * larger than normal frames.
1106 *
1107 * RETURNS: An END object pointer, or NULL on error, or 0 and the name
1108 * of the device if the <loadStr> was empty.
1109 *
1110 * ERRNO: N/A
1111 */
1112 
1113 LOCAL END_OBJ *anEndLoad
1114     (
1115     char * loadStr,
1116     void * pArg
1117     )
1118     {
1119     AN_DRV_CTRL *pDrvCtrl;
1120     VXB_DEVICE_ID pDev;
1121 
1122     /* Make the MUX happy. */
1123 
1124     if (loadStr == NULL)
1125         return NULL;
1126 
1127     if (loadStr[0] == 0)
1128         {
1129         bcopy (AN_NAME, loadStr, sizeof(AN_NAME));
1130         return NULL;
1131         }
1132 
1133     pDev = pArg;
1134     pDrvCtrl = pDev->pDrvCtrl;
1135 
1136     if (END_OBJ_INIT (&pDrvCtrl->anEndObj, NULL, pDev->pName,
1137         pDev->unitNumber, &anNetFuncs,
1138         "Infineon AN983 VxBus END Driver") == ERROR)
1139         {
1140         logMsg("%s%d: END_OBJ_INIT failed\n", (int)AN_NAME,
1141             pDev->unitNumber, 0, 0, 0, 0);
1142         return (NULL);
1143         }
1144 
1145     endM2Init (&pDrvCtrl->anEndObj, M2_ifType_ethernet_csmacd,
1146         pDrvCtrl->anAddr, ETHER_ADDR_LEN, ETHERMTU, 100000000,
1147         IFF_NOTRAILERS | IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST);
1148 
1149     /* Allocate a buffer pool */
1150 
1151     if (endPoolCreate (256, &pDrvCtrl->anEndObj.pNetPool) == ERROR)
1152         {
1153         logMsg("%s%d: pool creation failed\n", (int)AN_NAME,
1154             pDev->unitNumber, 0, 0, 0, 0);
1155         return (NULL);
1156         }
1157 
1158     pDrvCtrl->anPollBuf = netTupleGet(pDrvCtrl->anEndObj.pNetPool,
1159         AN_CLSIZE, M_DONTWAIT, MT_DATA, 0);
1160 
1161     /* Set up capabilities. */
1162 
1163     pDrvCtrl->anCaps.cap_available = IFCAP_VLAN_MTU;
1164     pDrvCtrl->anCaps.cap_enabled = IFCAP_VLAN_MTU;
1165 
1166     return (&pDrvCtrl->anEndObj);
1167     }

 

posted @ 2015-04-07 10:55  zsdaka  阅读(3252)  评论(0编辑  收藏  举报