/*
 * 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 dev_link_t *
orinoco_cs_attach(void)
{
	struct net_device *dev;
	struct orinoco_private *priv;
	struct orinoco_pccard *card;
	dev_link_t *link;
	client_reg_t client_reg;
	int ret;

	dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset);
	if (! dev)
		return NULL;
	priv = netdev_priv(dev);
	card = priv->card;

	/* Link both structures together */
	link = &card->link;
	link->priv = dev;

	/* Interrupt setup */
	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
	link->irq.Handler = orinoco_interrupt;
	link->irq.Instance = dev; 

	/* General socket configuration defaults can go here.  In this
	 * client, we assume very little, and rely on the CIS for
	 * almost everything.  In most clients, many details (i.e.,
	 * number, sizes, and attributes of IO windows) are fixed by
	 * the nature of the device, and can be hard-wired here. */
	link->conf.Attributes = 0;
	link->conf.IntType = INT_MEMORY_AND_IO;

	/* Register with Card Services */
	/* FIXME: need a lock? */
	link->next = dev_list;
	dev_list = link;

	client_reg.dev_info = &dev_info;
	client_reg.EventMask =
		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
	client_reg.event_handler = &orinoco_cs_event;
	client_reg.Version = 0x0210; /* FIXME: what does this mean? */
	client_reg.event_callback_args.client_data = link;

	ret = pcmcia_register_client(&link->handle, &client_reg);
	if (ret != CS_SUCCESS) {
		cs_error(link->handle, RegisterClient, ret);
		orinoco_cs_detach(link);
		return NULL;
	}

	return link;
}				/* orinoco_cs_attach */
Exemple #2
0
/* Remove zombie instances (card removed, detach pending) */
static void
flush_stale_links(void)
{
	dev_link_t *link, *next;
	TRACE_ENTER("orinoco");
	for (link = dev_list; link; link = next) {
		next = link->next;
		if (link->state & DEV_STALE_LINK)
			orinoco_cs_detach(link);
	}
	TRACE_EXIT("orinoco");
}
Exemple #3
0
static void __exit
exit_orinoco_cs(void)
{
	TRACE_ENTER("orinoco");

	unregister_pccard_driver(&dev_info);

	if (dev_list)
		DEBUG(0, "orinoco_cs: Removing leftover devices.\n");
	while (dev_list != NULL) {
		del_timer(&dev_list->release);
		if (dev_list->state & DEV_CONFIG)
			orinoco_cs_release((u_long) dev_list);
		orinoco_cs_detach(dev_list);
	}

	TRACE_EXIT("orinoco");
}
Exemple #4
0
static dev_link_t *
orinoco_cs_attach(void)
{
	struct orinoco_pccard *card;
	struct orinoco_private *priv;
	dev_link_t *link;
	struct net_device *ndev;
	client_reg_t client_reg;
	int ret, i;

	TRACE_ENTER("orinoco");
	/* A bit of cleanup */
	flush_stale_links();

	/* Allocate space for private device-specific data */
	card = kmalloc(sizeof(*card), GFP_KERNEL);
	if (! card) {
		link = NULL;
		goto out;
	}
	memset(card, 0, sizeof(*card));

	/* Link both structure together */
	priv = &(card->priv);
	priv->card = card;
	link = &card->link;
	ndev = &priv->ndev;
	link->priv = priv;

	/* Initialize the dev_link_t structure */
	link->release.function = &orinoco_cs_release;
	link->release.data = (u_long) link;

	/* Interrupt setup */
	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
	if (irq_list[0] == -1)
		link->irq.IRQInfo2 = irq_mask;
	else
		for (i = 0; i < 4; i++)
			link->irq.IRQInfo2 |= 1 << irq_list[i];
	link->irq.Handler = NULL;

	/*
	   General socket configuration defaults can go here.  In this
	   client, we assume very little, and rely on the CIS for almost
	   everything.  In most clients, many details (i.e., number, sizes,
	   and attributes of IO windows) are fixed by the nature of the
	   device, and can be hard-wired here.
	 */
	link->conf.Attributes = 0;
	link->conf.IntType = INT_MEMORY_AND_IO;

	/* Setup the common part */
	if(orinoco_setup(priv) < 0) {
		kfree(card);
		return NULL;
	}

	/* Overrides */
	ndev->open = orinoco_cs_open;
	ndev->stop = orinoco_cs_stop;
	priv->card_reset_handler = orinoco_cs_cor_reset;

	/* Register with Card Services */
	link->next = dev_list;
	dev_list = link;
	client_reg.dev_info = &dev_info;
	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
	client_reg.EventMask =
	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
	client_reg.event_handler = &orinoco_cs_event;
	client_reg.Version = 0x0210;
	client_reg.event_callback_args.client_data = link;
	ret = CardServices(RegisterClient, &link->handle, &client_reg);
	if (ret != CS_SUCCESS) {
		cs_error(link->handle, RegisterClient, ret);
		orinoco_cs_detach(link);
		link = NULL;
		goto out;
	}

 out:
	TRACE_EXIT("orinoco");
	return link;
}				/* orinoco_cs_attach */