Completed 2.6.16+ support for prism2_cs.

Note that this is completely untested.
This commit is contained in:
pizza 2006-07-22 18:21:00 +00:00
parent 36eeb17fcf
commit 928bc8a929
2 changed files with 224 additions and 3 deletions

View File

@ -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)

View File

@ -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
*