smc-mca.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:15k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* smc-mca.c: A SMC Ultra ethernet driver for linux. */
  2. /*
  3.     Most of this driver, except for ultramca_probe is nearly
  4.     verbatim from smc-ultra.c by Donald Becker. The rest is
  5.     written and copyright 1996 by David Weis, weisd3458@uni.edu
  6.     This is a driver for the SMC Ultra and SMC EtherEZ ethercards.
  7.     This driver uses the cards in the 8390-compatible, shared memory mode.
  8.     Most of the run-time complexity is handled by the generic code in
  9.     8390.c.
  10.     This driver enables the shared memory only when doing the actual data
  11.     transfers to avoid a bug in early version of the card that corrupted
  12.     data transferred by a AHA1542.
  13.     This driver does not support the programmed-I/O data transfer mode of
  14.     the EtherEZ.  That support (if available) is smc-ez.c.  Nor does it
  15.     use the non-8390-compatible "Altego" mode. (No support currently planned.)
  16.     Changelog:
  17.     Paul Gortmaker  : multiple card support for module users.
  18.     David Weis  : Micro Channel-ized it.
  19.     Tom Sightler  : Added support for IBM PS/2 Ethernet Adapter/A
  20.     Christopher Turcksin : Changed MCA-probe so that multiple adapters are
  21.    found correctly (Jul 16, 1997)
  22.     Chris Beauregard  : Tried to merge the two changes above (Dec 15, 1997)
  23.     Tom Sightler  : Fixed minor detection bug caused by above merge
  24.     Tom Sightler  : Added support for three more Western Digital
  25.    MCA-adapters
  26.     Tom Sightler  : Added support for 2.2.x mca_find_unused_adapter
  27.     Hartmut Schmidt  : - Modified parameter detection to handle each
  28.      card differently depending on a switch-list
  29.    - 'card_ver' removed from the adapter list
  30.    - Some minor bug fixes
  31. */
  32. #include <linux/module.h>
  33. #include <linux/kernel.h>
  34. #include <linux/sched.h>
  35. #include <linux/errno.h>
  36. #include <linux/string.h>
  37. #include <linux/init.h>
  38. #include <asm/io.h>
  39. #include <asm/system.h>
  40. #include <linux/netdevice.h>
  41. #include <linux/etherdevice.h>
  42. #include "8390.h"
  43. #include "smc-mca.h"
  44. #include <linux/mca.h>
  45. int ultramca_probe(struct net_device *dev);
  46. static int ultramca_open(struct net_device *dev);
  47. static void ultramca_reset_8390(struct net_device *dev);
  48. static void ultramca_get_8390_hdr(struct net_device *dev,
  49.                                   struct e8390_pkt_hdr *hdr,
  50.                                   int ring_page);
  51. static void ultramca_block_input(struct net_device *dev, int count,
  52.                                  struct sk_buff *skb,
  53.                                  int ring_offset);
  54. static void ultramca_block_output(struct net_device *dev, int count,
  55.                                   const unsigned char *buf,
  56.                                   const int start_page);
  57. static int ultramca_close_card(struct net_device *dev);
  58. #define START_PG        0x00    /* First page of TX buffer */
  59. #define ULTRA_CMDREG 0      /* Offset to ASIC command register. */
  60. #define ULTRA_RESET  0x80   /* Board reset, in ULTRA_CMDREG. */
  61. #define ULTRA_MEMENB 0x40   /* Enable the shared memory. */
  62. #define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */
  63. #define ULTRA_IO_EXTENT 32
  64. #define EN0_ERWCNT      0x08  /* Early receive warning count. */
  65. #define _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A            0
  66. #define _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A            1
  67. #define _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A              2
  68. #define _6fc1_WD_Starcard_PLUS_A_WD8003ST_A                            3
  69. #define _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A                        4
  70. #define _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A        5
  71. #define _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A        6
  72. #define _efe5_IBM_PS2_Adapter_A_for_Ethernet                           7
  73. struct smc_mca_adapters_t {
  74. unsigned int id;
  75. char *name;
  76. };
  77. static struct smc_mca_adapters_t smc_mca_adapters[] __initdata = {
  78.     { 0x61c8, "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)" },
  79.     { 0x61c9, "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)" },
  80.     { 0x6fc0, "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)" },
  81.     { 0x6fc1, "WD Starcard PLUS/A (WD8003ST/A)" },
  82.     { 0x6fc2, "WD Ethercard PLUS 10T/A (WD8003W/A)" },
  83.     { 0xefd4, "IBM PS/2 Adapter/A for Ethernet UTP/AUI (WD8013WP/A)" },
  84.     { 0xefd5, "IBM PS/2 Adapter/A for Ethernet BNC/AUI (WD8013EP/A)" },
  85.     { 0xefe5, "IBM PS/2 Adapter/A for Ethernet" },
  86.     { 0x0000, NULL }
  87. };
  88. int __init ultramca_probe(struct net_device *dev)
  89. {
  90. unsigned short ioaddr;
  91. unsigned char reg4, num_pages;
  92. char slot = -1;
  93. unsigned char pos2 = 0xff, pos3 = 0xff, pos4 = 0xff, pos5 = 0xff;
  94. int i, j;
  95. int adapter_found = 0;
  96. int adapter = 0;
  97. int tbase = 0;
  98. int tirq = 0;
  99. int base_addr = dev->base_addr;
  100. int irq = dev->irq;
  101. if (!MCA_bus) {
  102. return -ENODEV;
  103. }
  104. SET_MODULE_OWNER(dev);
  105. if (base_addr || irq) {
  106. printk(KERN_INFO "Probing for SMC MCA adapter");
  107. if (base_addr) {
  108. printk(KERN_INFO " at I/O address 0x%04x%c",
  109.        base_addr, irq ? ' ' : 'n');
  110. }
  111. if (irq) {
  112. printk(KERN_INFO "using irq %dn", irq);
  113. }
  114. }
  115.         /* proper multicard detection by ZP Gu (zpg@castle.net) */
  116. for (j = 0; (smc_mca_adapters[j].name != NULL) && !adapter_found; j++) {
  117. slot = mca_find_unused_adapter(smc_mca_adapters[j].id, 0);
  118. while((slot != MCA_NOTFOUND) && !adapter_found) {
  119. tirq = 0;
  120. tbase = 0;
  121.                         /* If we're trying to match a specificied irq or
  122.  * io address, we'll reject the adapter
  123.  * found unless it's the one we're looking for
  124.  */
  125. pos2 = mca_read_stored_pos(slot, 2); /* io_addr */
  126. pos3 = mca_read_stored_pos(slot, 3); /* shared mem */
  127. pos4 = mca_read_stored_pos(slot, 4); /* ROM bios addr
  128.       * range */
  129. pos5 = mca_read_stored_pos(slot, 5); /* irq, media
  130.       * and RIPL */
  131. /* Test the following conditions:
  132.  * - If an irq parameter is supplied, compare it
  133.  *   with the irq of the adapter we found
  134.  * - If a base_addr paramater is given, compare it
  135.  *   with the base_addr of the adapter we found
  136.  * - Check that the irq and the base_addr of the
  137.  *   adapter we found is not already in use by
  138.  *   this driver
  139.  */
  140. switch (j) { /* j = card-idx (card array above) [hs] */
  141. case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A:
  142.                 case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A:
  143. case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A:
  144. case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A:
  145. {
  146. tbase = addr_table[(pos2 & 0xf0) >> 4].base_addr;
  147. tirq  = irq_table[(pos5 & 0xc) >> 2].new_irq;
  148. break;
  149. }
  150. case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A:
  151. case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A:
  152. case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A:
  153. case _efe5_IBM_PS2_Adapter_A_for_Ethernet:
  154. {
  155. tbase = ((pos2 & 0x0fe) * 0x10);
  156. tirq  = irq_table[(pos5 & 3)].old_irq;
  157. break;
  158. }
  159. }
  160. if(!tirq || !tbase || (irq && irq != tirq) || (base_addr && tbase != base_addr)) {
  161. slot = mca_find_unused_adapter(smc_mca_adapters[j].id, slot + 1);
  162. } else {
  163. adapter_found = 1;
  164. adapter = j;
  165. }
  166. }
  167. }
  168. if(!adapter_found) {
  169. return ((base_addr || irq) ? -ENXIO : -ENODEV);
  170. }
  171.         /* Adapter found. */
  172. printk(KERN_INFO "%s: %s found in slot %dn",
  173.        dev->name, smc_mca_adapters[adapter].name, slot + 1);
  174. mca_set_adapter_name(slot, smc_mca_adapters[adapter].name);
  175. mca_mark_as_used(slot);
  176. dev->base_addr = ioaddr = tbase;
  177. dev->irq       = tirq;
  178. dev->mem_start = 0;
  179. num_pages      = 40;
  180. switch (adapter) { /* card-# in const array above [hs] */
  181. case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A:
  182. case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A:
  183. {
  184. for (i = 0; i < 16; i++) { /* taking 16 counts
  185.     * up to 15 [hs] */
  186. if (mem_table[i].mem_index == (pos3 & ~MEM_MASK)) {
  187. dev->mem_start = mem_table[i].mem_start;
  188. num_pages = mem_table[i].num_pages;
  189. }
  190. }
  191. break;
  192. }
  193. case _6fc0_WD_Ethercard_PLUS_A_WD8003E_A_OR_WD8003ET_A:
  194. case _6fc1_WD_Starcard_PLUS_A_WD8003ST_A:
  195. case _6fc2_WD_Ethercard_PLUS_10T_A_WD8003W_A:
  196. case _efe5_IBM_PS2_Adapter_A_for_Ethernet:
  197. {
  198. dev->mem_start = ((pos3 & 0xfc) * 0x1000);
  199. num_pages = 0x40;
  200. break;
  201. }
  202. case _efd4_IBM_PS2_Adapter_A_for_Ethernet_UTP_AUI_WD8013WP_A:
  203. case _efd5_IBM_PS2_Adapter_A_for_Ethernet_BNC_AUI_WD8013WP_A:
  204. {
  205. /* courtesy of gamera@quartz.ocn.ne.jp, pos3 indicates
  206.  * the index of the 0x2000 step.
  207.  * beware different number of pages [hs]
  208.  */
  209. dev->mem_start = 0xc0000 + (0x2000 * (pos3 & 0xf));
  210. num_pages = 0x20 + (2 * (pos3 & 0x10));
  211. break;
  212. }
  213. }
  214. if (dev->mem_start == 0) /* sanity check, shouldn't happen */
  215. return -ENODEV;
  216. if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name))
  217. return -EBUSY;
  218. reg4 = inb(ioaddr + 4) & 0x7f;
  219. outb(reg4, ioaddr + 4);
  220. printk(KERN_INFO "%s: Parameters: %#3x,", dev->name, ioaddr);
  221. for (i = 0; i < 6; i++)
  222. printk(KERN_INFO " %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
  223. /* Switch from the station address to the alternate register set
  224.  * and read the useful registers there.
  225.  */
  226. outb(0x80 | reg4, ioaddr + 4);
  227. /* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot.
  228.  */
  229. outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
  230. /* Switch back to the station address register set so that
  231.  * the MS-DOS driver can find the card after a warm boot.
  232.  */
  233. outb(reg4, ioaddr + 4);
  234. /* Allocate dev->priv and fill in 8390 specific dev fields.
  235.  */
  236. if (ethdev_init(dev)) {
  237. printk (KERN_INFO ", no memory for dev->priv.n");
  238. release_region(ioaddr, ULTRA_IO_EXTENT);
  239. return -ENOMEM;
  240. }
  241. /* The 8390 isn't at the base address, so fake the offset
  242.  */
  243. dev->base_addr = ioaddr + ULTRA_NIC_OFFSET;
  244. ei_status.name = "SMC Ultra MCA";
  245. ei_status.word16 = 1;
  246. ei_status.tx_start_page = START_PG;
  247. ei_status.rx_start_page = START_PG + TX_PAGES;
  248. ei_status.stop_page = num_pages;
  249. dev->rmem_start = dev->mem_start + TX_PAGES * 256;
  250. dev->mem_end = dev->rmem_end =
  251. dev->mem_start + (ei_status.stop_page - START_PG) * 256;
  252. printk(KERN_INFO ", IRQ %d memory %#lx-%#lx.n",
  253. dev->irq, dev->mem_start, dev->mem_end - 1);
  254. ei_status.reset_8390 = &ultramca_reset_8390;
  255. ei_status.block_input = &ultramca_block_input;
  256. ei_status.block_output = &ultramca_block_output;
  257. ei_status.get_8390_hdr = &ultramca_get_8390_hdr;
  258. ei_status.priv = slot;
  259. dev->open = &ultramca_open;
  260. dev->stop = &ultramca_close_card;
  261. NS8390_init(dev, 0);
  262. return 0;
  263. }
  264. static int ultramca_open(struct net_device *dev)
  265. {
  266. int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
  267. int retval;
  268. if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)))
  269. return retval;
  270. outb(ULTRA_MEMENB, ioaddr); /* Enable memory */
  271. outb(0x80, ioaddr + 5);     /* ??? */
  272. outb(0x01, ioaddr + 6);     /* Enable interrupts and memory. */
  273. outb(0x04, ioaddr + 5);     /* ??? */
  274. /* Set the early receive warning level in window 0 high enough not
  275.  * to receive ERW interrupts.
  276.  */
  277. /* outb_p(E8390_NODMA + E8390_PAGE0, dev->base_addr);
  278.  * outb(0xff, dev->base_addr + EN0_ERWCNT);
  279.  */
  280. ei_open(dev);
  281. return 0;
  282. }
  283. static void ultramca_reset_8390(struct net_device *dev)
  284. {
  285. int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
  286. outb(ULTRA_RESET, ioaddr);
  287. if (ei_debug > 1)
  288. printk("resetting Ultra, t=%ld...", jiffies);
  289. ei_status.txing = 0;
  290. outb(0x80, ioaddr + 5);     /* ??? */
  291. outb(0x01, ioaddr + 6);     /* Enable interrupts and memory. */
  292. if (ei_debug > 1)
  293. printk("reset donen");
  294. return;
  295. }
  296. /* Grab the 8390 specific header. Similar to the block_input routine, but
  297.  * we don't need to be concerned with ring wrap as the header will be at
  298.  * the start of a page, so we optimize accordingly.
  299.  */
  300. static void ultramca_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
  301. {
  302. unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG) << 8);
  303. #ifdef notdef
  304. /* Officially this is what we are doing, but the readl() is faster */
  305. isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
  306. #else
  307. ((unsigned int*)hdr)[0] = isa_readl(hdr_start);
  308. #endif
  309. }
  310. /* Block input and output are easy on shared memory ethercards, the only
  311.  * complication is when the ring buffer wraps.
  312.  */
  313. static void ultramca_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
  314. {
  315. unsigned long xfer_start = dev->mem_start + ring_offset - (START_PG << 8);
  316. if (xfer_start + count > dev->rmem_end) {
  317. /* We must wrap the input move. */
  318. int semi_count = dev->rmem_end - xfer_start;
  319. isa_memcpy_fromio(skb->data, xfer_start, semi_count);
  320. count -= semi_count;
  321. isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
  322. } else {
  323. /* Packet is in one chunk -- we can copy + cksum. */
  324. isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
  325. }
  326. }
  327. static void ultramca_block_output(struct net_device *dev, int count, const unsigned char *buf,
  328.                 int start_page)
  329. {
  330. unsigned long shmem = dev->mem_start + ((start_page - START_PG) << 8);
  331. isa_memcpy_toio(shmem, buf, count);
  332. }
  333. static int ultramca_close_card(struct net_device *dev)
  334. {
  335. int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
  336. netif_stop_queue(dev);
  337. if (ei_debug > 1)
  338. printk("%s: Shutting down ethercard.n", dev->name);
  339. outb(0x00, ioaddr + 6);     /* Disable interrupts. */
  340. free_irq(dev->irq, dev);
  341. NS8390_init(dev, 0);
  342. /* We should someday disable shared memory and change to 8-bit mode
  343.          * "just in case"...
  344.  */
  345. return 0;
  346. }
  347. #ifdef MODULE
  348. #undef MODULE        /* don't want to bother now! */
  349. #define MAX_ULTRAMCA_CARDS 4 /* Max number of Ultra cards per module */
  350. static struct net_device dev_ultra[MAX_ULTRAMCA_CARDS];
  351. static int io[MAX_ULTRAMCA_CARDS];
  352. static int irq[MAX_ULTRAMCA_CARDS];
  353. MODULE_LICENSE("GPL");
  354. MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
  355. MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRAMCA_CARDS) "i");
  356. MODULE_PARM_DESC(io, "SMC Ultra/EtherEZ MCA I/O base address(es)");
  357. MODULE_PARM_DESC(irq, "SMC Ultra/EtherEZ MCA IRQ number(s)");
  358. int init_module(void)
  359. {
  360. int this_dev, found = 0;
  361. for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
  362. struct net_device *dev = &dev_ultra[this_dev];
  363. dev->irq = irq[this_dev];
  364. dev->base_addr = io[this_dev];
  365. dev->init = ultramca_probe;
  366. if (register_netdev(dev) != 0) {
  367. if (found != 0) { /* Got at least one. */
  368. return 0;
  369. }
  370. printk(KERN_NOTICE "smc-mca.c: No SMC Ultra card found (i/o = 0x%x).n", io[this_dev]);
  371. return -ENXIO;
  372. }
  373. found++;
  374. }
  375. return 0;
  376. }
  377. void cleanup_module(void)
  378. {
  379. int this_dev;
  380. for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
  381. struct net_device *dev = &dev_ultra[this_dev];
  382. if (dev->priv != NULL) {
  383. void *priv = dev->priv;
  384. /* NB: ultra_close_card() does free_irq */
  385. int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
  386. mca_mark_as_unused(ei_status.priv);
  387. release_region(ioaddr, ULTRA_IO_EXTENT);
  388. unregister_netdev(dev);
  389. kfree(priv);
  390. }
  391. }
  392. }
  393. #endif /* MODULE */
  394. /*
  395.  * Local variables:
  396.  *  compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/inet -c smc-mca.c"
  397.  *  version-control: t
  398.  *  kept-new-versions: 5
  399.  *  c-indent-level: 8
  400.  *  tab-width: 8
  401.  * End:
  402.  */