1/* 2 * Linux ARCnet driver - COM20020 PCMCIA support 3 * 4 * Written 1994-1999 by Avery Pennarun, 5 * based on an ISA version by David Woodhouse. 6 * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4) 7 * which was derived from pcnet_cs.c by David Hinds. 8 * Some additional portions derived from skeleton.c by Donald Becker. 9 * 10 * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) 11 * for sponsoring the further development of this driver. 12 * 13 * ********************** 14 * 15 * The original copyright of skeleton.c was as follows: 16 * 17 * skeleton.c Written 1993 by Donald Becker. 18 * Copyright 1993 United States Government as represented by the 19 * Director, National Security Agency. This software may only be used 20 * and distributed according to the terms of the GNU General Public License as 21 * modified by SRC, incorporated herein by reference. 22 * 23 * ********************** 24 * Changes: 25 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000 26 * - reorganize kmallocs in com20020_attach, checking all for failure 27 * and releasing the previous allocations if one fails 28 * ********************** 29 * 30 * For more details, see drivers/net/arcnet.c 31 * 32 * ********************** 33 */ 34#include <linux/kernel.h> 35#include <linux/init.h> 36#include <linux/ptrace.h> 37#include <linux/slab.h> 38#include <linux/string.h> 39#include <linux/timer.h> 40#include <linux/delay.h> 41#include <linux/module.h> 42#include <linux/netdevice.h> 43#include <linux/arcdevice.h> 44#include <linux/com20020.h> 45 46#include <pcmcia/cs.h> 47#include <pcmcia/cistpl.h> 48#include <pcmcia/ds.h> 49 50#include <asm/io.h> 51#include <asm/system.h> 52 53#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n" 54 55#ifdef DEBUG 56 57static void regdump(struct net_device *dev) 58{ 59 int ioaddr = dev->base_addr; 60 int count; 61 62 printk("com20020 register dump:\n"); 63 for (count = ioaddr; count < ioaddr + 16; count++) 64 { 65 if (!(count % 16)) 66 printk("\n%04X: ", count); 67 printk("%02X ", inb(count)); 68 } 69 printk("\n"); 70 71 printk("buffer0 dump:\n"); 72 /* set up the address register */ 73 count = 0; 74 outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI); 75 outb(count & 0xff, _ADDR_LO); 76 77 for (count = 0; count < 256+32; count++) 78 { 79 if (!(count % 16)) 80 printk("\n%04X: ", count); 81 82 /* copy the data */ 83 printk("%02X ", inb(_MEMDATA)); 84 } 85 printk("\n"); 86} 87 88#else 89 90static inline void regdump(struct net_device *dev) { } 91 92#endif 93 94 95/*====================================================================*/ 96 97/* Parameters that can be set with 'insmod' */ 98 99static int node; 100static int timeout = 3; 101static int backplane; 102static int clockp; 103static int clockm; 104 105module_param(node, int, 0); 106module_param(timeout, int, 0); 107module_param(backplane, int, 0); 108module_param(clockp, int, 0); 109module_param(clockm, int, 0); 110 111MODULE_LICENSE("GPL"); 112 113/*====================================================================*/ 114 115static int com20020_config(struct pcmcia_device *link); 116static void com20020_release(struct pcmcia_device *link); 117 118static void com20020_detach(struct pcmcia_device *p_dev); 119 120/*====================================================================*/ 121 122typedef struct com20020_dev_t { 123 struct net_device *dev; 124} com20020_dev_t; 125 126/*====================================================================== 127 128 com20020_attach() creates an "instance" of the driver, allocating 129 local data structures for one device. The device is registered 130 with Card Services. 131 132======================================================================*/ 133 134static int com20020_probe(struct pcmcia_device *p_dev) 135{ 136 com20020_dev_t *info; 137 struct net_device *dev; 138 struct arcnet_local *lp; 139 140 dev_dbg(&p_dev->dev, "com20020_attach()\n"); 141 142 /* Create new network device */ 143 info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); 144 if (!info) 145 goto fail_alloc_info; 146 147 dev = alloc_arcdev(""); 148 if (!dev) 149 goto fail_alloc_dev; 150 151 lp = netdev_priv(dev); 152 lp->timeout = timeout; 153 lp->backplane = backplane; 154 lp->clockp = clockp; 155 lp->clockm = clockm & 3; 156 lp->hw.owner = THIS_MODULE; 157 158 /* fill in our module parameters as defaults */ 159 dev->dev_addr[0] = node; 160 161 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; 162 p_dev->resource[0]->end = 16; 163 p_dev->conf.Attributes = CONF_ENABLE_IRQ; 164 p_dev->conf.IntType = INT_MEMORY_AND_IO; 165 166 info->dev = dev; 167 p_dev->priv = info; 168 169 return com20020_config(p_dev); 170 171fail_alloc_dev: 172 kfree(info); 173fail_alloc_info: 174 return -ENOMEM; 175} /* com20020_attach */ 176 177/*====================================================================== 178 179 This deletes a driver "instance". The device is de-registered 180 with Card Services. If it has been released, all local data 181 structures are freed. Otherwise, the structures will be freed 182 when the device is released. 183 184======================================================================*/ 185 186static void com20020_detach(struct pcmcia_device *link) 187{ 188 struct com20020_dev_t *info = link->priv; 189 struct net_device *dev = info->dev; 190 191 dev_dbg(&link->dev, "detach...\n"); 192 193 dev_dbg(&link->dev, "com20020_detach\n"); 194 195 dev_dbg(&link->dev, "unregister...\n"); 196 197 unregister_netdev(dev); 198 199 /* 200 * this is necessary because we register our IRQ separately 201 * from card services. 202 */ 203 if (dev->irq) 204 free_irq(dev->irq, dev); 205 206 com20020_release(link); 207 208 /* Unlink device structure, free bits */ 209 dev_dbg(&link->dev, "unlinking...\n"); 210 if (link->priv) 211 { 212 dev = info->dev; 213 if (dev) 214 { 215 dev_dbg(&link->dev, "kfree...\n"); 216 free_netdev(dev); 217 } 218 dev_dbg(&link->dev, "kfree2...\n"); 219 kfree(info); 220 } 221 222} /* com20020_detach */ 223 224/*====================================================================== 225 226 com20020_config() is scheduled to run after a CARD_INSERTION event 227 is received, to configure the PCMCIA socket, and to make the 228 device available to the system. 229 230======================================================================*/ 231 232static int com20020_config(struct pcmcia_device *link) 233{ 234 struct arcnet_local *lp; 235 com20020_dev_t *info; 236 struct net_device *dev; 237 int i, ret; 238 int ioaddr; 239 240 info = link->priv; 241 dev = info->dev; 242 243 dev_dbg(&link->dev, "config...\n"); 244 245 dev_dbg(&link->dev, "com20020_config\n"); 246 247 dev_dbg(&link->dev, "baseport1 is %Xh\n", 248 (unsigned int) link->resource[0]->start); 249 250 i = -ENODEV; 251 link->io_lines = 16; 252 253 if (!link->resource[0]->start) 254 { 255 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) 256 { 257 link->resource[0]->start = ioaddr; 258 i = pcmcia_request_io(link); 259 if (i == 0) 260 break; 261 } 262 } 263 else 264 i = pcmcia_request_io(link); 265 266 if (i != 0) 267 { 268 dev_dbg(&link->dev, "requestIO failed totally!\n"); 269 goto failed; 270 } 271 272 ioaddr = dev->base_addr = link->resource[0]->start; 273 dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr); 274 275 dev_dbg(&link->dev, "request IRQ %d\n", 276 link->irq); 277 if (!link->irq) 278 { 279 dev_dbg(&link->dev, "requestIRQ failed totally!\n"); 280 goto failed; 281 } 282 283 dev->irq = link->irq; 284 285 ret = pcmcia_request_configuration(link, &link->conf); 286 if (ret) 287 goto failed; 288 289 if (com20020_check(dev)) 290 { 291 regdump(dev); 292 goto failed; 293 } 294 295 lp = netdev_priv(dev); 296 lp->card_name = "PCMCIA COM20020"; 297 lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ 298 299 SET_NETDEV_DEV(dev, &link->dev); 300 301 i = com20020_found(dev, 0); /* calls register_netdev */ 302 303 if (i != 0) { 304 dev_printk(KERN_NOTICE, &link->dev, 305 "com20020_cs: com20020_found() failed\n"); 306 goto failed; 307 } 308 309 dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n", 310 dev->name, dev->base_addr, dev->irq); 311 return 0; 312 313failed: 314 dev_dbg(&link->dev, "com20020_config failed...\n"); 315 com20020_release(link); 316 return -ENODEV; 317} /* com20020_config */ 318 319/*====================================================================== 320 321 After a card is removed, com20020_release() will unregister the net 322 device, and release the PCMCIA configuration. If the device is 323 still open, this will be postponed until it is closed. 324 325======================================================================*/ 326 327static void com20020_release(struct pcmcia_device *link) 328{ 329 dev_dbg(&link->dev, "com20020_release\n"); 330 pcmcia_disable_device(link); 331} 332 333static int com20020_suspend(struct pcmcia_device *link) 334{ 335 com20020_dev_t *info = link->priv; 336 struct net_device *dev = info->dev; 337 338 if (link->open) 339 netif_device_detach(dev); 340 341 return 0; 342} 343 344static int com20020_resume(struct pcmcia_device *link) 345{ 346 com20020_dev_t *info = link->priv; 347 struct net_device *dev = info->dev; 348 349 if (link->open) { 350 int ioaddr = dev->base_addr; 351 struct arcnet_local *lp = netdev_priv(dev); 352 ARCRESET; 353 } 354 355 return 0; 356} 357 358static struct pcmcia_device_id com20020_ids[] = { 359 PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", 360 "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf), 361 PCMCIA_DEVICE_PROD_ID12("SoHard AG", 362 "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7), 363 PCMCIA_DEVICE_NULL 364}; 365MODULE_DEVICE_TABLE(pcmcia, com20020_ids); 366 367static struct pcmcia_driver com20020_cs_driver = { 368 .owner = THIS_MODULE, 369 .drv = { 370 .name = "com20020_cs", 371 }, 372 .probe = com20020_probe, 373 .remove = com20020_detach, 374 .id_table = com20020_ids, 375 .suspend = com20020_suspend, 376 .resume = com20020_resume, 377}; 378 379static int __init init_com20020_cs(void) 380{ 381 return pcmcia_register_driver(&com20020_cs_driver); 382} 383 384static void __exit exit_com20020_cs(void) 385{ 386 pcmcia_unregister_driver(&com20020_cs_driver); 387} 388 389module_init(init_com20020_cs); 390module_exit(exit_com20020_cs); 391