11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    A PCMCIA token-ring driver for IBM-based cards
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This driver supports the IBM PCMCIA Token-Ring Card.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Written by Steve Kipisz, kipisz@vnet.ibm.com or
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                             bungy@ibm.net
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Written 1995,1996.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This code is based on pcnet_cs.c from David Hinds.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Linux V2.2.x presented significant changes to the underlying
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ibmtr.c code.  Mainly the code became a lot more organized and
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    modular.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This caused the old PCMCIA Token Ring driver to give up and go
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    home early. Instead of just patching the old code to make it
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    work, the PCMCIA code has been streamlined, updated and possibly
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    improved.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This code now only contains code required for the Card Services.
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    All we do here is set the card up enough so that the real ibmtr.c
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    driver can find it and work with it properly.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i.e. We set up the io port, irq, mmio memory and shared ram
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    memory.  This enables ibmtr_probe in ibmtr.c to find the card and
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    configure it as though it was a normal ISA and/or PnP card.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    CHANGES
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com)
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com)
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Updated to version 2.2.7 to match the first version of the kernel
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    that the modification to ibmtr.c were incorporated into.
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    v2.2.17 July 2000 Burt Silverman (burts@us.ibm.com)
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Address translation feature of PCMCIA controller is usable so
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    memory windows can be placed in High memory (meaning above
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    0xFFFFF.)
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48636b8116d4e116eca1ac978f546b16fadfc15a6cJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49636b8116d4e116eca1ac978f546b16fadfc15a6cJoe Perches
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/trdevice.h>
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ibmtr.h>
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cistpl.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ds.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PCMCIA
68c0153225a0e86013b8b8267ffd94e5484d83b916Jeff Kirsher#include "ibmtr.c"
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Parameters that can be set with 'insmod' */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* MMIO base address */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_long mmiobase = 0xce000;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SRAM base address */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_long srambase = 0xd0000;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SRAM size 8,16,32,64 */
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_long sramsize = 64;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ringspeed 4,16 */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ringspeed = 16;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(mmiobase, ulong, 0);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(srambase, ulong, 0);
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(sramsize, ulong, 0);
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ringspeed, int, 0);
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9515b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowskistatic int ibmtr_config(struct pcmcia_device *link);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase);
97fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void ibmtr_release(struct pcmcia_device *link);
98cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowskistatic void ibmtr_detach(struct pcmcia_device *p_dev);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct ibmtr_dev_t {
103fd238232cd0ff4840ae6946bb338502154096d88Dominik Brodowski	struct pcmcia_device	*p_dev;
104cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski	struct net_device	*dev;
105cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski	struct tok_info		*ti;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} ibmtr_dev_t;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1085fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044Dominik Brodowskistatic irqreturn_t ibmtr_interrupt(int irq, void *dev_id) {
1095fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044Dominik Brodowski	ibmtr_dev_t *info = dev_id;
1105fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044Dominik Brodowski	struct net_device *dev = info->dev;
1115fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044Dominik Brodowski	return tok_interrupt(irq, dev);
1125fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044Dominik Brodowski};
1135fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044Dominik Brodowski
114abf0437b420b1476b9afd56af69d1a725f51359cAl Virostatic int __devinit ibmtr_attach(struct pcmcia_device *link)
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ibmtr_dev_t *info;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct net_device *dev;
118fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowski
119dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    dev_dbg(&link->dev, "ibmtr_attach()\n");
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Create new token-ring device */
122dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau    info = kzalloc(sizeof(*info), GFP_KERNEL);
123f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski    if (!info) return -ENOMEM;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    dev = alloc_trdev(sizeof(struct tok_info));
125f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski    if (!dev) {
126f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski	kfree(info);
127f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski	return -ENOMEM;
128f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski    }
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
130fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowski    info->p_dev = link;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    link->priv = info;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    info->ti = netdev_priv(dev);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13490abdc3b973229bae98dd96649d9f7106cc177a4Dominik Brodowski    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
13590abdc3b973229bae98dd96649d9f7106cc177a4Dominik Brodowski    link->resource[0]->end = 4;
1361ac71e5a35eebee60cdcf15b3980bd94498f037bDominik Brodowski    link->config_flags |= CONF_ENABLE_IRQ;
1377feabb6412ea23edd298c0fa90e5aa6733eb4a42Dominik Brodowski    link->config_regs = PRESENT_OPTION;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1395fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044Dominik Brodowski    info->dev = dev;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14115b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski    return ibmtr_config(link);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* ibmtr_attach */
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
144fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void ibmtr_detach(struct pcmcia_device *link)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct ibmtr_dev_t *info = link->priv;
147b463581154f3f3eecda27cae60df813fefcd84d3Dominik Brodowski    struct net_device *dev = info->dev;
1485bebf82fff53a96f330c0879ffe870bdf3aaeab6Paul Walmsley     struct tok_info *ti = netdev_priv(dev);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
150dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    dev_dbg(&link->dev, "ibmtr_detach\n");
1515bebf82fff53a96f330c0879ffe870bdf3aaeab6Paul Walmsley
1525bebf82fff53a96f330c0879ffe870bdf3aaeab6Paul Walmsley    /*
1535bebf82fff53a96f330c0879ffe870bdf3aaeab6Paul Walmsley     * When the card removal interrupt hits tok_interrupt(),
1545bebf82fff53a96f330c0879ffe870bdf3aaeab6Paul Walmsley     * bail out early, so we don't crash the machine
1555bebf82fff53a96f330c0879ffe870bdf3aaeab6Paul Walmsley     */
1565bebf82fff53a96f330c0879ffe870bdf3aaeab6Paul Walmsley    ti->sram_phys |= 1;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
158c7c2fa079073ab92b0736a161b4cf1051a3e631fDominik Brodowski    unregister_netdev(dev);
1595bebf82fff53a96f330c0879ffe870bdf3aaeab6Paul Walmsley
1605bebf82fff53a96f330c0879ffe870bdf3aaeab6Paul Walmsley    del_timer_sync(&(ti->tr_timer));
161e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski
162e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski    ibmtr_release(link);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    free_netdev(dev);
165b463581154f3f3eecda27cae60df813fefcd84d3Dominik Brodowski    kfree(info);
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* ibmtr_detach */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
168abf0437b420b1476b9afd56af69d1a725f51359cAl Virostatic int __devinit ibmtr_config(struct pcmcia_device *link)
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ibmtr_dev_t *info = link->priv;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct net_device *dev = info->dev;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    struct tok_info *ti = netdev_priv(dev);
173dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    int i, ret;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
175dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    dev_dbg(&link->dev, "ibmtr_config\n");
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17790abdc3b973229bae98dd96649d9f7106cc177a4Dominik Brodowski    link->io_lines = 16;
1787feabb6412ea23edd298c0fa90e5aa6733eb4a42Dominik Brodowski    link->config_index = 0x61;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Determine if this is PRIMARY or ALTERNATE. */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Try PRIMARY card at 0xA20-0xA23 */
18390abdc3b973229bae98dd96649d9f7106cc177a4Dominik Brodowski    link->resource[0]->start = 0xA20;
18490abdc3b973229bae98dd96649d9f7106cc177a4Dominik Brodowski    i = pcmcia_request_io(link);
1854c89e88bfde6a3c179790e21004f24e09a058290Dominik Brodowski    if (i != 0) {
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Couldn't get 0xA20-0xA23.  Try ALTERNATE at 0xA24-0xA27. */
18790abdc3b973229bae98dd96649d9f7106cc177a4Dominik Brodowski	link->resource[0]->start = 0xA24;
18890abdc3b973229bae98dd96649d9f7106cc177a4Dominik Brodowski	ret = pcmcia_request_io(link);
189dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski	if (ret)
190dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski		goto failed;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
1929a017a910346afd88ec2e065989903bf211a7d37Dominik Brodowski    dev->base_addr = link->resource[0]->start;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
194eb14120f743d29744d9475bffec56ff4ad43a749Dominik Brodowski    ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt);
195dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    if (ret)
196dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski	    goto failed;
197eb14120f743d29744d9475bffec56ff4ad43a749Dominik Brodowski    dev->irq = link->irq;
198eb14120f743d29744d9475bffec56ff4ad43a749Dominik Brodowski    ti->irq = link->irq;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Allocate the MMIO memory window */
202cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
203cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    link->resource[2]->flags |= WIN_USE_WAIT;
204cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    link->resource[2]->start = 0;
205cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    link->resource[2]->end = 0x2000;
206cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    ret = pcmcia_request_window(link, link->resource[2], 250);
207dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    if (ret)
208dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski	    goto failed;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
210cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase);
211dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    if (ret)
212dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski	    goto failed;
213cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    ti->mmio = ioremap(link->resource[2]->start,
214cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski		    resource_size(link->resource[2]));
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Allocate the SRAM memory window */
217cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
218cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    link->resource[3]->flags |= WIN_USE_WAIT;
219cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    link->resource[3]->start = 0;
220cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    link->resource[3]->end = sramsize * 1024;
221cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    ret = pcmcia_request_window(link, link->resource[3], 250);
222dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    if (ret)
223dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski	    goto failed;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
225cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    ret = pcmcia_map_mem_page(link, link->resource[3], srambase);
226dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    if (ret)
227dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski	    goto failed;
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
229b5cb259e7fac5536c4ddf350af6a3d6cc950e47eDominik Brodowski    ti->sram_base = srambase >> 12;
230cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    ti->sram_virt = ioremap(link->resource[3]->start,
231cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski		    resource_size(link->resource[3]));
232cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski    ti->sram_phys = link->resource[3]->start;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341ac71e5a35eebee60cdcf15b3980bd94498f037bDominik Brodowski    ret = pcmcia_enable_device(link);
235dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski    if (ret)
236dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski	    goto failed;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /*  Set up the Token-Ring Controller Configuration Register and
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        turn on the card.  Check the "Local Area Network Credit Card
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        Adapters Technical Reference"  SC30-3585 for this info.  */
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ibmtr_hw_setup(dev, mmiobase);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
243dd2e5a156525f11754d9b1e0583f6bb49c253d62Dominik Brodowski    SET_NETDEV_DEV(dev, &link->dev);
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i = ibmtr_probe_card(dev);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (i != 0) {
247636b8116d4e116eca1ac978f546b16fadfc15a6cJoe Perches	pr_notice("register_netdev() failed\n");
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto failed;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251636b8116d4e116eca1ac978f546b16fadfc15a6cJoe Perches    netdev_info(dev, "port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
252636b8116d4e116eca1ac978f546b16fadfc15a6cJoe Perches		dev->base_addr, dev->irq,
253636b8116d4e116eca1ac978f546b16fadfc15a6cJoe Perches		(u_long)ti->mmio, (u_long)(ti->sram_base << 12),
254636b8116d4e116eca1ac978f546b16fadfc15a6cJoe Perches		dev->dev_addr);
25515b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski    return 0;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfailed:
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ibmtr_release(link);
25915b99ac1729503db9e6dc642a50b9b6cb3bf51f9Dominik Brodowski    return -ENODEV;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} /* ibmtr_config */
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
262fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic void ibmtr_release(struct pcmcia_device *link)
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2645f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski	ibmtr_dev_t *info = link->priv;
2655f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski	struct net_device *dev = info->dev;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
267dd0fab5b940c0b65f26ac5b01485bac1f690ace6Dominik Brodowski	dev_dbg(&link->dev, "ibmtr_release\n");
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
269cdb138080b78146d1cdadba9f5dadbeb97445b91Dominik Brodowski	if (link->resource[2]->end) {
2705f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski		struct tok_info *ti = netdev_priv(dev);
2715f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski		iounmap(ti->mmio);
2725f2a71fcb7995633b335a1e380ac63a968e61320Dominik Brodowski	}
273fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowski	pcmcia_disable_device(link);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
276fba395eee7d3f342ca739c20f5b3ee635d0420a0Dominik Brodowskistatic int ibmtr_suspend(struct pcmcia_device *link)
27798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{
27898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski	ibmtr_dev_t *info = link->priv;
27998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski	struct net_device *dev = info->dev;
28098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski
281e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski	if (link->open)
2828661bb5b4af1849c1f5a4e80c4e275fd13c155d6Dominik Brodowski		netif_device_detach(dev);
28398e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski
28498e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski	return 0;
28598e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski}
28698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski
2878814b5050d183f00a25a087b550841797c0c2775Al Virostatic int __devinit ibmtr_resume(struct pcmcia_device *link)
28898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski{
28998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski	ibmtr_dev_t *info = link->priv;
29098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski	struct net_device *dev = info->dev;
29198e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski
292e2d4096365e06b9a3799afbadc28b4519c0b3526Dominik Brodowski	if (link->open) {
2938661bb5b4af1849c1f5a4e80c4e275fd13c155d6Dominik Brodowski		ibmtr_probe(dev);	/* really? */
2948661bb5b4af1849c1f5a4e80c4e275fd13c155d6Dominik Brodowski		netif_device_attach(dev);
2958661bb5b4af1849c1f5a4e80c4e275fd13c155d6Dominik Brodowski	}
29698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski
29798e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski	return 0;
29898e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski}
29998e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski
30098e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*====================================================================*/
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    int i;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Bizarre IBM behavior, there are 16 bits of information we
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       need to set, but the card only allows us to send 4 bits at a
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       time.  For each byte sent to base_addr, bits 7-4 tell the
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       card which part of the 16 bits we are setting, bits 3-0 contain
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       the actual information */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* First nibble provides 4 bits of mmio */
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i = (mmiobase >> 16) & 0x0F;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    outb(i, dev->base_addr);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Second nibble provides 3 bits of mmio */
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i = 0x10 | ((mmiobase >> 12) & 0x0E);
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    outb(i, dev->base_addr);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Third nibble, hard-coded values */
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i = 0x26;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    outb(i, dev->base_addr);
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* Fourth nibble sets shared ram page size */
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i = (sramsize >> 4) & 0x07;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i = ((i == 4) ? 3 : i) << 2;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    i |= 0x30;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (ringspeed == 16)
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i |= 2;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    if (dev->base_addr == 0xA24)
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i |= 1;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    outb(i, dev->base_addr);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    /* 0x40 will release the card for use */
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    outb(0x40, dev->base_addr);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34225f8f54f6e178acfd503a95441b0ea05c525f751Joe Perchesstatic const struct pcmcia_device_id ibmtr_ids[] = {
343469bf2b9389c9265ac0920da5b1a5c71fe496213Dominik Brodowski	PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
344469bf2b9389c9265ac0920da5b1a5c71fe496213Dominik Brodowski	PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
345469bf2b9389c9265ac0920da5b1a5c71fe496213Dominik Brodowski	PCMCIA_DEVICE_NULL,
346469bf2b9389c9265ac0920da5b1a5c71fe496213Dominik Brodowski};
347469bf2b9389c9265ac0920da5b1a5c71fe496213Dominik BrodowskiMODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
348469bf2b9389c9265ac0920da5b1a5c71fe496213Dominik Brodowski
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pcmcia_driver ibmtr_cs_driver = {
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
3512e9b981a7c63ee8278df6823f8389d69dad1a499Dominik Brodowski	.name		= "ibmtr_cs",
352f8cfa618dccbdc6dab5297f75779566a388a98fdDominik Brodowski	.probe		= ibmtr_attach,
353cc3b4866bee996c922e875b8c8efe9f0d8803aaeDominik Brodowski	.remove		= ibmtr_detach,
354469bf2b9389c9265ac0920da5b1a5c71fe496213Dominik Brodowski	.id_table       = ibmtr_ids,
35598e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski	.suspend	= ibmtr_suspend,
35698e4c28b7ec390c2dad6a4c69d69629c0f7e8b10Dominik Brodowski	.resume		= ibmtr_resume,
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init init_ibmtr_cs(void)
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pcmcia_register_driver(&ibmtr_cs_driver);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit exit_ibmtr_cs(void)
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pcmcia_unregister_driver(&ibmtr_cs_driver);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_ibmtr_cs);
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(exit_ibmtr_cs);
371