⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_sdio.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	sdio_claim_host(card->func);	ret = sdio_set_block_size(card->func, 32);	if (ret)		goto release;	firmware = fw->data;	size = fw->size;	while (size) {		timeout = jiffies + HZ;		while (1) {			status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);			if (ret)				goto release;			if ((status & IF_SDIO_IO_RDY) &&					(status & IF_SDIO_DL_RDY))				break;			if (time_after(jiffies, timeout)) {				ret = -ETIMEDOUT;				goto release;			}			mdelay(1);		}		req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);		if (ret)			goto release;		req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;		if (ret)			goto release;/*		lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);*/		if (req_size == 0) {			lbs_deb_sdio("firmware helper gave up early\n");			ret = -EIO;			goto release;		}		if (req_size & 0x01) {			lbs_deb_sdio("firmware helper signalled error\n");			ret = -EIO;			goto release;		}		if (req_size > size)			req_size = size;		while (req_size) {			chunk_size = min(req_size, (size_t)512);			memcpy(chunk_buffer, firmware, chunk_size);/*			lbs_deb_sdio("sending %d bytes (%d bytes) chunk\n",				chunk_size, (chunk_size + 31) / 32 * 32);*/			ret = sdio_writesb(card->func, card->ioport,				chunk_buffer, (chunk_size + 31) / 32 * 32);			if (ret)				goto release;			firmware += chunk_size;			size -= chunk_size;			req_size -= chunk_size;		}	}	ret = 0;	lbs_deb_sdio("waiting for firmware to boot...\n");	/* wait for the firmware to boot */	timeout = jiffies + HZ;	while (1) {		u16 scratch;		scratch = if_sdio_read_scratch(card, &ret);		if (ret)			goto release;		if (scratch == IF_SDIO_FIRMWARE_OK)			break;		if (time_after(jiffies, timeout)) {			ret = -ETIMEDOUT;			goto release;		}		msleep(10);	}	ret = 0;release:	sdio_set_block_size(card->func, 0);	sdio_release_host(card->func);	kfree(chunk_buffer);release_fw:	release_firmware(fw);out:	if (ret)		lbs_pr_err("failed to load firmware\n");	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);	return ret;}static int if_sdio_prog_firmware(struct if_sdio_card *card){	int ret;	u16 scratch;	lbs_deb_enter(LBS_DEB_SDIO);	sdio_claim_host(card->func);	scratch = if_sdio_read_scratch(card, &ret);	sdio_release_host(card->func);	if (ret)		goto out;	if (scratch == IF_SDIO_FIRMWARE_OK) {		lbs_deb_sdio("firmware already loaded\n");		goto success;	}	ret = if_sdio_prog_helper(card);	if (ret)		goto out;	ret = if_sdio_prog_real(card);	if (ret)		goto out;success:	ret = 0;out:	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);	return ret;}/*******************************************************************//* Libertas callbacks                                              *//*******************************************************************/static int if_sdio_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb){	int ret;	struct if_sdio_card *card;	struct if_sdio_packet *packet, *cur;	u16 size;	unsigned long flags;	lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb);	card = priv->card;	if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {		ret = -EINVAL;		goto out;	}	/*	 * The transfer must be in one transaction or the firmware	 * goes suicidal.	 */	size = nb + 4;	if ((size > card->func->cur_blksize) || (size > 512)) {		size = (size + card->func->cur_blksize - 1) /			card->func->cur_blksize * card->func->cur_blksize;	}	packet = kzalloc(sizeof(struct if_sdio_packet) + size,			GFP_ATOMIC);	if (!packet) {		ret = -ENOMEM;		goto out;	}	packet->next = NULL;	packet->nb = size;	/*	 * SDIO specific header.	 */	packet->buffer[0] = (nb + 4) & 0xff;	packet->buffer[1] = ((nb + 4) >> 8) & 0xff;	packet->buffer[2] = type;	packet->buffer[3] = 0;	memcpy(packet->buffer + 4, buf, nb);	spin_lock_irqsave(&card->lock, flags);	if (!card->packets)		card->packets = packet;	else {		cur = card->packets;		while (cur->next)			cur = cur->next;		cur->next = packet;	}	switch (type) {	case MVMS_CMD:		priv->dnld_sent = DNLD_CMD_SENT;		break;	case MVMS_DAT:		priv->dnld_sent = DNLD_DATA_SENT;		break;	default:		lbs_deb_sdio("unknown packet type %d\n", (int)type);	}	spin_unlock_irqrestore(&card->lock, flags);	schedule_work(&card->packet_worker);	ret = 0;out:	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);	return ret;}static int if_sdio_get_int_status(wlan_private *priv, u8 *ireg){	struct if_sdio_card *card;	lbs_deb_enter(LBS_DEB_SDIO);	card = priv->card;	*ireg = card->int_cause;	card->int_cause = 0;	lbs_deb_leave(LBS_DEB_SDIO);	return 0;}static int if_sdio_read_event_cause(wlan_private *priv){	struct if_sdio_card *card;	lbs_deb_enter(LBS_DEB_SDIO);	card = priv->card;	priv->adapter->eventcause = card->event;	lbs_deb_leave(LBS_DEB_SDIO);	return 0;}/*******************************************************************//* SDIO callbacks                                                  *//*******************************************************************/static void if_sdio_interrupt(struct sdio_func *func){	int ret;	struct if_sdio_card *card;	u8 cause;	lbs_deb_enter(LBS_DEB_SDIO);	card = sdio_get_drvdata(func);	cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);	if (ret)		goto out;	lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);	sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);	if (ret)		goto out;	/*	 * Ignore the define name, this really means the card has	 * successfully received the command.	 */	if (cause & IF_SDIO_H_INT_DNLD) {		if ((card->priv->dnld_sent == DNLD_DATA_SENT) &&			(card->priv->adapter->connect_status == LIBERTAS_CONNECTED))			netif_wake_queue(card->priv->dev);		card->priv->dnld_sent = DNLD_RES_RECEIVED;	}	if (cause & IF_SDIO_H_INT_UPLD) {		ret = if_sdio_card_to_host(card);		if (ret)			goto out;	}	ret = 0;out:	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);}static int if_sdio_probe(struct sdio_func *func,		const struct sdio_device_id *id){	struct if_sdio_card *card;	wlan_private *priv;	int ret, i;	unsigned int model;	struct if_sdio_packet *packet;	lbs_deb_enter(LBS_DEB_SDIO);	for (i = 0;i < func->card->num_info;i++) {		if (sscanf(func->card->info[i],				"802.11 SDIO ID: %x", &model) == 1)			break;		if (sscanf(func->card->info[i],				"ID: %x", &model) == 1)			break;               if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {                       model = 4;                       break;               }	}	if (i == func->card->num_info) {		lbs_pr_err("unable to identify card model\n");		return -ENODEV;	}	card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);	if (!card)		return -ENOMEM;	card->func = func;	card->model = model;	spin_lock_init(&card->lock);	INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);	for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {		if (card->model == if_sdio_models[i].model)			break;	}	if (i == ARRAY_SIZE(if_sdio_models)) {		lbs_pr_err("unkown card model 0x%x\n", card->model);		ret = -ENODEV;		goto free;	}	card->helper = if_sdio_models[i].helper;	card->firmware = if_sdio_models[i].firmware;	if (libertas_helper_name) {		lbs_deb_sdio("overriding helper firmware: %s\n",			libertas_helper_name);		card->helper = libertas_helper_name;	}	if (libertas_fw_name) {		lbs_deb_sdio("overriding firmware: %s\n", libertas_fw_name);		card->firmware = libertas_fw_name;	}	sdio_claim_host(func);	ret = sdio_enable_func(func);	if (ret)		goto release;	ret = sdio_claim_irq(func, if_sdio_interrupt);	if (ret)		goto disable;	card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);	if (ret)		goto release_int;	card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;	if (ret)		goto release_int;	card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;	if (ret)		goto release_int;	sdio_release_host(func);	sdio_set_drvdata(func, card);	lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "			"device = 0x%X, model = 0x%X, ioport = 0x%X\n",			func->class, func->vendor, func->device,			model, (unsigned)card->ioport);	ret = if_sdio_prog_firmware(card);	if (ret)		goto reclaim;	priv = libertas_add_card(card, &func->dev);	if (!priv) {		ret = -ENOMEM;		goto reclaim;	}	card->priv = priv;	priv->card = card;	priv->hw_host_to_card = if_sdio_host_to_card;	priv->hw_get_int_status = if_sdio_get_int_status;	priv->hw_read_event_cause = if_sdio_read_event_cause;	priv->adapter->fw_ready = 1;	/*	 * Enable interrupts now that everything is set up	 */	sdio_claim_host(func);	sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);	sdio_release_host(func);	if (ret)		goto reclaim;	ret = libertas_start_card(priv);	if (ret)		goto err_activate_card;out:	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);	return ret;err_activate_card:	flush_scheduled_work();	free_netdev(priv->dev);	kfree(priv->adapter);reclaim:	sdio_claim_host(func);release_int:	sdio_release_irq(func);disable:	sdio_disable_func(func);release:	sdio_release_host(func);free:	while (card->packets) {		packet = card->packets;		card->packets = card->packets->next;		kfree(packet);	}	kfree(card);	goto out;}static void if_sdio_remove(struct sdio_func *func){	struct if_sdio_card *card;	struct if_sdio_packet *packet;	lbs_deb_enter(LBS_DEB_SDIO);	card = sdio_get_drvdata(func);	card->priv->adapter->surpriseremoved = 1;	lbs_deb_sdio("call remove card\n");	libertas_stop_card(card->priv);	libertas_remove_card(card->priv);	flush_scheduled_work();	sdio_claim_host(func);	sdio_release_irq(func);	sdio_disable_func(func);	sdio_release_host(func);	while (card->packets) {		packet = card->packets;		card->packets = card->packets->next;		kfree(packet);	}	kfree(card);	lbs_deb_leave(LBS_DEB_SDIO);}static struct sdio_driver if_sdio_driver = {	.name		= "libertas_sdio",	.id_table	= if_sdio_ids,	.probe		= if_sdio_probe,	.remove		= if_sdio_remove,};/*******************************************************************//* Module functions                                                *//*******************************************************************/static int if_sdio_init_module(void){	int ret = 0;	lbs_deb_enter(LBS_DEB_SDIO);	printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");	printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");	ret = sdio_register_driver(&if_sdio_driver);	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);	return ret;}static void if_sdio_exit_module(void){	lbs_deb_enter(LBS_DEB_SDIO);	sdio_unregister_driver(&if_sdio_driver);	lbs_deb_leave(LBS_DEB_SDIO);}module_init(if_sdio_init_module);module_exit(if_sdio_exit_module);MODULE_DESCRIPTION("Libertas SDIO WLAN Driver");MODULE_AUTHOR("Pierre Ossman");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -