Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 17431928194b36a0f88082df875e2e036da7fddf 388 lines 9.7 kB view raw
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_types.h> 47#include <pcmcia/cs.h> 48#include <pcmcia/cistpl.h> 49#include <pcmcia/ds.h> 50 51#include <asm/io.h> 52#include <asm/system.h> 53 54#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n" 55 56#ifdef DEBUG 57 58static void regdump(struct net_device *dev) 59{ 60 int ioaddr = dev->base_addr; 61 int count; 62 63 printk("com20020 register dump:\n"); 64 for (count = ioaddr; count < ioaddr + 16; count++) 65 { 66 if (!(count % 16)) 67 printk("\n%04X: ", count); 68 printk("%02X ", inb(count)); 69 } 70 printk("\n"); 71 72 printk("buffer0 dump:\n"); 73 /* set up the address register */ 74 count = 0; 75 outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI); 76 outb(count & 0xff, _ADDR_LO); 77 78 for (count = 0; count < 256+32; count++) 79 { 80 if (!(count % 16)) 81 printk("\n%04X: ", count); 82 83 /* copy the data */ 84 printk("%02X ", inb(_MEMDATA)); 85 } 86 printk("\n"); 87} 88 89#else 90 91static inline void regdump(struct net_device *dev) { } 92 93#endif 94 95 96/*====================================================================*/ 97 98/* Parameters that can be set with 'insmod' */ 99 100static int node; 101static int timeout = 3; 102static int backplane; 103static int clockp; 104static int clockm; 105 106module_param(node, int, 0); 107module_param(timeout, int, 0); 108module_param(backplane, int, 0); 109module_param(clockp, int, 0); 110module_param(clockm, int, 0); 111 112MODULE_LICENSE("GPL"); 113 114/*====================================================================*/ 115 116static int com20020_config(struct pcmcia_device *link); 117static void com20020_release(struct pcmcia_device *link); 118 119static void com20020_detach(struct pcmcia_device *p_dev); 120 121/*====================================================================*/ 122 123typedef struct com20020_dev_t { 124 struct net_device *dev; 125} com20020_dev_t; 126 127/*====================================================================== 128 129 com20020_attach() creates an "instance" of the driver, allocating 130 local data structures for one device. The device is registered 131 with Card Services. 132 133======================================================================*/ 134 135static int com20020_probe(struct pcmcia_device *p_dev) 136{ 137 com20020_dev_t *info; 138 struct net_device *dev; 139 struct arcnet_local *lp; 140 141 dev_dbg(&p_dev->dev, "com20020_attach()\n"); 142 143 /* Create new network device */ 144 info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); 145 if (!info) 146 goto fail_alloc_info; 147 148 dev = alloc_arcdev(""); 149 if (!dev) 150 goto fail_alloc_dev; 151 152 lp = netdev_priv(dev); 153 lp->timeout = timeout; 154 lp->backplane = backplane; 155 lp->clockp = clockp; 156 lp->clockm = clockm & 3; 157 lp->hw.owner = THIS_MODULE; 158 159 /* fill in our module parameters as defaults */ 160 dev->dev_addr[0] = node; 161 162 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 163 p_dev->io.NumPorts1 = 16; 164 p_dev->io.IOAddrLines = 16; 165 p_dev->conf.Attributes = CONF_ENABLE_IRQ; 166 p_dev->conf.IntType = INT_MEMORY_AND_IO; 167 168 info->dev = dev; 169 p_dev->priv = info; 170 171 return com20020_config(p_dev); 172 173fail_alloc_dev: 174 kfree(info); 175fail_alloc_info: 176 return -ENOMEM; 177} /* com20020_attach */ 178 179/*====================================================================== 180 181 This deletes a driver "instance". The device is de-registered 182 with Card Services. If it has been released, all local data 183 structures are freed. Otherwise, the structures will be freed 184 when the device is released. 185 186======================================================================*/ 187 188static void com20020_detach(struct pcmcia_device *link) 189{ 190 struct com20020_dev_t *info = link->priv; 191 struct net_device *dev = info->dev; 192 193 dev_dbg(&link->dev, "detach...\n"); 194 195 dev_dbg(&link->dev, "com20020_detach\n"); 196 197 dev_dbg(&link->dev, "unregister...\n"); 198 199 unregister_netdev(dev); 200 201 /* 202 * this is necessary because we register our IRQ separately 203 * from card services. 204 */ 205 if (dev->irq) 206 free_irq(dev->irq, dev); 207 208 com20020_release(link); 209 210 /* Unlink device structure, free bits */ 211 dev_dbg(&link->dev, "unlinking...\n"); 212 if (link->priv) 213 { 214 dev = info->dev; 215 if (dev) 216 { 217 dev_dbg(&link->dev, "kfree...\n"); 218 free_netdev(dev); 219 } 220 dev_dbg(&link->dev, "kfree2...\n"); 221 kfree(info); 222 } 223 224} /* com20020_detach */ 225 226/*====================================================================== 227 228 com20020_config() is scheduled to run after a CARD_INSERTION event 229 is received, to configure the PCMCIA socket, and to make the 230 device available to the system. 231 232======================================================================*/ 233 234static int com20020_config(struct pcmcia_device *link) 235{ 236 struct arcnet_local *lp; 237 com20020_dev_t *info; 238 struct net_device *dev; 239 int i, ret; 240 int ioaddr; 241 242 info = link->priv; 243 dev = info->dev; 244 245 dev_dbg(&link->dev, "config...\n"); 246 247 dev_dbg(&link->dev, "com20020_config\n"); 248 249 dev_dbg(&link->dev, "baseport1 is %Xh\n", link->io.BasePort1); 250 i = -ENODEV; 251 if (!link->io.BasePort1) 252 { 253 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) 254 { 255 link->io.BasePort1 = ioaddr; 256 i = pcmcia_request_io(link, &link->io); 257 if (i == 0) 258 break; 259 } 260 } 261 else 262 i = pcmcia_request_io(link, &link->io); 263 264 if (i != 0) 265 { 266 dev_dbg(&link->dev, "requestIO failed totally!\n"); 267 goto failed; 268 } 269 270 ioaddr = dev->base_addr = link->io.BasePort1; 271 dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr); 272 273 dev_dbg(&link->dev, "request IRQ %d\n", 274 link->irq); 275 if (!link->irq) 276 { 277 dev_dbg(&link->dev, "requestIRQ failed totally!\n"); 278 goto failed; 279 } 280 281 dev->irq = link->irq; 282 283 ret = pcmcia_request_configuration(link, &link->conf); 284 if (ret) 285 goto failed; 286 287 if (com20020_check(dev)) 288 { 289 regdump(dev); 290 goto failed; 291 } 292 293 lp = netdev_priv(dev); 294 lp->card_name = "PCMCIA COM20020"; 295 lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ 296 297 SET_NETDEV_DEV(dev, &link->dev); 298 299 i = com20020_found(dev, 0); /* calls register_netdev */ 300 301 if (i != 0) { 302 dev_printk(KERN_NOTICE, &link->dev, 303 "com20020_cs: com20020_found() failed\n"); 304 goto failed; 305 } 306 307 dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n", 308 dev->name, dev->base_addr, dev->irq); 309 return 0; 310 311failed: 312 dev_dbg(&link->dev, "com20020_config failed...\n"); 313 com20020_release(link); 314 return -ENODEV; 315} /* com20020_config */ 316 317/*====================================================================== 318 319 After a card is removed, com20020_release() will unregister the net 320 device, and release the PCMCIA configuration. If the device is 321 still open, this will be postponed until it is closed. 322 323======================================================================*/ 324 325static void com20020_release(struct pcmcia_device *link) 326{ 327 dev_dbg(&link->dev, "com20020_release\n"); 328 pcmcia_disable_device(link); 329} 330 331static int com20020_suspend(struct pcmcia_device *link) 332{ 333 com20020_dev_t *info = link->priv; 334 struct net_device *dev = info->dev; 335 336 if (link->open) 337 netif_device_detach(dev); 338 339 return 0; 340} 341 342static int com20020_resume(struct pcmcia_device *link) 343{ 344 com20020_dev_t *info = link->priv; 345 struct net_device *dev = info->dev; 346 347 if (link->open) { 348 int ioaddr = dev->base_addr; 349 struct arcnet_local *lp = netdev_priv(dev); 350 ARCRESET; 351 } 352 353 return 0; 354} 355 356static struct pcmcia_device_id com20020_ids[] = { 357 PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", 358 "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf), 359 PCMCIA_DEVICE_PROD_ID12("SoHard AG", 360 "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7), 361 PCMCIA_DEVICE_NULL 362}; 363MODULE_DEVICE_TABLE(pcmcia, com20020_ids); 364 365static struct pcmcia_driver com20020_cs_driver = { 366 .owner = THIS_MODULE, 367 .drv = { 368 .name = "com20020_cs", 369 }, 370 .probe = com20020_probe, 371 .remove = com20020_detach, 372 .id_table = com20020_ids, 373 .suspend = com20020_suspend, 374 .resume = com20020_resume, 375}; 376 377static int __init init_com20020_cs(void) 378{ 379 return pcmcia_register_driver(&com20020_cs_driver); 380} 381 382static void __exit exit_com20020_cs(void) 383{ 384 pcmcia_unregister_driver(&com20020_cs_driver); 385} 386 387module_init(init_com20020_cs); 388module_exit(exit_com20020_cs);