BCM wifi分析

一:加载wifi驱动模块

    在hardware/libhardware_legacy/wifi/wifi.c调用函数

    insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG)

    其中

     DRIVER_MODULE_PATH = /system/lib/dhd.ko

      DRIVER_MODULE_ARG  = "firmware_path=/etc/wifi/40181/fw_bcm40181a2.bin nvram_path=/etc/wifi/40181/nvram.txt"

二:wifi驱动模块运行

     wifi驱动入口dhd_module_init(void) ... dhd_linux.c

dhd_module_init(void)
{
	int error = 0;

	DHD_TRACE(("%s: Enter\n", __FUNCTION__));

	wl_android_init(); //初始化dhd_msg_level |= DHD_ERROR_VAL,给iface_name赋值为wlan

	do {
		sema_init(&dhd_chipup_sem, 0);
		dhd_bus_reg_sdio_notify(&dhd_chipup_sem);//注册sdio driver,支持如下图wifi列表,sdio驱动获取wifi列表的设备后调用dummy_probe() --> up(dhd_chipup_sem)
                dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON);
                
		if (down_timeout(&dhd_chipup_sem, //2000ms超时等待
			msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) {
			dhd_bus_unreg_sdio_notify();
			chip_up = 1;
			break;
		}
		DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
			retry+1));
		dhd_bus_unreg_sdio_notify();
		dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
	} while (retry-- > 0);

	if (!chip_up) {
		DHD_ERROR(("\nfailed to power up wifi chip, max retry reached, exits **\n\n"));
		return -ENODEV;
	}

	sema_init(&dhd_registration_sem, 0);

	error = dhd_bus_register();//详细分析看<三>,注册dhd_sdio驱动,最终会调用到dhd_net_attach();

	if (!error)
		printf("\n%s\n", dhd_version);
	else {
		DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__));
		goto fail_1;
	}

	/*
	 * Wait till MMC sdio_register_driver callback called and made driver attach.
	 * It's needed to make sync up exit from dhd insmod  and
	 * Kernel MMC sdio device callback registration
	 */
	if ((down_timeout(&dhd_registration_sem,//函数dhd_net_attach() --> up(&dhd_registration_sem);
		msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) ||
		(dhd_registration_check != TRUE)) {
		error = -ENODEV;
		DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__));
		goto fail_2;
	}

	wl_android_post_init();


	return error;

fail_2:
	dhd_bus_unregister();

fail_1:

	/* Call customer gpio to turn off power with WL_REG_ON signal */
	dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);

	return error;
}
BCM wifi分析_第1张图片

三:dhd_bus_register(void) ... dhd_sdio.c分析

BCM wifi分析_第2张图片

bcmsdh_register(&dhd_sdio)会调用pci_register_driver(&bcmsdh_pci_driver)注册一个pci类型的驱动,如果匹配到bcmsdh_pci_devid就会调用到bcmsdh_pci_probe --> drvinfo.attach --> drvinfo.attach ,最终调用到dhd_sdio->dhdsdio_probe,接下来分析dhdsdio_probe函数

四:dhdsdio_probe() ... dhd_sdio.c分析

dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
	uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
{
	int ret;
	dhd_bus_t *bus;


	/* attach the common module */
	dhd_common_init(osh);

	/* attempt to attach to the dongle */
	if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
		DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
		goto fail;
	}

	/* Attach to the dhd/OS/network interface */ //创建3个线程,分别是dhd_watchdog_thread、dhd_dpc、dhd_sysioc
	if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
		DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
		goto fail;
	}

	/* Allocate buffers */
	if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
		DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
		goto fail;
	}

	if (!(dhdsdio_probe_init(bus, osh, sdh))) {
		DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
		goto fail;
	}

	if (bus->intr) {
		/* Register interrupt callback, but mask it (not operational yet). */
		DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
		bcmsdh_intr_disable(sdh);
		if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
			DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
			           __FUNCTION__, ret));
			goto fail;
		}
		DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
	} else {
		DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
		           __FUNCTION__));
	}

	DHD_INFO(("%s: completed!!\n", __FUNCTION__));
        //获取wifi MAC地址
	ret = dhd_custom_get_mac_address(ea_addr.octet);


	/* if firmware path present try to download and bring up bus */
	if (dhd_download_fw_on_driverload) {  //更新模组firmware、nvram,其中使用了filp_open、kernel_read、filp_close进行文件系统的操作
		if ((ret = dhd_bus_start(bus->dhd)) != 0) {
			DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
			goto fail;
		}
	}
	/* Ok, have the per-port tell the stack we're open for business */
	if (dhd_net_attach(bus->dhd, 0) != 0) {
		DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
		goto fail;
	}


	return bus;

fail:
	dhdsdio_release(bus, osh);

	return NULL;
}





你可能感兴趣的:(linux)