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

📄 if_cs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		/* "write this to I/O Command port register as 16 bit writes */		if (count)			if_cs_write16_rep(card, IF_CS_H_CMD,				&fw->data[sent],				count >> 1);		/* "Assert the download over interrupt command in the Host		 * status register" */		if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);		/* "Assert the download over interrupt command in the Card		 * interrupt case register" */		if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);		/* "The host polls the Card Status register ... for 50 ms before		   declaring a failure */		ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,			IF_CS_C_S_CMD_DNLD_RDY);		if (ret < 0) {			lbs_pr_err("can't download helper at 0x%x, ret %d\n",				sent, ret);			goto done;		}		if (count == 0)			break;		sent += count;	}	release_firmware(fw);	ret = 0;done:	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);	return ret;}static int if_cs_prog_real(struct if_cs_card *card){	const struct firmware *fw;	int ret = 0;	int retry = 0;	int len = 0;	int sent;	lbs_deb_enter(LBS_DEB_CS);	/* TODO: make firmware file configurable */	ret = request_firmware(&fw, "libertas_cs.fw",		&handle_to_dev(card->p_dev));	if (ret) {		lbs_pr_err("can't load firmware\n");		ret = -ENODEV;		goto done;	}	lbs_deb_cs("fw size %td\n", fw->size);	ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);	if (ret < 0) {		int i;		lbs_pr_err("helper firmware doesn't answer\n");		for (i = 0; i < 0x50; i += 2)			printk(KERN_INFO "## HS %02x: %04x\n",				i, if_cs_read16(card, i));		goto err_release;	}	for (sent = 0; sent < fw->size; sent += len) {		len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);		/* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",			__LINE__, sent, fw->size); */		if (len & 1) {			retry++;			lbs_pr_info("odd, need to retry this firmware block\n");		} else {			retry = 0;		}		if (retry > 20) {			lbs_pr_err("could not download firmware\n");			ret = -ENODEV;			goto err_release;		}		if (retry) {			sent -= len;		}		if_cs_write16(card, IF_CS_H_CMD_LEN, len);		if_cs_write16_rep(card, IF_CS_H_CMD,			&fw->data[sent],			(len+1) >> 1);		if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);		if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);		ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,			IF_CS_C_S_CMD_DNLD_RDY);		if (ret < 0) {			lbs_pr_err("can't download firmware at 0x%x\n", sent);			goto err_release;		}	}	ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);	if (ret < 0) {		lbs_pr_err("firmware download failed\n");		goto err_release;	}	ret = 0;	goto done;err_release:	release_firmware(fw);done:	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);	return ret;}/********************************************************************//* Callback functions for libertas.ko                               *//********************************************************************//* Send commands or data packets to the card */static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb){	int ret = -1;	lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);	switch (type) {	case MVMS_DAT:		priv->dnld_sent = DNLD_DATA_SENT;		if_cs_send_data(priv, buf, nb);		ret = 0;		break;	case MVMS_CMD:		priv->dnld_sent = DNLD_CMD_SENT;		ret = if_cs_send_cmd(priv, buf, nb);		break;	default:		lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type);	}	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);	return ret;}static int if_cs_get_int_status(wlan_private *priv, u8 *ireg){	struct if_cs_card *card = (struct if_cs_card *)priv->card;	//wlan_adapter *adapter = priv->adapter;	int ret = 0;	u16 int_cause;	u8 *cmdbuf;	*ireg = 0;	lbs_deb_enter(LBS_DEB_CS);	if (priv->adapter->surpriseremoved)		goto out;	int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;	if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);	*ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;	if (!*ireg)		goto sbi_get_int_status_exit;sbi_get_int_status_exit:	/* is there a data packet for us? */	if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {		struct sk_buff *skb = if_cs_receive_data(priv);		libertas_process_rxed_packet(priv, skb);		*ireg &= ~IF_CS_C_S_RX_UPLD_RDY;	}	if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {		priv->dnld_sent = DNLD_RES_RECEIVED;	}	/* Card has a command result for us */	if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {		spin_lock(&priv->adapter->driver_lock);		if (!priv->adapter->cur_cmd) {			cmdbuf = priv->upld_buf;			priv->adapter->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY;		} else {			cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;		}		ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len);		spin_unlock(&priv->adapter->driver_lock);		if (ret < 0)			lbs_pr_err("could not receive cmd from card\n");	}out:	lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->adapter->hisregcpy);	return ret;}static int if_cs_read_event_cause(wlan_private *priv){	lbs_deb_enter(LBS_DEB_CS);	priv->adapter->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;	if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);	return 0;}/********************************************************************//* Card Services                                                    *//********************************************************************//* * After a card is removed, if_cs_release() will unregister the * device, and release the PCMCIA configuration.  If the device is * still open, this will be postponed until it is closed. */static void if_cs_release(struct pcmcia_device *p_dev){	struct if_cs_card *card = p_dev->priv;	lbs_deb_enter(LBS_DEB_CS);	pcmcia_disable_device(p_dev);	free_irq(p_dev->irq.AssignedIRQ, card);	if (card->iobase)		ioport_unmap(card->iobase);	lbs_deb_leave(LBS_DEB_CS);}/* * This creates an "instance" of the driver, allocating local data * structures for one device.  The device is registered with Card * Services. * * The dev_link structure is initialized, but we don't actually * configure the card at this point -- we wait until we receive a card * insertion event. */static int if_cs_probe(struct pcmcia_device *p_dev){	int ret = -ENOMEM;	wlan_private *priv;	struct if_cs_card *card;	/* CIS parsing */	tuple_t tuple;	cisparse_t parse;	cistpl_cftable_entry_t *cfg = &parse.cftable_entry;	cistpl_io_t *io = &cfg->io;	u_char buf[64];	lbs_deb_enter(LBS_DEB_CS);	card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);	if (!card) {		lbs_pr_err("error in kzalloc\n");		goto out;	}	card->p_dev = p_dev;	p_dev->priv = card;	p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;	p_dev->irq.Handler = NULL;	p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;	p_dev->conf.Attributes = 0;	p_dev->conf.IntType = INT_MEMORY_AND_IO;	tuple.Attributes = 0;	tuple.TupleData = buf;	tuple.TupleDataMax = sizeof(buf);	tuple.TupleOffset = 0;	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;	if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||	    (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||	    (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0)	{		lbs_pr_err("error in pcmcia_get_first_tuple etc\n");		goto out1;	}	p_dev->conf.ConfigIndex = cfg->index;	/* Do we need to allocate an interrupt? */	if (cfg->irq.IRQInfo1) {		p_dev->conf.Attributes |= CONF_ENABLE_IRQ;	}	/* IO window settings */	if (cfg->io.nwin != 1) {		lbs_pr_err("wrong CIS (check number of IO windows)\n");		ret = -ENODEV;		goto out1;	}	p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;	p_dev->io.BasePort1 = io->win[0].base;	p_dev->io.NumPorts1 = io->win[0].len;	/* This reserves IO space but doesn't actually enable it */	ret = pcmcia_request_io(p_dev, &p_dev->io);	if (ret) {		lbs_pr_err("error in pcmcia_request_io\n");		goto out1;	}	/*	 * Allocate an interrupt line.  Note that this does not assign	 * a handler to the interrupt, unless the 'Handler' member of	 * the irq structure is initialized.	 */	if (p_dev->conf.Attributes & CONF_ENABLE_IRQ) {		ret = pcmcia_request_irq(p_dev, &p_dev->irq);		if (ret) {			lbs_pr_err("error in pcmcia_request_irq\n");			goto out1;		}	}	/* Initialize io access */	card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1);	if (!card->iobase) {		lbs_pr_err("error in ioport_map\n");		ret = -EIO;		goto out1;	}	/*	 * This actually configures the PCMCIA socket -- setting up	 * the I/O windows and the interrupt mapping, and putting the	 * card and host interface into "Memory and IO" mode.	 */	ret = pcmcia_request_configuration(p_dev, &p_dev->conf);	if (ret) {		lbs_pr_err("error in pcmcia_request_configuration\n");		goto out2;	}	/* Finally, report what we've done */	lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n",	       p_dev->irq.AssignedIRQ, p_dev->io.BasePort1,	       p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);	/* Load the firmware early, before calling into libertas.ko */	ret = if_cs_prog_helper(card);	if (ret == 0)		ret = if_cs_prog_real(card);	if (ret)		goto out2;	/* Make this card known to the libertas driver */	priv = libertas_add_card(card, &p_dev->dev);	if (!priv) {		ret = -ENOMEM;		goto out2;	}	/* Store pointers to our call-back functions */	card->priv = priv;	priv->card = card;	priv->hw_host_to_card     = if_cs_host_to_card;	priv->hw_get_int_status   = if_cs_get_int_status;	priv->hw_read_event_cause = if_cs_read_event_cause;	priv->adapter->fw_ready = 1;	/* Now actually get the IRQ */	ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt,		IRQF_SHARED, DRV_NAME, card);	if (ret) {		lbs_pr_err("error in request_irq\n");		goto out3;	}	/* Clear any interrupt cause that happend while sending	 * firmware/initializing card */	if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK);	if_cs_enable_ints(card);	/* And finally bring the card up */	if (libertas_start_card(priv) != 0) {		lbs_pr_err("could not activate card\n");		goto out3;	}	ret = 0;	goto out;out3:	libertas_remove_card(priv);out2:	ioport_unmap(card->iobase);out1:	pcmcia_disable_device(p_dev);out:	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);	return ret;}/* * This deletes a driver "instance".  The device is de-registered with * Card Services.  If it has been released, all local data structures * are freed.  Otherwise, the structures will be freed when the device * is released. */static void if_cs_detach(struct pcmcia_device *p_dev){	struct if_cs_card *card = p_dev->priv;	lbs_deb_enter(LBS_DEB_CS);	libertas_stop_card(card->priv);	libertas_remove_card(card->priv);	if_cs_disable_ints(card);	if_cs_release(p_dev);	kfree(card);	lbs_deb_leave(LBS_DEB_CS);}/********************************************************************//* Module initialization                                            *//********************************************************************/static struct pcmcia_device_id if_cs_ids[] = {	PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103),	PCMCIA_DEVICE_NULL,};MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);static struct pcmcia_driver libertas_driver = {	.owner		= THIS_MODULE,	.drv		= {		.name	= DRV_NAME,	},	.probe		= if_cs_probe,	.remove		= if_cs_detach,	.id_table       = if_cs_ids,};static int __init if_cs_init(void){	int ret;	lbs_deb_enter(LBS_DEB_CS);	ret = pcmcia_register_driver(&libertas_driver);	lbs_deb_leave(LBS_DEB_CS);	return ret;}static void __exit if_cs_exit(void){	lbs_deb_enter(LBS_DEB_CS);	pcmcia_unregister_driver(&libertas_driver);	lbs_deb_leave(LBS_DEB_CS);}module_init(if_cs_init);module_exit(if_cs_exit);

⌨️ 快捷键说明

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