1/*======================================================================
2
3    A PCMCIA token-ring driver for IBM-based cards
4
5    This driver supports the IBM PCMCIA Token-Ring Card.
6    Written by Steve Kipisz, kipisz@vnet.ibm.com or
7                             bungy@ibm.net
8
9    Written 1995,1996.
10
11    This code is based on pcnet_cs.c from David Hinds.
12
13    V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com
14
15    Linux V2.2.x presented significant changes to the underlying
16    ibmtr.c code.  Mainly the code became a lot more organized and
17    modular.
18
19    This caused the old PCMCIA Token Ring driver to give up and go
20    home early. Instead of just patching the old code to make it
21    work, the PCMCIA code has been streamlined, updated and possibly
22    improved.
23
24    This code now only contains code required for the Card Services.
25    All we do here is set the card up enough so that the real ibmtr.c
26    driver can find it and work with it properly.
27
28    i.e. We set up the io port, irq, mmio memory and shared ram
29    memory.  This enables ibmtr_probe in ibmtr.c to find the card and
30    configure it as though it was a normal ISA and/or PnP card.
31
32    CHANGES
33
34    v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com)
35    Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c
36
37    v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com)
38    Updated to version 2.2.7 to match the first version of the kernel
39    that the modification to ibmtr.c were incorporated into.
40
41    v2.2.17 July 2000 Burt Silverman (burts@us.ibm.com)
42    Address translation feature of PCMCIA controller is usable so
43    memory windows can be placed in High memory (meaning above
44    0xFFFFF.)
45
46======================================================================*/
47
48#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49
50#include <linux/kernel.h>
51#include <linux/init.h>
52#include <linux/ptrace.h>
53#include <linux/slab.h>
54#include <linux/string.h>
55#include <linux/timer.h>
56#include <linux/module.h>
57#include <linux/netdevice.h>
58#include <linux/trdevice.h>
59#include <linux/ibmtr.h>
60
61#include <pcmcia/cistpl.h>
62#include <pcmcia/ds.h>
63
64#include <asm/uaccess.h>
65#include <asm/io.h>
66
67#define PCMCIA
68#include "ibmtr.c"
69
70
71/*====================================================================*/
72
73/* Parameters that can be set with 'insmod' */
74
75/* MMIO base address */
76static u_long mmiobase = 0xce000;
77
78/* SRAM base address */
79static u_long srambase = 0xd0000;
80
81/* SRAM size 8,16,32,64 */
82static u_long sramsize = 64;
83
84/* Ringspeed 4,16 */
85static int ringspeed = 16;
86
87module_param(mmiobase, ulong, 0);
88module_param(srambase, ulong, 0);
89module_param(sramsize, ulong, 0);
90module_param(ringspeed, int, 0);
91MODULE_LICENSE("GPL");
92
93/*====================================================================*/
94
95static int ibmtr_config(struct pcmcia_device *link);
96static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase);
97static void ibmtr_release(struct pcmcia_device *link);
98static void ibmtr_detach(struct pcmcia_device *p_dev);
99
100/*====================================================================*/
101
102typedef struct ibmtr_dev_t {
103	struct pcmcia_device	*p_dev;
104	struct net_device	*dev;
105	struct tok_info		*ti;
106} ibmtr_dev_t;
107
108static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) {
109	ibmtr_dev_t *info = dev_id;
110	struct net_device *dev = info->dev;
111	return tok_interrupt(irq, dev);
112};
113
114static int __devinit ibmtr_attach(struct pcmcia_device *link)
115{
116    ibmtr_dev_t *info;
117    struct net_device *dev;
118
119    dev_dbg(&link->dev, "ibmtr_attach()\n");
120
121    /* Create new token-ring device */
122    info = kzalloc(sizeof(*info), GFP_KERNEL);
123    if (!info) return -ENOMEM;
124    dev = alloc_trdev(sizeof(struct tok_info));
125    if (!dev) {
126	kfree(info);
127	return -ENOMEM;
128    }
129
130    info->p_dev = link;
131    link->priv = info;
132    info->ti = netdev_priv(dev);
133
134    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
135    link->resource[0]->end = 4;
136    link->config_flags |= CONF_ENABLE_IRQ;
137    link->config_regs = PRESENT_OPTION;
138
139    info->dev = dev;
140
141    return ibmtr_config(link);
142} /* ibmtr_attach */
143
144static void ibmtr_detach(struct pcmcia_device *link)
145{
146    struct ibmtr_dev_t *info = link->priv;
147    struct net_device *dev = info->dev;
148     struct tok_info *ti = netdev_priv(dev);
149
150    dev_dbg(&link->dev, "ibmtr_detach\n");
151
152    /*
153     * When the card removal interrupt hits tok_interrupt(),
154     * bail out early, so we don't crash the machine
155     */
156    ti->sram_phys |= 1;
157
158    unregister_netdev(dev);
159
160    del_timer_sync(&(ti->tr_timer));
161
162    ibmtr_release(link);
163
164    free_netdev(dev);
165    kfree(info);
166} /* ibmtr_detach */
167
168static int __devinit ibmtr_config(struct pcmcia_device *link)
169{
170    ibmtr_dev_t *info = link->priv;
171    struct net_device *dev = info->dev;
172    struct tok_info *ti = netdev_priv(dev);
173    int i, ret;
174
175    dev_dbg(&link->dev, "ibmtr_config\n");
176
177    link->io_lines = 16;
178    link->config_index = 0x61;
179
180    /* Determine if this is PRIMARY or ALTERNATE. */
181
182    /* Try PRIMARY card at 0xA20-0xA23 */
183    link->resource[0]->start = 0xA20;
184    i = pcmcia_request_io(link);
185    if (i != 0) {
186	/* Couldn't get 0xA20-0xA23.  Try ALTERNATE at 0xA24-0xA27. */
187	link->resource[0]->start = 0xA24;
188	ret = pcmcia_request_io(link);
189	if (ret)
190		goto failed;
191    }
192    dev->base_addr = link->resource[0]->start;
193
194    ret = pcmcia_request_exclusive_irq(link, ibmtr_interrupt);
195    if (ret)
196	    goto failed;
197    dev->irq = link->irq;
198    ti->irq = link->irq;
199    ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
200
201    /* Allocate the MMIO memory window */
202    link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
203    link->resource[2]->flags |= WIN_USE_WAIT;
204    link->resource[2]->start = 0;
205    link->resource[2]->end = 0x2000;
206    ret = pcmcia_request_window(link, link->resource[2], 250);
207    if (ret)
208	    goto failed;
209
210    ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase);
211    if (ret)
212	    goto failed;
213    ti->mmio = ioremap(link->resource[2]->start,
214		    resource_size(link->resource[2]));
215
216    /* Allocate the SRAM memory window */
217    link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
218    link->resource[3]->flags |= WIN_USE_WAIT;
219    link->resource[3]->start = 0;
220    link->resource[3]->end = sramsize * 1024;
221    ret = pcmcia_request_window(link, link->resource[3], 250);
222    if (ret)
223	    goto failed;
224
225    ret = pcmcia_map_mem_page(link, link->resource[3], srambase);
226    if (ret)
227	    goto failed;
228
229    ti->sram_base = srambase >> 12;
230    ti->sram_virt = ioremap(link->resource[3]->start,
231		    resource_size(link->resource[3]));
232    ti->sram_phys = link->resource[3]->start;
233
234    ret = pcmcia_enable_device(link);
235    if (ret)
236	    goto failed;
237
238    /*  Set up the Token-Ring Controller Configuration Register and
239        turn on the card.  Check the "Local Area Network Credit Card
240        Adapters Technical Reference"  SC30-3585 for this info.  */
241    ibmtr_hw_setup(dev, mmiobase);
242
243    SET_NETDEV_DEV(dev, &link->dev);
244
245    i = ibmtr_probe_card(dev);
246    if (i != 0) {
247	pr_notice("register_netdev() failed\n");
248	goto failed;
249    }
250
251    netdev_info(dev, "port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM\n",
252		dev->base_addr, dev->irq,
253		(u_long)ti->mmio, (u_long)(ti->sram_base << 12),
254		dev->dev_addr);
255    return 0;
256
257failed:
258    ibmtr_release(link);
259    return -ENODEV;
260} /* ibmtr_config */
261
262static void ibmtr_release(struct pcmcia_device *link)
263{
264	ibmtr_dev_t *info = link->priv;
265	struct net_device *dev = info->dev;
266
267	dev_dbg(&link->dev, "ibmtr_release\n");
268
269	if (link->resource[2]->end) {
270		struct tok_info *ti = netdev_priv(dev);
271		iounmap(ti->mmio);
272	}
273	pcmcia_disable_device(link);
274}
275
276static int ibmtr_suspend(struct pcmcia_device *link)
277{
278	ibmtr_dev_t *info = link->priv;
279	struct net_device *dev = info->dev;
280
281	if (link->open)
282		netif_device_detach(dev);
283
284	return 0;
285}
286
287static int __devinit ibmtr_resume(struct pcmcia_device *link)
288{
289	ibmtr_dev_t *info = link->priv;
290	struct net_device *dev = info->dev;
291
292	if (link->open) {
293		ibmtr_probe(dev);	/* really? */
294		netif_device_attach(dev);
295	}
296
297	return 0;
298}
299
300
301/*====================================================================*/
302
303static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
304{
305    int i;
306
307    /* Bizarre IBM behavior, there are 16 bits of information we
308       need to set, but the card only allows us to send 4 bits at a
309       time.  For each byte sent to base_addr, bits 7-4 tell the
310       card which part of the 16 bits we are setting, bits 3-0 contain
311       the actual information */
312
313    /* First nibble provides 4 bits of mmio */
314    i = (mmiobase >> 16) & 0x0F;
315    outb(i, dev->base_addr);
316
317    /* Second nibble provides 3 bits of mmio */
318    i = 0x10 | ((mmiobase >> 12) & 0x0E);
319    outb(i, dev->base_addr);
320
321    /* Third nibble, hard-coded values */
322    i = 0x26;
323    outb(i, dev->base_addr);
324
325    /* Fourth nibble sets shared ram page size */
326
327    /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
328    i = (sramsize >> 4) & 0x07;
329    i = ((i == 4) ? 3 : i) << 2;
330    i |= 0x30;
331
332    if (ringspeed == 16)
333	i |= 2;
334    if (dev->base_addr == 0xA24)
335	i |= 1;
336    outb(i, dev->base_addr);
337
338    /* 0x40 will release the card for use */
339    outb(0x40, dev->base_addr);
340}
341
342static const struct pcmcia_device_id ibmtr_ids[] = {
343	PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
344	PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
345	PCMCIA_DEVICE_NULL,
346};
347MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
348
349static struct pcmcia_driver ibmtr_cs_driver = {
350	.owner		= THIS_MODULE,
351	.name		= "ibmtr_cs",
352	.probe		= ibmtr_attach,
353	.remove		= ibmtr_detach,
354	.id_table       = ibmtr_ids,
355	.suspend	= ibmtr_suspend,
356	.resume		= ibmtr_resume,
357};
358
359static int __init init_ibmtr_cs(void)
360{
361	return pcmcia_register_driver(&ibmtr_cs_driver);
362}
363
364static void __exit exit_ibmtr_cs(void)
365{
366	pcmcia_unregister_driver(&ibmtr_cs_driver);
367}
368
369module_init(init_ibmtr_cs);
370module_exit(exit_ibmtr_cs);
371