Completed 2.6.16+ support for prism2_cs.
Note that this is completely untested.
This commit is contained in:
parent
36eeb17fcf
commit
928bc8a929
2
CHANGES
2
CHANGES
|
@ -41,7 +41,7 @@
|
|||
* Intersil Corporation as part of PRISM(R) chipset product development.
|
||||
*
|
||||
* --------------------------------------------------------------------
|
||||
- Beginnings of prism2_cs support for 2.6.16+
|
||||
- prism2_cs support for 2.6.16+ (untested)
|
||||
- Makefile fixes for 2.6.17+
|
||||
- udev support for USB targets (Richard Kennedy)
|
||||
- semaphores are deprecated as of 2.6.16 (Chris Rankin)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
static u_int irq_mask = 0xdeb8; /* Interrupt mask */
|
||||
static int irq_list[4] = { -1 }; /* Interrupt list */
|
||||
#endif
|
||||
static u_int prism2_ignorevcc=0; /* Boolean, if set, we
|
||||
static u_int prism2_ignorevcc=1; /* Boolean, if set, we
|
||||
* ignore what the Vcc
|
||||
* is set to and what the CIS
|
||||
* says.
|
||||
|
@ -37,6 +37,7 @@ module_param( irq_mask, int, 0644);
|
|||
static int prism2_cs_suspend(struct pcmcia_device *pdev);
|
||||
static int prism2_cs_resume(struct pcmcia_device *pdev);
|
||||
static void prism2_cs_remove(struct pcmcia_device *pdev);
|
||||
static int prism2_cs_probe(struct pcmcia_device *pdev);
|
||||
#else
|
||||
dev_link_t *prism2sta_attach(void);
|
||||
static void prism2sta_detach(dev_link_t *link);
|
||||
|
@ -146,7 +147,7 @@ static struct pcmcia_driver prism2_cs_driver = {
|
|||
.suspend = prism2_cs_suspend,
|
||||
.resume = prism2_cs_resume,
|
||||
.remove = prism2_cs_remove,
|
||||
// XXXX probe
|
||||
.probe = prism2_cs_probe,
|
||||
#else
|
||||
.attach = prism2sta_attach,
|
||||
.detach = prism2sta_detach,
|
||||
|
@ -159,6 +160,18 @@ static struct pcmcia_driver prism2_cs_driver = {
|
|||
#endif /* kernel_version */
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
|
||||
#define CS_CHECK(fn, ret) \
|
||||
do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
|
||||
|
||||
#define CFG_CHECK(fn, retf) \
|
||||
do { int ret = (retf); \
|
||||
if (ret != 0) { \
|
||||
WLAN_LOG_DEBUG(1, "CardServices(" #fn ") returned %d\n", ret); \
|
||||
cs_error(pdev, fn, ret); \
|
||||
goto next_entry; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void prism2_cs_remove(struct pcmcia_device *pdev)
|
||||
{
|
||||
struct wlandevice *wlandev = pdev->priv;
|
||||
|
@ -211,7 +224,215 @@ int prism2_cs_resume(struct pcmcia_device *pdev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
DBFENTER;
|
||||
|
||||
/* Set up interrupt type */
|
||||
pdev->conf.IntType = INT_MEMORY_AND_IO;
|
||||
|
||||
// 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;
|
||||
pdev->priv = wlandev;
|
||||
|
||||
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));
|
||||
pdev->conf.ConfigBase = parse->config.base;
|
||||
pdev->conf.Present = parse->config.rmask[0];
|
||||
|
||||
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;
|
||||
pdev->conf.ConfigIndex = cfg->index;
|
||||
|
||||
/* Does this card need audio output? */
|
||||
if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
|
||||
pdev->conf.Attributes |= CONF_ENABLE_SPKR;
|
||||
pdev->conf.Status = CCSR_AUDIO_ENA;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
pdev->conf.Vpp =
|
||||
cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
|
||||
else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
|
||||
pdev->conf.Vpp =
|
||||
dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
|
||||
|
||||
/* 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) */
|
||||
pdev->conf.Attributes |= CONF_ENABLE_IRQ;
|
||||
|
||||
/* IO window settings */
|
||||
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));
|
||||
|
||||
/* 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 */
|
||||
pdev->dev_node = &hw->node;
|
||||
|
||||
/* 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 (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));
|
||||
}
|
||||
|
||||
/* 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(pdev, &pdev->conf));
|
||||
|
||||
/* Fill the netdevice with this info */
|
||||
wlandev->netdev->irq = pdev->irq.AssignedIRQ;
|
||||
wlandev->netdev->base_addr = pdev->io.BasePort1;
|
||||
|
||||
/* And now we're done! */
|
||||
|
||||
goto done;
|
||||
|
||||
cs_failed:
|
||||
cs_error(pdev, last_fn, last_ret);
|
||||
|
||||
failed:
|
||||
// wlandev, hw, etc etc..
|
||||
pdev->priv = NULL;
|
||||
if (wlandev) {
|
||||
wlan_unsetup(wlandev);
|
||||
if (wlandev->priv) {
|
||||
hfa384x_t *hw = wlandev->priv;
|
||||
wlandev->priv = NULL;
|
||||
if (hw) {
|
||||
hfa384x_destroy(hw);
|
||||
kfree(hw);
|
||||
}
|
||||
}
|
||||
kfree(wlandev);
|
||||
}
|
||||
|
||||
done:
|
||||
if (parse) kfree(parse);
|
||||
|
||||
DBFEXIT;
|
||||
return rval;
|
||||
}
|
||||
#else // <= 2.6.15
|
||||
#define CS_CHECK(fn, ret) \
|
||||
do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
|
||||
|
||||
#define CFG_CHECK(fn, retf) \
|
||||
do { int ret = (retf); \
|
||||
if (ret != 0) { \
|
||||
WLAN_LOG_DEBUG(1, "CardServices(" #fn ") returned %d\n", ret); \
|
||||
cs_error(link->handle, fn, ret); \
|
||||
goto next_entry; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* prism2sta_attach
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue