#include <net/iw_handler.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#define PCMCIA_DEBUG 0
#ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
+module_param(pc_debug, int, 0);
#define dprintk(n, format, args...) \
{ if (pc_debug > (n)) \
printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##args); }
#define WL3501_RESUME 0
#define WL3501_SUSPEND 1
-/* Parameters that can be set with 'insmod' */
-/* Bit map of interrupts to choose from */
-/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
-static unsigned long wl3501_irq_mask = 0xdeb8;
-static int wl3501_irq_list[4] = { -1 };
-
/*
* The event() function is this driver's Card Services event handler. It will
* be called by Card Services when an appropriate card status event is
*/
static void wl3501_config(dev_link_t *link);
static void wl3501_release(dev_link_t *link);
-static int wl3501_event(event_t event, int pri, event_callback_args_t *args);
/*
* The dev_info variable is the "key" that is used to match up this
*
* Move 'size' bytes from PC to card. (Shouldn't be interrupted)
*/
-void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, int size)
+static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src,
+ int size)
{
/* switch to SRAM Page 0 */
wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 :
*
* Move 'size' bytes from card to PC. (Shouldn't be interrupted)
*/
-void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest,
- int size)
+static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest,
+ int size)
{
/* switch to SRAM Page 0 */
wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 :
goto out;
}
-struct net_device_stats *wl3501_get_stats(struct net_device *dev)
+static struct net_device_stats *wl3501_get_stats(struct net_device *dev)
{
struct wl3501_card *this = dev->priv;
return &this->stats;
}
-struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
+static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
{
struct wl3501_card *this = dev->priv;
struct iw_statistics *wstats = &this->wstats;
return wstats;
}
-static inline int wl3501_ethtool_ioctl(struct net_device *dev, void *uaddr)
+static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- u32 ethcmd;
- int rc = -EFAULT;
-
- if (copy_from_user(ðcmd, uaddr, sizeof(ethcmd)))
- goto out;
-
- switch (ethcmd) {
- case ETHTOOL_GDRVINFO: {
- struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO, };
-
- strlcpy(info.driver, wl3501_dev_info, sizeof(info.driver));
- rc = copy_to_user(uaddr, &info, sizeof(info)) ? -EFAULT : 1;
- }
- default:
- rc = -EOPNOTSUPP;
- break;
- }
-out:
- return rc;
+ strlcpy(info->driver, wl3501_dev_info, sizeof(info->driver));
}
-/**
- * wl3501_ioctl - Perform IOCTL call functions
- * @dev - network device
- * @ifreq - request
- * @cmd - command
- *
- * Perform IOCTL call functions here. Some are privileged operations and the
- * effective uid is checked in those cases.
- *
- * This part is optional. Needed only if you want to run wlu (unix version).
- *
- * CAUTION: To prevent interrupted by wl3501_interrupt() and timer-based
- * wl3501_hard_start_xmit() from other interrupts, this should be run
- * single-threaded.
- */
-static int wl3501_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- int rc = -ENODEV;
-
- if (netif_device_present(dev)) {
- rc = -EOPNOTSUPP;
- if (cmd == SIOCETHTOOL)
- rc = wl3501_ethtool_ioctl(dev, (void *)rq->ifr_data);
- }
- return rc;
-}
+static struct ethtool_ops ops = {
+ .get_drvinfo = wl3501_get_drvinfo
+};
/**
* wl3501_detach - deletes a driver "instance"
* Services. If it has been released, all local data structures are freed.
* Otherwise, the structures will be freed when the device is released.
*/
-static void wl3501_detach(dev_link_t *link)
+static void wl3501_detach(struct pcmcia_device *p_dev)
{
+ dev_link_t *link = dev_to_instance(p_dev);
dev_link_t **linkp;
+ struct net_device *dev = link->priv;
/* Locate device structure */
for (linkp = &wl3501_dev_list; *linkp; linkp = &(*linkp)->next)
* function is called, that will trigger a proper detach(). */
if (link->state & DEV_CONFIG) {
-#ifdef PCMCIA_DEBUG
- printk(KERN_DEBUG "wl3501_cs: detach postponed, '%s' "
- "still locked\n", link->dev->dev_name);
-#endif
- goto out;
- }
+ while (link->open > 0)
+ wl3501_close(dev);
- /* Break the link with Card Services */
- if (link->handle)
- pcmcia_deregister_client(link->handle);
+ netif_device_detach(dev);
+ wl3501_release(link);
+ }
/* Unlink device structure, free pieces */
*linkp = link->next;
static const struct iw_handler_def wl3501_handler_def = {
.num_standard = sizeof(wl3501_handler) / sizeof(iw_handler),
.standard = (iw_handler *)wl3501_handler,
- .spy_offset = offsetof(struct wl3501_card, spy_data),
+ .get_wireless_stats = wl3501_get_wireless_stats,
};
/**
* The dev_link structure is initialized, but we don't actually configure the
* card at this point -- we wait until we receive a card insertion event.
*/
-static dev_link_t *wl3501_attach(void)
+static int wl3501_attach(struct pcmcia_device *p_dev)
{
- client_reg_t client_reg;
dev_link_t *link;
struct net_device *dev;
- int ret, i;
+ struct wl3501_card *this;
/* Initialize the dev_link_t structure */
- link = kmalloc(sizeof(*link), GFP_KERNEL);
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
if (!link)
- goto out;
- memset(link, 0, sizeof(struct dev_link_t));
+ return -ENOMEM;
/* The io structure describes IO port mapping */
link->io.NumPorts1 = 16;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
- link->irq.IRQInfo2 = wl3501_irq_mask;
- if (wl3501_irq_list[0] != -1)
- for (i = 0; i < 4; i++)
- link->irq.IRQInfo2 |= 1 << wl3501_irq_list[i];
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = wl3501_interrupt;
/* General socket configuration */
dev->tx_timeout = wl3501_tx_timeout;
dev->watchdog_timeo = 5 * HZ;
dev->get_stats = wl3501_get_stats;
- dev->get_wireless_stats = wl3501_get_wireless_stats;
- dev->do_ioctl = wl3501_ioctl;
+ this = dev->priv;
+ this->wireless_data.spy_data = &this->spy_data;
+ dev->wireless_data = &this->wireless_data;
dev->wireless_handlers = (struct iw_handler_def *)&wl3501_handler_def;
+ SET_ETHTOOL_OPS(dev, &ops);
netif_stop_queue(dev);
link->priv = link->irq.Instance = dev;
- /* Register with Card Services */
- link->next = wl3501_dev_list;
- wl3501_dev_list = link;
- client_reg.dev_info = &wl3501_dev_info;
- client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
- client_reg.EventMask = CS_EVENT_CARD_INSERTION |
- CS_EVENT_RESET_PHYSICAL |
- CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND |
- CS_EVENT_PM_RESUME;
- client_reg.event_handler = wl3501_event;
- client_reg.Version = 0x0210;
- client_reg.event_callback_args.client_data = link;
- ret = pcmcia_register_client(&link->handle, &client_reg);
- if (ret) {
- cs_error(link->handle, RegisterClient, ret);
- wl3501_detach(link);
- link = NULL;
- }
-out:
- return link;
+ link->handle = p_dev;
+ p_dev->instance = link;
+
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ wl3501_config(link);
+
+ return 0;
out_link:
kfree(link);
link = NULL;
- goto out;
+ return -ENOMEM;
}
#define CS_CHECK(fn, ret) \
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
+ SET_NETDEV_DEV(dev, &handle_to_dev(handle));
if (register_netdev(dev)) {
printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n");
goto failed;
link->state &= ~DEV_CONFIG;
}
-/**
- * wl3501_event - The card status event handler
- * @event - event
- * @pri - priority
- * @args - arguments for this event
- *
- * The card status event handler. Mostly, this schedules other stuff to run
- * after an event is received. A CARD_REMOVAL event also sets some flags to
- * discourage the net drivers from trying to talk to the card any more.
- *
- * When a CARD_REMOVAL event is received, we immediately set a flag to block
- * future accesses to this device. All the functions that actually access the
- * device should check this flag to make sure the card is still present.
- */
-static int wl3501_event(event_t event, int pri, event_callback_args_t *args)
+static int wl3501_suspend(struct pcmcia_device *p_dev)
{
- dev_link_t *link = args->client_data;
+ dev_link_t *link = dev_to_instance(p_dev);
struct net_device *dev = link->priv;
- switch (event) {
- case CS_EVENT_CARD_REMOVAL:
- link->state &= ~DEV_PRESENT;
- if (link->state & DEV_CONFIG) {
- while (link->open > 0)
- wl3501_close(dev);
+ link->state |= DEV_SUSPEND;
+
+ wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND);
+ if (link->state & DEV_CONFIG) {
+ if (link->open)
netif_device_detach(dev);
- wl3501_release(link);
- }
- break;
- case CS_EVENT_CARD_INSERTION:
- link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
- wl3501_config(link);
- break;
- case CS_EVENT_PM_SUSPEND:
- link->state |= DEV_SUSPEND;
- wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND);
- /* Fall through... */
- case CS_EVENT_RESET_PHYSICAL:
- if (link->state & DEV_CONFIG) {
- if (link->open)
- netif_device_detach(dev);
- pcmcia_release_configuration(link->handle);
- }
- break;
- case CS_EVENT_PM_RESUME:
- link->state &= ~DEV_SUSPEND;
- wl3501_pwr_mgmt(dev->priv, WL3501_RESUME);
- /* Fall through... */
- case CS_EVENT_CARD_RESET:
- if (link->state & DEV_CONFIG) {
- pcmcia_request_configuration(link->handle, &link->conf);
- if (link->open) {
- wl3501_reset(dev);
- netif_device_attach(dev);
- }
+ pcmcia_release_configuration(link->handle);
+ }
+
+ return 0;
+}
+
+static int wl3501_resume(struct pcmcia_device *p_dev)
+{
+ dev_link_t *link = dev_to_instance(p_dev);
+ struct net_device *dev = link->priv;
+
+ wl3501_pwr_mgmt(dev->priv, WL3501_RESUME);
+ if (link->state & DEV_CONFIG) {
+ pcmcia_request_configuration(link->handle, &link->conf);
+ if (link->open) {
+ wl3501_reset(dev);
+ netif_device_attach(dev);
}
- break;
}
+
return 0;
}
+
+static struct pcmcia_device_id wl3501_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);
+
static struct pcmcia_driver wl3501_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = "wl3501_cs",
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "wl3501_cs",
},
- .attach = wl3501_attach,
- .detach = wl3501_detach,
+ .probe = wl3501_attach,
+ .remove = wl3501_detach,
+ .id_table = wl3501_ids,
+ .suspend = wl3501_suspend,
+ .resume = wl3501_resume,
};
static int __init wl3501_init_module(void)
{
dprintk(0, ": unloading");
pcmcia_unregister_driver(&wl3501_driver);
- while (wl3501_dev_list) {
- /* Mark the device as non-existing to minimize calls to card */
- wl3501_dev_list->state &= ~DEV_PRESENT;
- if (wl3501_dev_list->state & DEV_CONFIG)
- wl3501_release(wl3501_dev_list);
- wl3501_detach(wl3501_dev_list);
- }
+ BUG_ON(wl3501_dev_list != NULL);
}
module_init(wl3501_init_module);
module_exit(wl3501_exit_module);
-MODULE_PARM(wl3501_irq_mask, "i");
-MODULE_PARM(wl3501_irq_list, "1-4i");
MODULE_AUTHOR("Fox Chen <mhchen@golf.ccl.itri.org.tw>, "
"Arnaldo Carvalho de Melo <acme@conectiva.com.br>,"
"Gustavo Niemeyer <niemeyer@conectiva.com>");