/*----------------------------------------------------------------
* prism2mgmt_flashdl_state
*
* Establishes the beginning/end of a card Flash download session.
*
* It is expected that the flashdl_write() function will be called
* one or more times between the 'enable' and 'disable' calls to
* this function.
*
* Note: This function should not be called when a mac comm port
*       is active.
*
* Arguments:
*	wlandev		wlan device structure
*	msgp		ptr to msg buffer
*
* Returns:
*	0	success and done
*	<0	success, but we're waiting for something to finish.
*	>0	an error occurred while handling the message.
* Side effects:
*
* Call context:
*	process thread  (usually)
----------------------------------------------------------------*/
int prism2mgmt_flashdl_state(wlandevice_t *wlandev, void *msgp)
{
    int			result = 0;
    hfa384x_t		*hw = wlandev->priv;
    p80211msg_p2req_flashdl_state_t	*msg = msgp;
    DBFENTER;

    if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
        WLAN_LOG_ERROR(
            "flashdl_state(): may only be called "
            "in the fwload state.\n");
        msg->resultcode.data =
            P80211ENUM_resultcode_implementation_failure;
        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
        DBFEXIT;
        return 0;
    }

    /*
    ** Note: Interrupts are locked out if this is an AP and are NOT
    ** locked out if this is a station.
    */

    msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
    if  ( msg->enable.data == P80211ENUM_truth_true ) {
        if ( hfa384x_drvr_flashdl_enable(hw) ) {
            msg->resultcode.data = P80211ENUM_resultcode_implementation_failure;
        } else {
            msg->resultcode.data = P80211ENUM_resultcode_success;
        }
    } else {
        hfa384x_drvr_flashdl_disable(hw);
        msg->resultcode.data = P80211ENUM_resultcode_success;
        /* NOTE: At this point, the MAC is in the post-reset
         * state and the driver is in the fwload state.
         * We need to get the MAC back into the fwload
         * state.  To do this, we set the nsdstate to HWPRESENT
         * and then call the ifstate function to redo everything
         * that got us into the fwload state.
         */
        wlandev->msdstate = WLAN_MSD_HWPRESENT;
        result = prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
        if (result != P80211ENUM_resultcode_success) {
            WLAN_LOG_ERROR("prism2sta_ifstate(fwload) failed,"
                           "P80211ENUM_resultcode=%d\n", result);
            msg->resultcode.data =
                P80211ENUM_resultcode_implementation_failure;
            result = -1;
        }
    }

    DBFEXIT;
    return 0;
}
/*----------------------------------------------------------------
* wlan_setup
*
* Roughly matches the functionality of ether_setup.  Here
* we set up any members of the wlandevice structure that are common
* to all devices.  Additionally, we allocate a linux 'struct device'
* and perform the same setup as ether_setup.
*
* Note: It's important that the caller have setup the wlandev->name
*	ptr prior to calling this function.
*
* Arguments:
*	wlandev		ptr to the wlandev structure for the
*			interface.
* Returns:
*	zero on success, non-zero otherwise.
* Call Context:
*	Should be process thread.  We'll assume it might be
*	interrupt though.  When we add support for statically
*	compiled drivers, this function will be called in the
*	context of the kernel startup code.
----------------------------------------------------------------*/
int wlan_setup(wlandevice_t *wlandev)
{
	int		result = 0;
	netdevice_t	*dev;

	DBFENTER;

	/* Set up the wlandev */
	wlandev->state = WLAN_DEVICE_CLOSED;
	wlandev->ethconv = WLAN_ETHCONV_8021h;
	wlandev->macmode = WLAN_MACMODE_NONE;

	/* Set up the rx queue */
	skb_queue_head_init(&wlandev->nsd_rxq);
	tasklet_init(&wlandev->rx_bh,
		     p80211netdev_rx_bh,
		     (unsigned long)wlandev);

	/* Allocate and initialize the struct device */
	dev = alloc_netdev(0,"wlan%d",ether_setup);
	if ( dev == NULL ) {
		WLAN_LOG_ERROR("Failed to alloc netdev.\n");
		result = 1;
	} else {
		wlandev->netdev = dev;
		dev->ml_priv = wlandev;
		dev->hard_start_xmit =	p80211knetdev_hard_start_xmit;
		dev->get_stats =	p80211knetdev_get_stats;
#ifdef HAVE_PRIVATE_IOCTL
		dev->do_ioctl = 	p80211knetdev_do_ioctl;
#endif
#ifdef HAVE_MULTICAST
		dev->set_multicast_list = p80211knetdev_set_multicast_list;
#endif
		dev->init =		p80211knetdev_init;
		dev->open =		p80211knetdev_open;
		dev->stop =		p80211knetdev_stop;

#if (WIRELESS_EXT < 21)
		dev->get_wireless_stats = p80211wext_get_wireless_stats;
#endif
		dev->wireless_handlers = &p80211wext_handler_def;

		netif_stop_queue(dev);
#ifdef HAVE_CHANGE_MTU
		dev->change_mtu = wlan_change_mtu;
#endif
#ifdef HAVE_SET_MAC_ADDR
		dev->set_mac_address =	p80211knetdev_set_mac_address;
#endif
#ifdef HAVE_TX_TIMEOUT
		dev->tx_timeout      =  &p80211knetdev_tx_timeout;
		dev->watchdog_timeo  =  (wlan_watchdog * HZ) / 1000;
#endif
		netif_carrier_off(dev);
	}

	DBFEXIT;
	return result;
}
/*----------------------------------------------------------------
* prism2mgmt_readpda
*
* Collect the PDA data and put it in the message.
*
* Arguments:
*	wlandev		wlan device structure
*	msgp		ptr to msg buffer
*
* Returns:
*	0	success and done
*	<0	success, but we're waiting for something to finish.
*	>0	an error occurred while handling the message.
* Side effects:
*
* Call context:
*	process thread  (usually)
----------------------------------------------------------------*/
int prism2mgmt_readpda(wlandevice_t *wlandev, void *msgp)
{
    hfa384x_t		*hw = wlandev->priv;
    p80211msg_p2req_readpda_t	*msg = msgp;
    int				result;
    DBFENTER;

    /* We only support collecting the PDA when in the FWLOAD
     * state.
     */
    if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
        WLAN_LOG_ERROR(
            "PDA may only be read "
            "in the fwload state.\n");
        msg->resultcode.data =
            P80211ENUM_resultcode_implementation_failure;
        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
    } else {
        /*  Call drvr_readpda(), it handles the auxport enable
         *  and validating the returned PDA.
         */
        result = hfa384x_drvr_readpda(
                     hw,
                     msg->pda.data,
                     HFA384x_PDA_LEN_MAX);
        if (result) {
            WLAN_LOG_ERROR(
                "hfa384x_drvr_readpda() failed, "
                "result=%d\n",
                result);

            msg->resultcode.data =
                P80211ENUM_resultcode_implementation_failure;
            msg->resultcode.status =
                P80211ENUM_msgitem_status_data_ok;
            DBFEXIT;
            return 0;
        }
        msg->pda.status = P80211ENUM_msgitem_status_data_ok;
        msg->resultcode.data = P80211ENUM_resultcode_success;
        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
    }

    DBFEXIT;
    return 0;
}
/*----------------------------------------------------------------
* prism2mgmt_flashdl_write
*
*
*
* Arguments:
*	wlandev		wlan device structure
*	msgp		ptr to msg buffer
*
* Returns:
*	0	success and done
*	<0	success, but we're waiting for something to finish.
*	>0	an error occurred while handling the message.
* Side effects:
*
* Call context:
*	process thread  (usually)
----------------------------------------------------------------*/
int prism2mgmt_flashdl_write(wlandevice_t *wlandev, void *msgp)
{
    hfa384x_t		*hw = wlandev->priv;
    p80211msg_p2req_flashdl_write_t	*msg = msgp;
    u32			addr;
    u32			len;
    u8			*buf;
    DBFENTER;

    if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
        WLAN_LOG_ERROR(
            "flashdl_write(): may only be called "
            "in the fwload state.\n");
        msg->resultcode.data =
            P80211ENUM_resultcode_implementation_failure;
        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
        DBFEXIT;
        return 0;
    }

    /*
    ** Note: Interrupts are locked out if this is an AP and are NOT
    ** locked out if this is a station.
    */

    msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
    /* first validate the length */
    if  ( msg->len.data > sizeof(msg->data.data) ) {
        msg->resultcode.status =
            P80211ENUM_resultcode_invalid_parameters;
        return 0;
    }
    /* call the hfa384x function to do the write */
    addr = msg->addr.data;
    len = msg->len.data;
    buf = msg->data.data;
    if ( hfa384x_drvr_flashdl_write(hw, addr, buf, len) ) {
        msg->resultcode.data = P80211ENUM_resultcode_refused;

    }
    msg->resultcode.data = P80211ENUM_resultcode_success;

    DBFEXIT;
    return 0;
}
Esempio n. 5
0
/*----------------------------------------------------------------
* wlan_unsetup
*
* This function is paired with the wlan_setup routine.  It should
* be called after unregister_wlandev.  Basically, all it does is
* free the 'struct device' that's associated with the wlandev.
* We do it here because the 'struct device' isn't allocated
* explicitly in the driver code, it's done in wlan_setup.  To
* do the free in the driver might seem like 'magic'.
*
* Arguments:
*	wlandev		ptr to the wlandev structure for the
*			interface.
* Returns:
*	zero on success, non-zero otherwise.
* Call Context:
*	Should be process thread.  We'll assume it might be
*	interrupt though.  When we add support for statically
*	compiled drivers, this function will be called in the
*	context of the kernel startup code.
----------------------------------------------------------------*/
int wlan_unsetup(wlandevice_t *wlandev)
{
	int		result = 0;

	DBFENTER;

	tasklet_kill(&wlandev->rx_bh);

	if (wlandev->netdev == NULL ) {
		WLAN_LOG_ERROR("called without wlandev->netdev set.\n");
		result = 1;
	} else {
		free_netdev(wlandev->netdev);
		wlandev->netdev = NULL;
	}

	DBFEXIT;
	return 0;
}
Esempio n. 6
0
static int p80211wext_siwscan(netdevice_t *dev,
			     struct iw_request_info *info,
			     struct iw_point *srq, char *extra)
{
	wlandevice_t *wlandev = (wlandevice_t*)dev->priv;
	p80211msg_dot11req_scan_t	msg;	
	int result;
	int err = 0;
	int i = 0;

	DBFENTER;

	if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
		WLAN_LOG_ERROR("Can't scan in AP mode\n");
		err = (-EOPNOTSUPP);
		goto exit;
	}

	memset(&msg, 0x00, sizeof(p80211msg_dot11req_scan_t));
	msg.msgcode = DIDmsg_dot11req_scan;
	msg.bsstype.data = P80211ENUM_bsstype_any;

	memset(&(msg.bssid.data), 0xFF, sizeof (p80211item_pstr6_t));
	msg.bssid.data.len = 6;

	msg.scantype.data = P80211ENUM_scantype_active;
	msg.probedelay.data = 0;

	for (i = 0; i < 14; i++)
		msg.channellist.data.data[i] = i;
	msg.channellist.data.len = 14;

	msg.maxchanneltime.data = 250;
	msg.minchanneltime.data = 200;

	result = p80211req_dorequest(wlandev, (UINT8*)&msg);
	if (result)
		err = prism2_result2err (msg.resultcode.data);

 exit:
	DBFEXIT;
	return err;
}
Esempio n. 7
0
/*----------------------------------------------------------------
* p80211req_dorequest
*
* Handles an MLME reqest/confirm message.
* 
* Arguments:
*	wlandev		WLAN device struct
*	msgbuf		Buffer containing a request message
*
* Returns: 
*	0 on success, an errno otherwise
*	
* Call context:
*	Potentially blocks the caller, so it's a good idea to 
*	not call this function from an interrupt context.
----------------------------------------------------------------*/
int p80211req_dorequest( wlandevice_t *wlandev, UINT8 *msgbuf)
{
	int		result = 0;
	p80211msg_t	*msg = (p80211msg_t*)msgbuf;

	DBFENTER;

	/* Check to make sure the MSD is running */
	if ( 
	!((wlandev->msdstate == WLAN_MSD_HWPRESENT &&
	msg->msgcode == DIDmsg_lnxreq_ifstate) ||
	wlandev->msdstate == WLAN_MSD_RUNNING || 
	wlandev->msdstate == WLAN_MSD_FWLOAD) ) {
		return -ENODEV;
	}

	/* Check Permissions */
	if (!capable(CAP_NET_ADMIN) && 
	    (msg->msgcode != DIDmsg_dot11req_mibget)) {
		WLAN_LOG_ERROR("%s: only dot11req_mibget allowed for non-root.\n", wlandev->name);
		return -EPERM;
	}

	/* Check for busy status */
	if ( test_and_set_bit(1, &(wlandev->request_pending))) {
		return -EBUSY;
	}

	/* Allow p80211 to look at msg and handle if desired. */
	/* So far, all p80211 msgs are immediate, no waitq/timer necessary */
	/* This may change. */
	p80211req_handlemsg(wlandev, msg);

	/* Pass it down to wlandev via wlandev->mlmerequest */
	if ( wlandev->mlmerequest != NULL ) 
		wlandev->mlmerequest(wlandev, msg);

	clear_bit( 1, &(wlandev->request_pending));
	DBFEXIT;
	return result;	/* if result==0, msg->status still may contain an err */
}
/*----------------------------------------------------------------
* prism2mgmt_ramdl_state
*
* Establishes the beginning/end of a card RAM download session.
*
* It is expected that the ramdl_write() function will be called
* one or more times between the 'enable' and 'disable' calls to
* this function.
*
* Note: This function should not be called when a mac comm port
*       is active.
*
* Arguments:
*	wlandev		wlan device structure
*	msgp		ptr to msg buffer
*
* Returns:
*	0	success and done
*	<0	success, but we're waiting for something to finish.
*	>0	an error occurred while handling the message.
* Side effects:
*
* Call context:
*	process thread  (usually)
----------------------------------------------------------------*/
int prism2mgmt_ramdl_state(wlandevice_t *wlandev, void *msgp)
{
    hfa384x_t		*hw = wlandev->priv;
    p80211msg_p2req_ramdl_state_t	*msg = msgp;
    DBFENTER;

    if (wlandev->msdstate != WLAN_MSD_FWLOAD) {
        WLAN_LOG_ERROR(
            "ramdl_state(): may only be called "
            "in the fwload state.\n");
        msg->resultcode.data =
            P80211ENUM_resultcode_implementation_failure;
        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
        DBFEXIT;
        return 0;
    }

    /*
    ** Note: Interrupts are locked out if this is an AP and are NOT
    ** locked out if this is a station.
    */

    msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
    if  ( msg->enable.data == P80211ENUM_truth_true ) {
        if ( hfa384x_drvr_ramdl_enable(hw, msg->exeaddr.data) ) {
            msg->resultcode.data = P80211ENUM_resultcode_implementation_failure;
        } else {
            msg->resultcode.data = P80211ENUM_resultcode_success;
        }
    } else {
        hfa384x_drvr_ramdl_disable(hw);
        msg->resultcode.data = P80211ENUM_resultcode_success;
    }

    DBFEXIT;
    return 0;
}
Esempio n. 9
0
void prism2sta_config(dev_link_t *link)
{
	client_handle_t		handle;
	wlandevice_t		*wlandev;
	hfa384x_t               *hw;
	int			last_fn;
	int			last_ret;
	tuple_t			tuple;
	cisparse_t		parse;
	config_info_t		socketconf;
	UINT8			buf[64];
	int			minVcc = 0;
	int			maxVcc = 0;
	cistpl_cftable_entry_t	dflt = { 0 };

	DBFENTER;

	handle = link->handle;
	wlandev = (wlandevice_t*)link->priv;
	hw = wlandev->priv;

	/* Collect the config register info */
	tuple.DesiredTuple = CISTPL_CONFIG;
	tuple.Attributes = 0;
	tuple.TupleData = buf;
	tuple.TupleDataMax = sizeof(buf);
	tuple.TupleOffset = 0;
	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));

	link->conf.ConfigBase = parse.config.base;
	link->conf.Present = parse.config.rmask[0];

	/* Configure card */
	link->state |= DEV_CONFIG;

	/* Acquire the current socket config (need Vcc setting) */
	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &socketconf));

	/* Loop through the config table entries until we find one that works */
	/* Assumes a complete and valid CIS */
	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
	while (1) {
		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
		CFG_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
		CFG_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));

		if (cfg->index == 0) goto next_entry;
		link->conf.ConfigIndex = cfg->index;

		/* Lets print out the Vcc that the controller+pcmcia-cs set
		 * for us, cause that's what we're going to use.
		 */
		WLAN_LOG_DEBUG(1,"Initial Vcc=%d/10v\n", socketconf.Vcc);
		if (prism2_ignorevcc) {
			link->conf.Vcc = socketconf.Vcc;
			goto skipvcc;
		}

		/* Use power settings for Vcc and Vpp if present */
		/* Note that the CIS values need to be rescaled */
		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
			WLAN_LOG_DEBUG(1, "Vcc obtained from curtupl.VNOM\n");
			minVcc = maxVcc =
				cfg->vcc.param[CISTPL_POWER_VNOM]/10000;
		} else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
			WLAN_LOG_DEBUG(1, "Vcc set from dflt.VNOM\n");
			minVcc = maxVcc =
				dflt.vcc.param[CISTPL_POWER_VNOM]/10000;
		} else if ((cfg->vcc.present & (1<<CISTPL_POWER_VMAX)) &&
			   (cfg->vcc.present & (1<<CISTPL_POWER_VMIN)) ) {
			WLAN_LOG_DEBUG(1, "Vcc set from curtupl(VMIN,VMAX)\n");			minVcc = cfg->vcc.param[CISTPL_POWER_VMIN]/10000;
			maxVcc = cfg->vcc.param[CISTPL_POWER_VMAX]/10000;
		} else if ((dflt.vcc.present & (1<<CISTPL_POWER_VMAX)) &&
			   (dflt.vcc.present & (1<<CISTPL_POWER_VMIN)) ) {
			WLAN_LOG_DEBUG(1, "Vcc set from dflt(VMIN,VMAX)\n");
			minVcc = dflt.vcc.param[CISTPL_POWER_VMIN]/10000;
			maxVcc = dflt.vcc.param[CISTPL_POWER_VMAX]/10000;
		}

		if ( socketconf.Vcc >= minVcc && socketconf.Vcc <= maxVcc) {
			link->conf.Vcc = socketconf.Vcc;
		} else {
			/* [MSM]: Note that I've given up trying to change
			 * the Vcc if a change is indicated.  It seems the
			 * system&socketcontroller&card vendors can't seem
			 * to get it right, so I'm tired of trying to hack
			 * my way around it.  pcmcia-cs does its best using
			 * the voltage sense pins but sometimes the controller
			 * lies.  Then, even if we have a good read on the VS
			 * pins, some system designs will silently ignore our
			 * requests to set the voltage.  Additionally, some
			 * vendors have 3.3v indicated on their sense pins,
			 * but 5v specified in the CIS or vice-versa.  I've
			 * had it.  My only recommendation is "let the buyer
			 * beware".  Your system might supply 5v to a 3v card
			 * (possibly causing damage) or a 3v capable system
			 * might supply 5v to a 3v capable card (wasting
			 * precious battery life).
			 * My only recommendation (if you care) is to get
			 * yourself an extender card (I don't know where, I
			 * have only one myself) and a meter and test it for
			 * yourself.
			 */
			goto next_entry;
		}
skipvcc:
		WLAN_LOG_DEBUG(1, "link->conf.Vcc=%d\n", link->conf.Vcc);

		/* Do we need to allocate an interrupt? */
		/* HACK: due to a bad CIS....we ALWAYS need an interrupt */
		/* if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) */
			link->conf.Attributes |= CONF_ENABLE_IRQ;

		/* IO window settings */
		link->io.NumPorts1 = link->io.NumPorts2 = 0;
		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
			if (!(io->flags & CISTPL_IO_8BIT))
				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
			if (!(io->flags & CISTPL_IO_16BIT))
				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
			link->io.BasePort1 = io->win[0].base;
			if  ( link->io.BasePort1 != 0 ) {
				WLAN_LOG_WARNING(
				"Brain damaged CIS: hard coded iobase="
				"0x%x, try letting pcmcia_cs decide...\n",
				link->io.BasePort1 );
				link->io.BasePort1 = 0;
			}
			link->io.NumPorts1 = io->win[0].len;
			if (io->nwin > 1) {
				link->io.Attributes2 = link->io.Attributes1;
				link->io.BasePort2 = io->win[1].base;
				link->io.NumPorts2 = io->win[1].len;
			}
		}

		/* This reserves IO space but doesn't actually enable it */
		CFG_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io));

		/* If we got this far, we're cool! */
		break;

next_entry:
		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
			dflt = *cfg;
		CS_CHECK(GetNextTuple,
                         pcmcia_get_next_tuple(handle, &tuple));
	}

	/* 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 (link->conf.Attributes & CONF_ENABLE_IRQ)
	{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) )
		int			i;
		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];
#else
		link->irq.IRQInfo1 = IRQ_LEVEL_ID;
#endif
		link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
		link->irq.Handler = hfa384x_interrupt;
		link->irq.Instance = wlandev;
		CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
	}

	/* 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. */
	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));

	/* Fill the netdevice with this info */
	wlandev->netdev->irq = link->irq.AssignedIRQ;
	wlandev->netdev->base_addr = link->io.BasePort1;

	/* Report what we've done */
	WLAN_LOG_INFO("%s: index 0x%02x: Vcc %d.%d",
		dev_info, link->conf.ConfigIndex,
		link->conf.Vcc/10, link->conf.Vcc%10);
	if (link->conf.Vpp1)
		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
	if (link->conf.Attributes & CONF_ENABLE_IRQ)
		printk(", irq %d", link->irq.AssignedIRQ);
	if (link->io.NumPorts1)
		printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1);
	if (link->io.NumPorts2)
		printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1);
	printk("\n");

	link->state &= ~DEV_CONFIG_PENDING;

	/* Let pcmcia know the device name */
	link->dev = &hw->node;

	/* Register the network device and get assigned a name */
	SET_MODULE_OWNER(wlandev->netdev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) )
	SET_NETDEV_DEV(wlandev->netdev,  &handle_to_dev(link->handle));
#endif
	if (register_wlandev(wlandev) != 0) {
		WLAN_LOG_NOTICE("prism2sta_cs: register_wlandev() failed.\n");
		goto failed;
	}

	strcpy(hw->node.dev_name, wlandev->name);

	/* Any device custom config/query stuff should be done here */
	/* For a netdevice, we should at least grab the mac address */

	return;
cs_failed:
	cs_error(link->handle, last_fn, last_ret);
	WLAN_LOG_ERROR("NextTuple failure? It's probably a Vcc mismatch.\n");

failed:
	prism2sta_release((u_long)link);
	return;
}
Esempio n. 10
0
/*----------------------------------------------------------------
* prism2sta_attach
*
* Half of the attach/detach pair.  Creates and registers a device
* instance with Card Services.  In this case, it also creates the
* wlandev structure and device private structure.  These are
* linked to the device instance via its priv member.
*
* Arguments:
*	none
*
* Returns:
*	A valid ptr to dev_link_t on success, NULL otherwise
*
* Side effects:
*
*
* Call context:
*	process thread (insmod/init_module/register_pccard_driver)
----------------------------------------------------------------*/
dev_link_t *prism2sta_attach(void)
{
	client_reg_t		client_reg;
	int			result;
	dev_link_t		*link = NULL;
	wlandevice_t		*wlandev = NULL;
	hfa384x_t		*hw = NULL;

	DBFENTER;

	/* Alloc our structures */
	link =		kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);

	if (!link || ((wlandev = create_wlan()) == NULL)) {
		WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
		result = -EIO;
		goto failed;
	}
	hw = wlandev->priv;

	/* Clear all the structs */
	memset(link, 0, sizeof(struct dev_link_t));

	if ( wlan_setup(wlandev) != 0 ) {
		WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
		result = -EIO;
		goto failed;
	}

	/* Initialize the hw struct for now */
	hfa384x_create(hw, 0, 0, NULL);
	hw->wlandev = wlandev;

	/* Initialize the PC card device object. */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
	init_timer(&link->release);
	link->release.function = &prism2sta_release;
	link->release.data = (u_long)link;
#endif
	link->conf.IntType = INT_MEMORY_AND_IO;
	link->priv = wlandev;
#if (defined(CS_RELEASE_CODE) && (CS_RELEASE_CODE < 0x2911))
	link->irq.Instance = wlandev;
#endif

	/* Link in to the list of devices managed by this driver */
	link->next = dev_list;
	dev_list = link;

	/* Register with Card Services */
	client_reg.dev_info = &dev_info;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) )
	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
#endif

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) )
	client_reg.EventMask =
		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
		CS_EVENT_RESET_REQUEST |
		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
	client_reg.event_handler = &prism2sta_event;
#endif

	client_reg.Version = 0x0210;
	client_reg.event_callback_args.client_data = link;

	result = pcmcia_register_client(&link->handle, &client_reg);
	if (result != 0) {
		cs_error(link->handle, RegisterClient, result);
		prism2sta_detach(link);
		return NULL;
	}

	goto done;

 failed:
	if (link)	kfree(link);
	if (wlandev)	kfree(wlandev);
	if (hw)		kfree(hw);
	link = NULL;

 done:
	DBFEXIT;
	return link;
}
Esempio n. 11
0
static int prism2_cs_probe(struct pcmcia_device *pdev)
{
	int rval = 0;
	struct wlandevice *wlandev = NULL;
	hfa384x_t *hw = NULL;

        config_info_t socketconf;
        cisparse_t *parse = NULL;
	tuple_t tuple;
	uint8_t	buf[64];
        int last_fn, last_ret;
        cistpl_cftable_entry_t dflt = { 0 };

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
	dev_link_t *link;
#endif

	DBFENTER;

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	/* Set up interrupt type */
        pdev->conf.IntType = INT_MEMORY_AND_IO;
#else
        link = kmalloc(sizeof(dev_link_t), GFP_KERNEL);
        if (link == NULL)
                return -ENOMEM;
        memset(link, 0, sizeof(dev_link_t));

        link->conf.Vcc = 33;
        link->conf.IntType = INT_MEMORY_AND_IO;

        link->handle = pdev;
        pdev->instance = link;
        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;

#endif

	// VCC crap?
        parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);

	wlandev = create_wlan();
	if (!wlandev || !parse) {
		WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
		rval = -EIO;
		goto failed;
	}
	hw = wlandev->priv;

	if ( wlan_setup(wlandev) != 0 ) {
		WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
		rval = -EIO;
		goto failed;
	}

	/* Initialize the hw struct for now */
	hfa384x_create(hw, 0, 0, NULL);
	hw->wlandev = wlandev;

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	hw->pdev = pdev;
	pdev->priv = wlandev;
#else
	hw->link = link;
	link->priv = wlandev;
#endif

        tuple.DesiredTuple = CISTPL_CONFIG;
        tuple.Attributes = 0;
        tuple.TupleData = buf;
        tuple.TupleDataMax = sizeof(buf);
        tuple.TupleOffset = 0;
        CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
        CS_CHECK(GetTupleData, pcmcia_get_tuple_data(pdev, &tuple));
        CS_CHECK(ParseTuple, pcmcia_parse_tuple(pdev, &tuple, parse));
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
        pdev->conf.ConfigBase = parse->config.base;
        pdev->conf.Present = parse->config.rmask[0];
#else
        link->conf.ConfigBase = parse->config.base;
        link->conf.Present = parse->config.rmask[0];

	link->conf.Vcc = socketconf.Vcc;
#endif
        CS_CHECK(GetConfigurationInfo,
                 pcmcia_get_configuration_info(pdev, &socketconf));

	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
        for (;;) {
		cistpl_cftable_entry_t *cfg = &(parse->cftable_entry);
                CFG_CHECK(GetTupleData,
                           pcmcia_get_tuple_data(pdev, &tuple));
                CFG_CHECK(ParseTuple,
                           pcmcia_parse_tuple(pdev, &tuple, parse));

                if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
                        dflt = *cfg;
                if (cfg->index == 0)
                        goto next_entry;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
                pdev->conf.ConfigIndex = cfg->index;
#else
                link->conf.ConfigIndex = cfg->index;
#endif

                /* Does this card need audio output? */
                if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
                        pdev->conf.Attributes |= CONF_ENABLE_SPKR;
                        pdev->conf.Status = CCSR_AUDIO_ENA;
#else
                        link->conf.Attributes |= CONF_ENABLE_SPKR;
                        link->conf.Status = CCSR_AUDIO_ENA;
#endif
                }

                /* Use power settings for Vcc and Vpp if present */
                /*  Note that the CIS values need to be rescaled */
                if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
                        if (socketconf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
                            10000 && !prism2_ignorevcc) {
                                WLAN_LOG_DEBUG(1, "  Vcc mismatch - skipping"
                                       " this entry\n");
                                goto next_entry;
                        }
                } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
                        if (socketconf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] /
                            10000 && !prism2_ignorevcc) {
                                WLAN_LOG_DEBUG(1, "  Vcc (default) mismatch "
                                       "- skipping this entry\n");
                                goto next_entry;
                        }
                }

                if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
                        pdev->conf.Vpp =
                                cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
#else
                        link->conf.Vpp1 = link->conf.Vpp2 =
                                cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
#endif
                } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
                        pdev->conf.Vpp =
                                dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
#else
                        link->conf.Vpp1 = link->conf.Vpp2 =
                                dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
#endif
		}

		/* Do we need to allocate an interrupt? */
		/* HACK: due to a bad CIS....we ALWAYS need an interrupt */
		/* if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
		pdev->conf.Attributes |= CONF_ENABLE_IRQ;
#else
		link->conf.Attributes |= CONF_ENABLE_IRQ;
#endif

		/* IO window settings */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
		pdev->io.NumPorts1 = pdev->io.NumPorts2 = 0;
		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
			pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
			if (!(io->flags & CISTPL_IO_8BIT))
				pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
			if (!(io->flags & CISTPL_IO_16BIT))
				pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
			pdev->io.BasePort1 = io->win[0].base;
			if  ( pdev->io.BasePort1 != 0 ) {
				WLAN_LOG_WARNING(
				"Brain damaged CIS: hard coded iobase="
				"0x%x, try letting pcmcia_cs decide...\n",
				pdev->io.BasePort1 );
				pdev->io.BasePort1 = 0;
			}
			pdev->io.NumPorts1 = io->win[0].len;
			if (io->nwin > 1) {
				pdev->io.Attributes2 = pdev->io.Attributes1;
				pdev->io.BasePort2 = io->win[1].base;
				pdev->io.NumPorts2 = io->win[1].len;
			}
		}
		/* This reserves IO space but doesn't actually enable it */
		CFG_CHECK(RequestIO, pcmcia_request_io(pdev, &pdev->io));
#else
		link->io.NumPorts1 = link->io.NumPorts2 = 0;
		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
			if (!(io->flags & CISTPL_IO_8BIT))
				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
			if (!(io->flags & CISTPL_IO_16BIT))
				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
			link->io.BasePort1 = io->win[0].base;
			if  ( link->io.BasePort1 != 0 ) {
				WLAN_LOG_WARNING(
				"Brain damaged CIS: hard coded iobase="
				"0x%x, try letting pcmcia_cs decide...\n",
				link->io.BasePort1 );
				link->io.BasePort1 = 0;
			}
			link->io.NumPorts1 = io->win[0].len;
			if (io->nwin > 1) {
				link->io.Attributes2 = link->io.Attributes1;
				link->io.BasePort2 = io->win[1].base;
				link->io.NumPorts2 = io->win[1].len;
			}
		}
		/* This reserves IO space but doesn't actually enable it */
		CFG_CHECK(RequestIO, pcmcia_request_io(pdev, &link->io));
#endif
		/* If we got this far, we're cool! */
		break;

	next_entry:
		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
			dflt = *cfg;
		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple));

	}

	/* Let pcmcia know the device name */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	pdev->dev_node = &hw->node;
#else
	link->dev = &hw->node;
#endif

	/* Register the network device and get assigned a name */
	SET_MODULE_OWNER(wlandev->netdev);
	SET_NETDEV_DEV(wlandev->netdev,  &handle_to_dev(pdev));
	if (register_wlandev(wlandev) != 0) {
		WLAN_LOG_NOTICE("prism2sta_cs: register_wlandev() failed.\n");
		goto failed;
	}

	strcpy(hw->node.dev_name, wlandev->name);

	/* 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 LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	if (pdev->conf.Attributes & CONF_ENABLE_IRQ) {
		pdev->irq.IRQInfo1 = IRQ_LEVEL_ID;
		pdev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
		pdev->irq.Handler = hfa384x_interrupt;
		pdev->irq.Instance = wlandev;
		CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
	}
#else
	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
		link->irq.IRQInfo1 = IRQ_LEVEL_ID;
		link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
		link->irq.Handler = hfa384x_interrupt;
		link->irq.Instance = wlandev;
		CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &link->irq));
	}
#endif

	/* 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. */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
#else
	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &link->conf));
#endif

	/* Fill the netdevice with this info */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	wlandev->netdev->irq = pdev->irq.AssignedIRQ;
	wlandev->netdev->base_addr = pdev->io.BasePort1;
#else
	wlandev->netdev->irq = link->irq.AssignedIRQ;
	wlandev->netdev->base_addr = link->io.BasePort1;
#endif

	/* And the rest of the hw structure */
	hw->irq = wlandev->netdev->irq;
	hw->iobase = wlandev->netdev->base_addr;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
	link->state |= DEV_CONFIG;
	link->state &= ~DEV_CONFIG_PENDING;
#endif

	/* And now we're done! */
	wlandev->msdstate = WLAN_MSD_HWPRESENT;

	goto done;

 cs_failed:
        cs_error(pdev, last_fn, last_ret);

failed:
	// wlandev, hw, etc etc..
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	pdev->priv = NULL;
#else
	pdev->instance = NULL;
	if (link) {
		link->priv = NULL;
		kfree(link);
	}
#endif
	if (wlandev) {
		wlan_unsetup(wlandev);
		if (wlandev->priv) {
			hw = wlandev->priv;
			wlandev->priv = NULL;
			if (hw) {
				hfa384x_destroy(hw);
				kfree(hw);
			}
		}
		kfree(wlandev);
	}

done:
	if (parse) kfree(parse);

	DBFEXIT;
	return rval;
}
Esempio n. 12
0
int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis)
{
	int		result = 0;
	conf_reg_t	reg;
	UINT8		corsave;
	DBFENTER;

	WLAN_LOG_DEBUG(3, "Doing reset via CardServices().\n");

	/* Collect COR */
	reg.Function = 0;
	reg.Action = CS_READ;
	reg.Offset = CISREG_COR;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	result = pcmcia_access_configuration_register(hw->pdev, &reg);
#else
	result = pcmcia_access_configuration_register(
			hw->link->handle,
			&reg);
#endif
	if (result != CS_SUCCESS ) {
		WLAN_LOG_ERROR(
			":0: AccessConfigurationRegister(CS_READ) failed,"
			"result=%d.\n", result);
		result = -EIO;
	}
	corsave = reg.Value;

	/* Write reset bit (BIT7) */
	reg.Value |= BIT7;
	reg.Action = CS_WRITE;
	reg.Offset = CISREG_COR;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	result = pcmcia_access_configuration_register(hw->pdev, &reg);
#else
	result = pcmcia_access_configuration_register(
			hw->link->handle,
			&reg);
#endif
	if (result != CS_SUCCESS ) {
		WLAN_LOG_ERROR(
			":1: AccessConfigurationRegister(CS_WRITE) failed,"
			"result=%d.\n", result);
		result = -EIO;
	}

	/* Hold for holdtime */
	mdelay(holdtime);

	if (genesis) {
		reg.Value = genesis;
		reg.Action = CS_WRITE;
		reg.Offset = CISREG_CCSR;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
		result = pcmcia_access_configuration_register(hw->pdev, &reg);
#else
		result = pcmcia_access_configuration_register(
				      hw->link->handle,
				      &reg);
#endif
		if (result != CS_SUCCESS ) {
			WLAN_LOG_ERROR(
				":1: AccessConfigurationRegister(CS_WRITE) failed,"
				"result=%d.\n", result);
			result = -EIO;
		}
	}

	/* Hold for holdtime */
	mdelay(holdtime);

	/* Clear reset bit */
	reg.Value &= ~BIT7;
	reg.Action = CS_WRITE;
	reg.Offset = CISREG_COR;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	result = pcmcia_access_configuration_register(hw->pdev, &reg);
#else
	result = pcmcia_access_configuration_register(
				      hw->link->handle,
				      &reg);
#endif
	if (result != CS_SUCCESS ) {
		WLAN_LOG_ERROR(
			":2: AccessConfigurationRegister(CS_WRITE) failed,"
			"result=%d.\n", result);
		result = -EIO;
		goto done;
	}

	/* Wait for settletime */
	mdelay(settletime);

	/* Set non-reset bits back what they were */
	reg.Value = corsave;
	reg.Action = CS_WRITE;
	reg.Offset = CISREG_COR;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
	result = pcmcia_access_configuration_register(hw->pdev, &reg);
#else
	result = pcmcia_access_configuration_register(
				      hw->link->handle,
				      &reg);
#endif
	if (result != CS_SUCCESS ) {
		WLAN_LOG_ERROR(
			":2: AccessConfigurationRegister(CS_WRITE) failed,"
			"result=%d.\n", result);
		result = -EIO;
		goto done;
	}

done:
	DBFEXIT;
	return result;
}
Esempio n. 13
0
/*----------------------------------------------------------------
* prism2sta_event
*
* Handler for card services events.
*
* Arguments:
*	event		The event code
*	priority	hi/low - REMOVAL is the only hi
*	args		ptr to card services struct containing info about
*			pcmcia status
*
* Returns:
*	Zero on success, non-zero otherwise
*
* Side effects:
*
*
* Call context:
*	Both interrupt and process thread, depends on the event.
----------------------------------------------------------------*/
static int
prism2sta_event (
	event_t event,
	int priority,
	event_callback_args_t *args)
{
	int			result = 0;
	dev_link_t		*link = (dev_link_t *) args->client_data;
	wlandevice_t		*wlandev = (wlandevice_t*)link->priv;
	hfa384x_t		*hw = NULL;

	DBFENTER;

	if (wlandev) hw = wlandev->priv;

	switch (event)
	{
	case CS_EVENT_CARD_INSERTION:
		WLAN_LOG_DEBUG(5,"event is INSERTION\n");
		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
		prism2sta_config(link);
		if (!(link->state & DEV_CONFIG)) {
			wlandev->netdev->irq = 0;
			WLAN_LOG_ERROR(
				"%s: Initialization failed!\n", dev_info);
			wlandev->msdstate = WLAN_MSD_HWFAIL;
			break;
		}

		/* Fill in the rest of the hw struct */
		hw->irq = wlandev->netdev->irq;
		hw->iobase = wlandev->netdev->base_addr;
		hw->link = link;

		if (prism2_doreset) {
			result = hfa384x_corereset(hw,
					prism2_reset_holdtime,
					prism2_reset_settletime, 0);
			if ( result ) {
				WLAN_LOG_ERROR(
					"corereset() failed, result=%d.\n",
					result);
				wlandev->msdstate = WLAN_MSD_HWFAIL;
				break;
			}
		}

#if 0
		/*
		 * TODO: test_hostif() not implemented yet.
		 */
		result = hfa384x_test_hostif(hw);
		if (result) {
			WLAN_LOG_ERROR(
			"test_hostif() failed, result=%d.\n", result);
			wlandev->msdstate = WLAN_MSD_HWFAIL;
			break;
		}
#endif
		wlandev->msdstate = WLAN_MSD_HWPRESENT;
		break;

	case CS_EVENT_CARD_REMOVAL:
		WLAN_LOG_DEBUG(5,"event is REMOVAL\n");
		link->state &= ~DEV_PRESENT;

		if (wlandev) {
			p80211netdev_hwremoved(wlandev);
		}

#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
		if (link->state & DEV_CONFIG)
		{
			link->release.expires = jiffies + (HZ/20);
			add_timer(&link->release);
		}
#endif
		break;
	case CS_EVENT_RESET_REQUEST:
		WLAN_LOG_DEBUG(5,"event is RESET_REQUEST\n");
		WLAN_LOG_NOTICE(
			"prism2 card reset not supported "
			"due to post-reset user mode configuration "
			"requirements.\n");
		WLAN_LOG_NOTICE(
			"  From user mode, use "
			"'cardctl suspend;cardctl resume' "
			"instead.\n");
		break;
	case CS_EVENT_RESET_PHYSICAL:
	case CS_EVENT_CARD_RESET:
		WLAN_LOG_WARNING("Rx'd CS_EVENT_RESET_xxx, should not "
			"be possible since RESET_REQUEST was denied.\n");
		break;

	case CS_EVENT_PM_SUSPEND:
		WLAN_LOG_DEBUG(5,"event is SUSPEND\n");
		link->state |= DEV_SUSPEND;
		if (link->state & DEV_CONFIG)
		{
			prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
			pcmcia_release_configuration(link->handle);
		}
		break;

	case CS_EVENT_PM_RESUME:
		WLAN_LOG_DEBUG(5,"event is RESUME\n");
		link->state &= ~DEV_SUSPEND;
		if (link->state & DEV_CONFIG) {
			pcmcia_request_configuration(link->handle, &link->conf);
		}
		break;
	}

	DBFEXIT;
	return 0;  /* noone else does anthing with the return value */
}
/*----------------------------------------------------------------
* prism2mgmt_scan_results
*
* Retrieve the BSS description for one of the BSSs identified in
* a scan.
*
* Arguments:
*	wlandev		wlan device structure
*	msgp		ptr to msg buffer
*
* Returns:
*	0	success and done
*	<0	success, but we're waiting for something to finish.
*	>0	an error occurred while handling the message.
* Side effects:
*
* Call context:
*	process thread  (usually)
*	interrupt
----------------------------------------------------------------*/
int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp)
{
    int 			result = 0;
    p80211msg_dot11req_scan_results_t       *req;
    hfa384x_t		*hw = wlandev->priv;
    hfa384x_HScanResultSub_t *item = NULL;

    int count;

    DBFENTER;

    req = (p80211msg_dot11req_scan_results_t *) msgp;

    req->resultcode.status = P80211ENUM_msgitem_status_data_ok;

    if (! hw->scanresults) {
        WLAN_LOG_ERROR("dot11req_scan_results can only be used after a successful dot11req_scan.\n");
        result = 2;
        req->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
        goto exit;
    }

    count = (hw->scanresults->framelen - 3) / 32;
    if (count > 32)  count = 32;

    if (req->bssindex.data >= count) {
        WLAN_LOG_DEBUG(0, "requested index (%d) out of range (%d)\n",
                       req->bssindex.data, count);
        result = 2;
        req->resultcode.data = P80211ENUM_resultcode_invalid_parameters;
        goto exit;
    }

    item = &(hw->scanresults->info.hscanresult.result[req->bssindex.data]);
    /* signal and noise */
    req->signal.status = P80211ENUM_msgitem_status_data_ok;
    req->noise.status = P80211ENUM_msgitem_status_data_ok;
    req->signal.data = hfa384x2host_16(item->sl);
    req->noise.data = hfa384x2host_16(item->anl);

    /* BSSID */
    req->bssid.status = P80211ENUM_msgitem_status_data_ok;
    req->bssid.data.len = WLAN_BSSID_LEN;
    memcpy(req->bssid.data.data, item->bssid, WLAN_BSSID_LEN);

    /* SSID */
    req->ssid.status = P80211ENUM_msgitem_status_data_ok;
    req->ssid.data.len = hfa384x2host_16(item->ssid.len);
    memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len);

    /* supported rates */
    for (count = 0; count < 10 ; count++)
        if (item->supprates[count] == 0)
            break;

#define REQBASICRATE(N) \
	if ((count >= N) && DOT11_RATE5_ISBASIC_GET(item->supprates[(N)-1])) { \
		req->basicrate ## N .data = item->supprates[(N)-1]; \
		req->basicrate ## N .status = P80211ENUM_msgitem_status_data_ok; \
	}

    REQBASICRATE(1);
    REQBASICRATE(2);
    REQBASICRATE(3);
    REQBASICRATE(4);
    REQBASICRATE(5);
    REQBASICRATE(6);
    REQBASICRATE(7);
    REQBASICRATE(8);

#define REQSUPPRATE(N) \
	if (count >= N) { \
		req->supprate ## N .data = item->supprates[(N)-1]; \
		req->supprate ## N .status = P80211ENUM_msgitem_status_data_ok; \
	}

    REQSUPPRATE(1);
    REQSUPPRATE(2);
    REQSUPPRATE(3);
    REQSUPPRATE(4);
    REQSUPPRATE(5);
    REQSUPPRATE(6);
    REQSUPPRATE(7);
    REQSUPPRATE(8);

    /* beacon period */
    req->beaconperiod.status = P80211ENUM_msgitem_status_data_ok;
    req->beaconperiod.data = hfa384x2host_16(item->bcnint);

    /* timestamps */
    req->timestamp.status = P80211ENUM_msgitem_status_data_ok;
    req->timestamp.data = jiffies;
    req->localtime.status = P80211ENUM_msgitem_status_data_ok;
    req->localtime.data = jiffies;

    /* atim window */
    req->ibssatimwindow.status = P80211ENUM_msgitem_status_data_ok;
    req->ibssatimwindow.data = hfa384x2host_16(item->atim);

    /* Channel */
    req->dschannel.status = P80211ENUM_msgitem_status_data_ok;
    req->dschannel.data = hfa384x2host_16(item->chid);

    /* capinfo bits */
    count = hfa384x2host_16(item->capinfo);

    /* privacy flag */
    req->privacy.status = P80211ENUM_msgitem_status_data_ok;
    req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count);

    /* cfpollable */
    req->cfpollable.status = P80211ENUM_msgitem_status_data_ok;
    req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count);

    /* cfpollreq */
    req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok;
    req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count);

    /* bsstype */
    req->bsstype.status =  P80211ENUM_msgitem_status_data_ok;
    req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ?
                        P80211ENUM_bsstype_infrastructure :
                        P80211ENUM_bsstype_independent;

    // item->proberesp_rate
    /*
    	req->fhdwelltime
    	req->fhhopset
    	req->fhhoppattern
    	req->fhhopindex
            req->cfpdurremaining
    */

    result = 0;
    req->resultcode.data = P80211ENUM_resultcode_success;

exit:
    DBFEXIT;
    return result;
}
Esempio n. 15
0
/*----------------------------------------------------------------
* p80211knetdev_set_mac_address
*
* Handles the ioctl for changing the MACAddress of a netdevice
*
* references: linux/netdevice.h and drivers/net/net_init.c
*
* NOTE: [MSM] We only prevent address changes when the netdev is
* up.  We don't control anything based on dot11 state.  If the
* address is changed on a STA that's currently associated, you
* will probably lose the ability to send and receive data frames.
* Just be aware.  Therefore, this should usually only be done
* prior to scan/join/auth/assoc.
*
* Arguments:
*	dev	netdevice struct
*	addr	the new MACAddress (a struct)
*
* Returns:
*	zero on success, a negative errno on failure.  Possible values:
*		-EBUSY	device is bussy (cmd not possible)
*		-and errors returned by: p80211req_dorequest(..)
*
* by: Collin R. Mulliner <*****@*****.**>
----------------------------------------------------------------*/
static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr)
{
	struct sockaddr			*new_addr = addr;
	p80211msg_dot11req_mibset_t	dot11req;
	p80211item_unk392_t		*mibattr;
	p80211item_pstr6_t		*macaddr;
	p80211item_uint32_t		*resultcode;
	int result = 0;

	DBFENTER;
	/* If we're running, we don't allow MAC address changes */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38) )
	if ( dev->start) {
		return -EBUSY;
	}
#else
	if (netif_running(dev)) {
		return -EBUSY;
	}
#endif

	/* Set up some convenience pointers. */
	mibattr = &dot11req.mibattribute;
	macaddr = (p80211item_pstr6_t*)&mibattr->data;
	resultcode = &dot11req.resultcode;

	/* Set up a dot11req_mibset */
	memset(&dot11req, 0, sizeof(p80211msg_dot11req_mibset_t));
	dot11req.msgcode = DIDmsg_dot11req_mibset;
	dot11req.msglen = sizeof(p80211msg_dot11req_mibset_t);
	memcpy(dot11req.devname,
		((wlandevice_t*)(dev->priv))->name,
		WLAN_DEVNAMELEN_MAX - 1);

	/* Set up the mibattribute argument */
	mibattr->did = DIDmsg_dot11req_mibset_mibattribute;
	mibattr->status = P80211ENUM_msgitem_status_data_ok;
	mibattr->len = sizeof(mibattr->data);

	macaddr->did = DIDmib_dot11mac_dot11OperationTable_dot11MACAddress;
	macaddr->status = P80211ENUM_msgitem_status_data_ok;
	macaddr->len = sizeof(macaddr->data);
	macaddr->data.len = WLAN_ADDR_LEN;
	memcpy(&macaddr->data.data, new_addr->sa_data, WLAN_ADDR_LEN);

	/* Set up the resultcode argument */
	resultcode->did = DIDmsg_dot11req_mibset_resultcode;
	resultcode->status = P80211ENUM_msgitem_status_no_value;
	resultcode->len = sizeof(resultcode->data);
	resultcode->data = 0;

	/* now fire the request */
	result = p80211req_dorequest(dev->priv, (UINT8*)&dot11req);

	/* If the request wasn't successful, report an error and don't
	 * change the netdev address
	 */
	if ( result != 0 || resultcode->data != P80211ENUM_resultcode_success) {
		WLAN_LOG_ERROR(
		"Low-level driver failed dot11req_mibset(dot11MACAddress).\n");
		result = -EADDRNOTAVAIL;
	} else {
		/* everything's ok, change the addr in netdev */
		memcpy(dev->dev_addr, new_addr->sa_data, dev->addr_len);
	}

	DBFEXIT;
	return result;
}
/*----------------------------------------------------------------
* prism2mgmt_start
*
* Start a BSS.  Any station can do this for IBSS, only AP for ESS.
*
* Arguments:
*	wlandev		wlan device structure
*	msgp		ptr to msg buffer
*
* Returns:
*	0	success and done
*	<0	success, but we're waiting for something to finish.
*	>0	an error occurred while handling the message.
* Side effects:
*
* Call context:
*	process thread  (usually)
*	interrupt
----------------------------------------------------------------*/
int prism2mgmt_start(wlandevice_t *wlandev, void *msgp)
{
    int 			result = 0;
    hfa384x_t		*hw = wlandev->priv;
    p80211msg_dot11req_start_t	*msg = msgp;

    p80211pstrd_t		*pstr;
    u8			bytebuf[80];
    hfa384x_bytestr_t	*p2bytestr = (hfa384x_bytestr_t*)bytebuf;
    u16			word;
    DBFENTER;

    wlandev->macmode = WLAN_MACMODE_NONE;

    /* Set the SSID */
    memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data));

    /*** ADHOC IBSS ***/
    /* see if current f/w is less than 8c3 */
    if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
                                 hw->ident_sta_fw.minor,
                                 hw->ident_sta_fw.variant) <
            HFA384x_FIRMWARE_VERSION(0,8,3)) {
        /* Ad-Hoc not quite supported on Prism2 */
        msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;
        msg->resultcode.data = P80211ENUM_resultcode_not_supported;
        goto done;
    }

    msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;

    /*** STATION ***/
    /* Set the REQUIRED config items */
    /* SSID */
    pstr = (p80211pstrd_t*)&(msg->ssid.data);
    prism2mgmt_pstr2bytestr(p2bytestr, pstr);
    result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFOWNSSID,
                                     bytebuf, HFA384x_RID_CNFOWNSSID_LEN);
    if ( result ) {
        WLAN_LOG_ERROR("Failed to set CnfOwnSSID\n");
        goto failed;
    }
    result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFDESIREDSSID,
                                     bytebuf, HFA384x_RID_CNFDESIREDSSID_LEN);
    if ( result ) {
        WLAN_LOG_ERROR("Failed to set CnfDesiredSSID\n");
        goto failed;
    }

    /* bsstype - we use the default in the ap firmware */
    /* IBSS port */
    hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0);

    /* beacon period */
    word = msg->beaconperiod.data;
    result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNint, word);
    if ( result ) {
        WLAN_LOG_ERROR("Failed to set beacon period=%d.\n", word);
        goto failed;
    }

    /* dschannel */
    word = msg->dschannel.data;
    result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word);
    if ( result ) {
        WLAN_LOG_ERROR("Failed to set channel=%d.\n", word);
        goto failed;
    }
    /* Basic rates */
    word = p80211rate_to_p2bit(msg->basicrate1.data);
    if ( msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->basicrate2.data);
    }
    if ( msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->basicrate3.data);
    }
    if ( msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->basicrate4.data);
    }
    if ( msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->basicrate5.data);
    }
    if ( msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->basicrate6.data);
    }
    if ( msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->basicrate7.data);
    }
    if ( msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->basicrate8.data);
    }
    result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word);
    if ( result ) {
        WLAN_LOG_ERROR("Failed to set basicrates=%d.\n", word);
        goto failed;
    }

    /* Operational rates (supprates and txratecontrol) */
    word = p80211rate_to_p2bit(msg->operationalrate1.data);
    if ( msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->operationalrate2.data);
    }
    if ( msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->operationalrate3.data);
    }
    if ( msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->operationalrate4.data);
    }
    if ( msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->operationalrate5.data);
    }
    if ( msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->operationalrate6.data);
    }
    if ( msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->operationalrate7.data);
    }
    if ( msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok ) {
        word |= p80211rate_to_p2bit(msg->operationalrate8.data);
    }
    result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word);
    if ( result ) {
        WLAN_LOG_ERROR("Failed to set supprates=%d.\n", word);
        goto failed;
    }

    result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word);
    if ( result ) {
        WLAN_LOG_ERROR("Failed to set txrates=%d.\n", word);
        goto failed;
    }

    /* Set the macmode so the frame setup code knows what to do */
    if ( msg->bsstype.data == P80211ENUM_bsstype_independent ) {
        wlandev->macmode = WLAN_MACMODE_IBSS_STA;
        /* lets extend the data length a bit */
        hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304);
    }

    /* Enable the Port */
    result = hfa384x_drvr_enable(hw, 0);
    if ( result ) {
        WLAN_LOG_ERROR("Enable macport failed, result=%d.\n", result);
        goto failed;
    }

    msg->resultcode.data = P80211ENUM_resultcode_success;

    goto done;
failed:
    WLAN_LOG_DEBUG(1, "Failed to set a config option, result=%d\n", result);
    msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters;

done:
    result = 0;

    DBFEXIT;
    return result;
}
Esempio n. 17
0
/*----------------------------------------------------------------
* prism2sta_probe_plx
*
* Probe routine called when a PCI device w/ matching ID is found.
* This PLX implementation uses the following map:
*   BAR0: Unused
*   BAR1: ????
*   BAR2: PCMCIA attribute memory
*   BAR3: PCMCIA i/o space
* Here's the sequence:
*   - Allocate the PCI resources.
*   - Read the PCMCIA attribute memory to make sure we have a WLAN card
*   - Reset the MAC using the PCMCIA COR
*   - Initialize the netdev and wlan data
*   - Initialize the MAC
*
* Arguments:
*	pdev		ptr to pci device structure containing info about
*			pci configuration.
*	id		ptr to the device id entry that matched this device.
*
* Returns:
*	zero		- success
*	negative	- failed
*
* Side effects:
*
*
* Call context:
*	process thread
*
----------------------------------------------------------------*/
static int __devinit
prism2sta_probe_plx(
	struct pci_dev			*pdev,
	const struct pci_device_id	*id)
{
	int		result;
        phys_t	pccard_ioaddr;
	phys_t  pccard_attr_mem;
        unsigned int    pccard_attr_len;
	void __iomem *attr_mem = NULL;
	UINT32		plx_addr;
        wlandevice_t    *wlandev = NULL;
	hfa384x_t	*hw = NULL;
	int		reg;
        u32		regic;

	if (pci_enable_device(pdev))
		return -EIO;

	/* TMC7160 boards are special */
	if ((pdev->vendor == PCIVENDOR_NDC) &&
	    (pdev->device == PCIDEVICE_NCP130_ASIC)) {
		unsigned long delay;

		pccard_attr_mem = 0;
		pccard_ioaddr = pci_resource_start(pdev, 1);

		outb(0x45, pccard_ioaddr);
		delay = jiffies + 1*HZ;
		while (time_before(jiffies, delay));

		if (inb(pccard_ioaddr) != 0x45) {
			WLAN_LOG_ERROR("Initialize the TMC7160 failed. (0x%x)\n", inb(pccard_ioaddr));
			return -EIO;
		}

		pccard_ioaddr = pci_resource_start(pdev, 2);
		prism2_doreset = 0;

		WLAN_LOG_INFO("NDC NCP130 with TMC716(ASIC) PCI interface device found at io:0x%x, irq:%d\n", pccard_ioaddr, pdev->irq);
		goto init;
	}

	/* Collect the resource requirements */
	pccard_attr_mem = pci_resource_start(pdev, 2);
	pccard_attr_len = pci_resource_len(pdev, 2);
        if (pccard_attr_len < PLX_MIN_ATTR_LEN)
		return -EIO;

	pccard_ioaddr = pci_resource_start(pdev, 3);

	/* bjoern: We need to tell the card to enable interrupts, in
	 * case the serial eprom didn't do this already. See the
	 * PLX9052 data book, p8-1 and 8-24 for reference.
	 * [MSM]: This bit of code came from the orinoco_cs driver.
	 */
	plx_addr = pci_resource_start(pdev, 1);

	regic = 0;
	regic = inl(plx_addr+PLX_INTCSR);
	if(regic & PLX_INTCSR_INTEN) {
		WLAN_LOG_DEBUG(1,
			"%s: Local Interrupt already enabled\n", dev_info);
	} else {
		regic |= PLX_INTCSR_INTEN;
		outl(regic, plx_addr+PLX_INTCSR);
		regic = inl(plx_addr+PLX_INTCSR);
		if(!(regic & PLX_INTCSR_INTEN)) {
			WLAN_LOG_ERROR(
				"%s: Couldn't enable Local Interrupts\n",
				dev_info);
			return -EIO;
		}
	}

	/* These assignments are here in case of future mappings for
	 * io space and irq that might be similar to ioremap
	 */
        if (!request_mem_region(pccard_attr_mem, pci_resource_len(pdev, 2), "Prism2")) {
		WLAN_LOG_ERROR("%s: Couldn't reserve PCI memory region\n", dev_info);
		return -EIO;
        }

	attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);

	WLAN_LOG_INFO("A PLX PCI/PCMCIA interface device found, "
		"phymem:0x%llx, phyio=0x%x, irq:%d, "
		"mem: 0x%lx\n",
		(unsigned long long)pccard_attr_mem, pccard_ioaddr, pdev->irq,
		(unsigned long)attr_mem);

	/* Verify whether PC card is present.
	 * [MSM] This needs improvement, the right thing to do is
	 * probably to walk the CIS looking for the vendor and product
	 * IDs.  It would be nice if this could be tied in with the
	 * etc/pcmcia/wlan-ng.conf file.  Any volunteers?  ;-)
	 */
	if (
	readb(attr_mem + 0) != 0x01 || readb(attr_mem + 2) != 0x03 ||
	readb(attr_mem + 4) != 0x00 || readb(attr_mem + 6) != 0x00 ||
	readb(attr_mem + 8) != 0xFF || readb(attr_mem + 10) != 0x17 ||
	readb(attr_mem + 12) != 0x04 || readb(attr_mem + 14) != 0x67) {
		WLAN_LOG_ERROR("Prism2 PC card CIS is invalid.\n");
		return -EIO;
        }
        WLAN_LOG_INFO("A PCMCIA WLAN adapter was found.\n");

        /* Write COR to enable PC card */
	writeb(COR_VALUE, attr_mem + COR_OFFSET);
	reg = readb(attr_mem + COR_OFFSET);

 init:

	/*
	 * Now do everything the same as a PCI device
	 * [MSM] TODO: We could probably factor this out of pcmcia/pci/plx
	 * and perhaps usb.  Perhaps a task for another day.......
	 */

	if ((wlandev = create_wlan()) == NULL) {
		WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
		result = -EIO;
		goto failed;
	}

	hw = wlandev->priv;

	if ( wlan_setup(wlandev) != 0 ) {
		WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
		result = -EIO;
		goto failed;
	}

	/* Setup netdevice's ability to report resources
	 * Note: the netdevice was allocated by wlan_setup()
	 */
        wlandev->netdev->irq = pdev->irq;
        wlandev->netdev->base_addr = pccard_ioaddr;
        wlandev->netdev->mem_start = (unsigned long)attr_mem;
        wlandev->netdev->mem_end = (unsigned long)attr_mem + pci_resource_len(pdev, 0);

	/* Initialize the hw data */
        hfa384x_create(hw, wlandev->netdev->irq, pccard_ioaddr, attr_mem);
	hw->wlandev = wlandev;

	/* Register the wlandev, this gets us a name and registers the
	 * linux netdevice.
	 */
	SET_MODULE_OWNER(wlandev->netdev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
       SET_NETDEV_DEV(wlandev->netdev, &(pdev->dev));
#endif
        if ( register_wlandev(wlandev) != 0 ) {
		WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info);
		result = -EIO;
		goto failed;
        }

#if 0
	/* TODO: Move this and an irq test into an hfa384x_testif() routine.
	 */
	outw(PRISM2STA_MAGIC, HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
	reg=inw( HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
	if ( reg != PRISM2STA_MAGIC ) {
		WLAN_LOG_ERROR("MAC register access test failed!\n");
 		result = -EIO;
		goto failed;
	}
#endif

	/* Do a chip-level reset on the MAC */
	if (prism2_doreset) {
		result = hfa384x_corereset(hw,
				prism2_reset_holdtime,
				prism2_reset_settletime, 0);
		if (result != 0) {
			unregister_wlandev(wlandev);
			hfa384x_destroy(hw);
			WLAN_LOG_ERROR(
				"%s: hfa384x_corereset() failed.\n",
				dev_info);
			result = -EIO;
			goto failed;
		}
	}

	pci_set_drvdata(pdev, wlandev);

	/* Shouldn't actually hook up the IRQ until we
	 * _know_ things are alright.  A test routine would help.
	 */
       	request_irq(wlandev->netdev->irq, hfa384x_interrupt,
		SA_SHIRQ, wlandev->name, wlandev);

	wlandev->msdstate = WLAN_MSD_HWPRESENT;

	result = 0;

	goto done;

 failed:

	pci_set_drvdata(pdev, NULL);
	if (wlandev)	kfree(wlandev);
	if (hw)		kfree(hw);
        if (attr_mem)        iounmap(attr_mem);
	pci_release_regions(pdev);
        pci_disable_device(pdev);

 done:
	DBFEXIT;
        return result;
}
/*----------------------------------------------------------------
* prism2mgmt_scan
*
* Initiate a scan for BSSs.
*
* This function corresponds to MLME-scan.request and part of
* MLME-scan.confirm.  As far as I can tell in the standard, there
* are no restrictions on when a scan.request may be issued.  We have
* to handle in whatever state the driver/MAC happen to be.
*
* Arguments:
*	wlandev		wlan device structure
*	msgp		ptr to msg buffer
*
* Returns:
*	0	success and done
*	<0	success, but we're waiting for something to finish.
*	>0	an error occurred while handling the message.
* Side effects:
*
* Call context:
*	process thread  (usually)
*	interrupt
----------------------------------------------------------------*/
int prism2mgmt_scan(wlandevice_t *wlandev, void *msgp)
{
    int 			result = 0;
    hfa384x_t		*hw = wlandev->priv;
    p80211msg_dot11req_scan_t	*msg = msgp;
    u16                  roamingmode, word;
    int                     i, timeout;
    int                     istmpenable = 0;

    hfa384x_HostScanRequest_data_t  scanreq;

    DBFENTER;

    /* gatekeeper check */
    if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
                                 hw->ident_sta_fw.minor,
                                 hw->ident_sta_fw.variant) <
            HFA384x_FIRMWARE_VERSION(1,3,2)) {
        WLAN_LOG_ERROR("HostScan not supported with current firmware (<1.3.2).\n");
        result = 1;
        msg->resultcode.data = P80211ENUM_resultcode_not_supported;
        goto exit;
    }

    memset(&scanreq, 0, sizeof(scanreq));

    /* save current roaming mode */
    result = hfa384x_drvr_getconfig16(hw,
                                      HFA384x_RID_CNFROAMINGMODE, &roamingmode);
    if ( result ) {
        WLAN_LOG_ERROR("getconfig(ROAMMODE) failed. result=%d\n",
                       result);
        msg->resultcode.data =
            P80211ENUM_resultcode_implementation_failure;
        goto exit;
    }

    /* drop into mode 3 for the scan */
    result = hfa384x_drvr_setconfig16(hw,
                                      HFA384x_RID_CNFROAMINGMODE,
                                      HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
    if ( result ) {
        WLAN_LOG_ERROR("setconfig(ROAMINGMODE) failed. result=%d\n",
                       result);
        msg->resultcode.data =
            P80211ENUM_resultcode_implementation_failure;
        goto exit;
    }

    /* active or passive? */
    if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
                                 hw->ident_sta_fw.minor,
                                 hw->ident_sta_fw.variant) >
            HFA384x_FIRMWARE_VERSION(1,5,0)) {
        if (msg->scantype.data != P80211ENUM_scantype_active) {
            word = host2hfa384x_16(msg->maxchanneltime.data);
        } else {
            word = 0;
        }
        result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPASSIVESCANCTRL, word);
        if ( result ) {
            WLAN_LOG_WARNING("Passive scan not supported with "
                             "current firmware.  (<1.5.1)\n");
        }
    }

    /* set up the txrate to be 2MBPS. Should be fastest basicrate... */
    word = HFA384x_RATEBIT_2;
    scanreq.txRate = host2hfa384x_16(word);

    /* set up the channel list */
    word = 0;
    for (i = 0; i < msg->channellist.data.len; i++) {
        u8 channel = msg->channellist.data.data[i];
        if (channel > 14) continue;
        /* channel 1 is BIT0 ... channel 14 is BIT13 */
        word |= (1 << (channel-1));
    }
    scanreq.channelList = host2hfa384x_16(word);

    /* set up the ssid, if present. */
    scanreq.ssid.len = host2hfa384x_16(msg->ssid.data.len);
    memcpy(scanreq.ssid.data, msg->ssid.data.data, msg->ssid.data.len);

    /* Enable the MAC port if it's not already enabled  */
    result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_PORTSTATUS, &word);
    if ( result ) {
        WLAN_LOG_ERROR("getconfig(PORTSTATUS) failed. "
                       "result=%d\n", result);
        msg->resultcode.data =
            P80211ENUM_resultcode_implementation_failure;
        goto exit;
    }
    if (word == HFA384x_PORTSTATUS_DISABLED) {
        u16 wordbuf[17];

        result = hfa384x_drvr_setconfig16(hw,
                                          HFA384x_RID_CNFROAMINGMODE,
                                          HFA384x_ROAMMODE_HOSTSCAN_HOSTROAM);
        if ( result ) {
            WLAN_LOG_ERROR("setconfig(ROAMINGMODE) failed. result=%d\n", result);
            msg->resultcode.data =
                P80211ENUM_resultcode_implementation_failure;
            goto exit;
        }
        /* Construct a bogus SSID and assign it to OwnSSID and
         * DesiredSSID
         */
        wordbuf[0] = host2hfa384x_16(WLAN_SSID_MAXLEN);
        get_random_bytes(&wordbuf[1], WLAN_SSID_MAXLEN);
        result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFOWNSSID,
                                         wordbuf, HFA384x_RID_CNFOWNSSID_LEN);
        if ( result ) {
            WLAN_LOG_ERROR("Failed to set OwnSSID.\n");
            msg->resultcode.data =
                P80211ENUM_resultcode_implementation_failure;
            goto exit;
        }
        result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFDESIREDSSID,
                                         wordbuf, HFA384x_RID_CNFDESIREDSSID_LEN);
        if ( result ) {
            WLAN_LOG_ERROR("Failed to set DesiredSSID.\n");
            msg->resultcode.data =
                P80211ENUM_resultcode_implementation_failure;
            goto exit;
        }
        /* bsstype */
        result = hfa384x_drvr_setconfig16(hw,
                                          HFA384x_RID_CNFPORTTYPE,
                                          HFA384x_PORTTYPE_IBSS);
        if ( result ) {
            WLAN_LOG_ERROR("Failed to set CNFPORTTYPE.\n");
            msg->resultcode.data =
                P80211ENUM_resultcode_implementation_failure;
            goto exit;
        }
        /* ibss options */
        result = hfa384x_drvr_setconfig16(hw,
                                          HFA384x_RID_CREATEIBSS,
                                          HFA384x_CREATEIBSS_JOINCREATEIBSS);
        if ( result ) {
            WLAN_LOG_ERROR("Failed to set CREATEIBSS.\n");
            msg->resultcode.data =
                P80211ENUM_resultcode_implementation_failure;
            goto exit;
        }
        result = hfa384x_drvr_enable(hw, 0);
        if ( result ) {
            WLAN_LOG_ERROR("drvr_enable(0) failed. "
                           "result=%d\n", result);
            msg->resultcode.data =
                P80211ENUM_resultcode_implementation_failure;
            goto exit;
        }
        istmpenable = 1;
    }

    /* Figure out our timeout first Kus, then HZ */
    timeout = msg->channellist.data.len * msg->maxchanneltime.data;
    timeout = (timeout * HZ)/1000;

    /* Issue the scan request */
    hw->scanflag = 0;

    WLAN_HEX_DUMP(5,"hscanreq", &scanreq, sizeof(scanreq));

    result = hfa384x_drvr_setconfig( hw,
                                     HFA384x_RID_HOSTSCAN, &scanreq,
                                     sizeof(hfa384x_HostScanRequest_data_t));
    if ( result ) {
        WLAN_LOG_ERROR("setconfig(SCANREQUEST) failed. result=%d\n",
                       result);
        msg->resultcode.data =
            P80211ENUM_resultcode_implementation_failure;
        goto exit;
    }

    /* sleep until info frame arrives */
    wait_event_interruptible_timeout(hw->cmdq, hw->scanflag, timeout);

    msg->numbss.status = P80211ENUM_msgitem_status_data_ok;
    if (hw->scanflag == -1)
        hw->scanflag = 0;

    msg->numbss.data = hw->scanflag;

    hw->scanflag = 0;

    /* Disable port if we temporarily enabled it. */
    if (istmpenable) {
        result = hfa384x_drvr_disable(hw, 0);
        if ( result ) {
            WLAN_LOG_ERROR("drvr_disable(0) failed. "
                           "result=%d\n", result);
            msg->resultcode.data =
                P80211ENUM_resultcode_implementation_failure;
            goto exit;
        }
    }

    /* restore original roaming mode */
    result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFROAMINGMODE,
                                      roamingmode);
    if ( result ) {
        WLAN_LOG_ERROR("setconfig(ROAMMODE) failed. result=%d\n",
                       result);
        msg->resultcode.data =
            P80211ENUM_resultcode_implementation_failure;
        goto exit;
    }

    result = 0;
    msg->resultcode.data = P80211ENUM_resultcode_success;

exit:
    msg->resultcode.status = P80211ENUM_msgitem_status_data_ok;

    DBFEXIT;
    return result;
}
Esempio n. 19
0
/*----------------------------------------------------------------
* prism2sta_probe_pci
*
* Probe routine called when a PCI device w/ matching ID is found. 
* The ISL3874 implementation uses the following map:
*   BAR0: Prism2.x registers memory mapped, size=4k
* Here's the sequence:
*   - Allocate the PCI resources.  
*   - Read the PCMCIA attribute memory to make sure we have a WLAN card
*   - Reset the MAC 
*   - Initialize the netdev and wlan data
*   - Initialize the MAC
*
* Arguments:
*	pdev		ptr to pci device structure containing info about 
*			pci configuration.
*	id		ptr to the device id entry that matched this device.
*
* Returns: 
*	zero		- success
*	negative	- failed
*
* Side effects:
*	
*
* Call context:
*	process thread
*	
----------------------------------------------------------------*/
static int __devinit
prism2sta_probe_pci(
	struct pci_dev *pdev, 
	const struct pci_device_id *id)
{
	int		result;
	phys_t		phymem = 0;
	void		*mem = NULL;
        wlandevice_t    *wlandev = NULL;
	hfa384x_t	*hw = NULL;

	DBFENTER;

	/* Enable the pci device */
	if (pci_enable_device(pdev)) {
		WLAN_LOG_ERROR("%s: pci_enable_device() failed.\n", dev_info);
		result = -EIO;
		goto fail;
	}

	/* Figure out our resources */
	phymem = pci_resource_start(pdev, 0);

        if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
		printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
		result = -EIO;
		goto fail;
        }

	mem = ioremap(phymem, PCI_SIZE);
	if ( mem == 0 ) {
		WLAN_LOG_ERROR("%s: ioremap() failed.\n", dev_info);
		result = -EIO;
		goto fail;
	}

	/* Log the device */
        WLAN_LOG_INFO("A Prism2.5 PCI device found, "
		"phymem:0x%llx, irq:%d, mem:0x%p\n", 
		(unsigned long long)phymem, pdev->irq, mem);
	
	if ((wlandev = create_wlan()) == NULL) {
		WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
		result = -EIO;
		goto fail;
	}
	hw = wlandev->priv;
	
	if ( wlan_setup(wlandev) != 0 ) {
		WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
		result = -EIO;
		goto fail;
	}

	/* Setup netdevice's ability to report resources 
	 * Note: the netdevice was allocated by wlan_setup()
	 */
        wlandev->netdev->irq = pdev->irq;
        wlandev->netdev->mem_start = (unsigned long) mem;
        wlandev->netdev->mem_end = wlandev->netdev->mem_start + 
		pci_resource_len(pdev, 0);

	/* Register the wlandev, this gets us a name and registers the
	 * linux netdevice.
	 */
	SET_MODULE_OWNER(wlandev->netdev);
        if ( register_wlandev(wlandev) != 0 ) {
		WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info);
		result = -EIO;
		goto fail;
        }

#if 0
	/* TODO: Move this and an irq test into an hfa384x_testif() routine.
	 */
	outw(PRISM2STA_MAGIC, HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
	reg=inw( HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
	if ( reg != PRISM2STA_MAGIC ) {
		WLAN_LOG_ERROR("MAC register access test failed!\n");
		result = -EIO;
		goto fail;
	}		
#endif

	/* Initialize the hw data */
        hfa384x_create(hw, wlandev->netdev->irq, 0, mem);
	hw->wlandev = wlandev;

	/* Do a chip-level reset on the MAC */
	if (prism2_doreset) {
		result = hfa384x_corereset(hw, 
				prism2_reset_holdtime, 
				prism2_reset_settletime, 0);
		if (result != 0) {
			WLAN_LOG_ERROR(
				"%s: hfa384x_corereset() failed.\n", 
				dev_info);
			unregister_wlandev(wlandev);
			hfa384x_destroy(hw);
			result = -EIO;
			goto fail;
		}
	}

        pci_set_drvdata(pdev, wlandev);

	/* Shouldn't actually hook up the IRQ until we 
	 * _know_ things are alright.  A test routine would help.
	 */
       	request_irq(wlandev->netdev->irq, hfa384x_interrupt, 
		SA_SHIRQ, wlandev->name, wlandev);

	wlandev->msdstate = WLAN_MSD_HWPRESENT;

	result = 0;
	goto done;

 fail:
	pci_set_drvdata(pdev, NULL);
	if (wlandev)	kfree(wlandev);
	if (hw)		kfree(hw);
        if (mem)        iounmap((void *) mem);
	pci_release_regions(pdev);
        pci_disable_device(pdev);

 done:
	DBFEXIT;
	return result;
}