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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Hardware-level driver for the COMX and HICOMX cards
  3.  * for Linux kernel 2.2.X
  4.  *
  5.  * Original authors:  Arpad Bakay <bakay.arpad@synergon.hu>,
  6.  *                    Peter Bajan <bajan.peter@synergon.hu>,
  7.  * Rewritten by: Tivadar Szemethy <tiv@itc.hu>
  8.  * Currently maintained by: Gergely Madarasz <gorgo@itc.hu>
  9.  *
  10.  * Copyright (C) 1995-2000 ITConsult-Pro Co. <info@itc.hu>
  11.  *
  12.  * Contributors:
  13.  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 0.86
  14.  *
  15.  * This program is free software; you can redistribute it and/or
  16.  * modify it under the terms of the GNU General Public License
  17.  * as published by the Free Software Foundation; either version
  18.  * 2 of the License, or (at your option) any later version.
  19.  *
  20.  * Version 0.80 (99/06/11):
  21.  * - port back to kernel, add support builtin driver 
  22.  * - cleaned up the source code a bit
  23.  *
  24.  * Version 0.81 (99/06/22):
  25.  * - cleaned up the board load functions, no more long reset
  26.  *   timeouts
  27.  * - lower modem lines on close
  28.  * - some interrupt handling fixes
  29.  *
  30.  * Version 0.82 (99/08/24):
  31.  * - fix multiple board support
  32.  *
  33.  * Version 0.83 (99/11/30):
  34.  * - interrupt handling and locking fixes during initalization
  35.  * - really fix multiple board support
  36.  * 
  37.  * Version 0.84 (99/12/02):
  38.  * - some workarounds for problematic hardware/firmware
  39.  *
  40.  * Version 0.85 (00/01/14):
  41.  * - some additional workarounds :/
  42.  * - printk cleanups
  43.  * Version 0.86 (00/08/15):
  44.  *  - resource release on failure at COMX_init
  45.  */
  46. #define VERSION "0.86"
  47. #include <linux/module.h>
  48. #include <linux/version.h>
  49. #include <linux/types.h>
  50. #include <linux/sched.h>
  51. #include <linux/netdevice.h>
  52. #include <linux/proc_fs.h>
  53. #include <linux/ioport.h>
  54. #include <linux/init.h>
  55. #include <linux/delay.h>
  56. #include <asm/uaccess.h>
  57. #include <asm/io.h>
  58. #include "comx.h"
  59. #include "comxhw.h"
  60. MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>, Tivadar Szemethy <tiv@itc.hu>, Arpad Bakay");
  61. MODULE_DESCRIPTION("Hardware-level driver for the COMX and HICOMX adaptersn");
  62. MODULE_LICENSE("GPL");
  63. #define COMX_readw(dev, offset) (readw(dev->mem_start + offset + 
  64. (unsigned int)(((struct comx_privdata *)
  65. ((struct comx_channel *)dev->priv)->HW_privdata)->channel) 
  66. * COMX_CHANNEL_OFFSET))
  67. #define COMX_WRITE(dev, offset, value) (writew(value, dev->mem_start + offset 
  68. + (unsigned int)(((struct comx_privdata *) 
  69. ((struct comx_channel *)dev->priv)->HW_privdata)->channel) 
  70. * COMX_CHANNEL_OFFSET))
  71. #define COMX_CMD(dev, cmd) (COMX_WRITE(dev, OFF_A_L2_CMD, cmd))
  72. struct comx_firmware {
  73. int len;
  74. unsigned char *data;
  75. };
  76. struct comx_privdata {
  77. struct comx_firmware *firmware;
  78. u16 clock;
  79. char channel; // channel no.
  80. int memory_size;
  81. short io_extent;
  82. u_long histogram[5];
  83. };
  84. static struct net_device *memory_used[(COMX_MEM_MAX - COMX_MEM_MIN) / 0x10000];
  85. extern struct comx_hardware hicomx_hw;
  86. extern struct comx_hardware comx_hw;
  87. extern struct comx_hardware cmx_hw;
  88. static void COMX_interrupt(int irq, void *dev_id, struct pt_regs *regs);
  89. static void COMX_board_on(struct net_device *dev)
  90. {
  91. outb_p( (byte) (((dev->mem_start & 0xf0000) >> 16) | 
  92.     COMX_ENABLE_BOARD_IT | COMX_ENABLE_BOARD_MEM), dev->base_addr);
  93. }
  94. static void COMX_board_off(struct net_device *dev)
  95. {
  96. outb_p( (byte) (((dev->mem_start & 0xf0000) >> 16) | 
  97.    COMX_ENABLE_BOARD_IT), dev->base_addr);
  98. }
  99. static void HICOMX_board_on(struct net_device *dev)
  100. {
  101. outb_p( (byte) (((dev->mem_start & 0xf0000) >> 12) | 
  102.    HICOMX_ENABLE_BOARD_MEM), dev->base_addr);
  103. }
  104. static void HICOMX_board_off(struct net_device *dev)
  105. {
  106. outb_p( (byte) (((dev->mem_start & 0xf0000) >> 12) | 
  107.    HICOMX_DISABLE_BOARD_MEM), dev->base_addr);
  108. }
  109. static void COMX_set_clock(struct net_device *dev)
  110. {
  111. struct comx_channel *ch = dev->priv;
  112. struct comx_privdata *hw = ch->HW_privdata;
  113. COMX_WRITE(dev, OFF_A_L1_CLKINI, hw->clock);
  114. }
  115. static struct net_device *COMX_access_board(struct net_device *dev)
  116. {
  117. struct comx_channel *ch = dev->priv;
  118. struct net_device *ret;
  119. int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16;
  120. unsigned long flags;
  121. save_flags(flags); cli();
  122. ret = memory_used[mempos];
  123. if(ret == dev) {
  124. goto out;
  125. }
  126. memory_used[mempos] = dev;
  127. if (!ch->twin || ret != ch->twin) {
  128. if (ret) ((struct comx_channel *)ret->priv)->HW_board_off(ret);
  129. ch->HW_board_on(dev);
  130. }
  131. out:
  132. restore_flags(flags);
  133. return ret;
  134. }
  135. static void COMX_release_board(struct net_device *dev, struct net_device *savep)
  136. {
  137. unsigned long flags;
  138. int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16;
  139. struct comx_channel *ch = dev->priv;
  140. save_flags(flags); cli();
  141. if (memory_used[mempos] == savep) {
  142. goto out;
  143. }
  144. memory_used[mempos] = savep;
  145. if (!ch->twin || ch->twin != savep) {
  146. ch->HW_board_off(dev);
  147. if (savep) ((struct comx_channel*)savep->priv)->HW_board_on(savep);
  148. }
  149. out:
  150. restore_flags(flags);
  151. }
  152. static int COMX_txe(struct net_device *dev) 
  153. {
  154. struct net_device *savep;
  155. struct comx_channel *ch = dev->priv;
  156. int rc = 0;
  157. savep = ch->HW_access_board(dev);
  158. if (COMX_readw(dev,OFF_A_L2_LINKUP) == LINKUP_READY) {
  159. rc = COMX_readw(dev,OFF_A_L2_TxEMPTY);
  160. ch->HW_release_board(dev,savep);
  161. if(rc==0xffff) {
  162. printk(KERN_ERR "%s, OFF_A_L2_TxEMPTY is %dn",dev->name, rc);
  163. }
  164. return rc;
  165. }
  166. static int COMX_send_packet(struct net_device *dev, struct sk_buff *skb)
  167. {
  168. struct net_device *savep;
  169. struct comx_channel *ch = dev->priv;
  170. struct comx_privdata *hw = ch->HW_privdata;
  171. int ret = FRAME_DROPPED;
  172. word tmp;
  173. savep = ch->HW_access_board(dev);
  174. if (ch->debug_flags & DEBUG_HW_TX) {
  175. comx_debug_bytes(dev, skb->data, skb->len,"COMX_send packet");
  176. }
  177. if (skb->len > COMX_MAX_TX_SIZE) {
  178. ret=FRAME_DROPPED;
  179. goto out;
  180. }
  181. tmp=COMX_readw(dev, OFF_A_L2_TxEMPTY);
  182. if ((ch->line_status & LINE_UP) && tmp==1) {
  183. int lensave = skb->len;
  184. int dest = COMX_readw(dev, OFF_A_L2_TxBUFP);
  185. word *data = (word *)skb->data;
  186. if(dest==0xffff) {
  187. printk(KERN_ERR "%s: OFF_A_L2_TxBUFP is %dn", dev->name, dest);
  188. ret=FRAME_DROPPED;
  189. goto out;
  190. }
  191. writew((unsigned short)skb->len, dev->mem_start + dest);
  192. dest += 2;
  193. while (skb->len > 1) {
  194. writew(*data++, dev->mem_start + dest);
  195. dest += 2; skb->len -= 2;
  196. }
  197. if (skb->len == 1) {
  198. writew(*((byte *)data), dev->mem_start + dest);
  199. }
  200. writew(0, dev->mem_start + (int)hw->channel * 
  201.    COMX_CHANNEL_OFFSET + OFF_A_L2_TxEMPTY);
  202. ch->stats.tx_packets++;
  203. ch->stats.tx_bytes += lensave; 
  204. ret = FRAME_ACCEPTED;
  205. } else {
  206. ch->stats.tx_dropped++;
  207. printk(KERN_INFO "%s: frame droppedn",dev->name);
  208. if(tmp) {
  209. printk(KERN_ERR "%s: OFF_A_L2_TxEMPTY is %dn",dev->name,tmp);
  210. }
  211. }
  212. out:
  213. ch->HW_release_board(dev, savep);
  214. dev_kfree_skb(skb);
  215. return ret;
  216. }
  217. static inline int comx_read_buffer(struct net_device *dev) 
  218. {
  219. struct comx_channel *ch = dev->priv;
  220. word rbuf_offs;
  221. struct sk_buff *skb;
  222. word len;
  223. int i=0;
  224. word *writeptr;
  225. i = 0;
  226. rbuf_offs = COMX_readw(dev, OFF_A_L2_RxBUFP);
  227. if(rbuf_offs == 0xffff) {
  228. printk(KERN_ERR "%s: OFF_A_L2_RxBUFP is %dn",dev->name,rbuf_offs);
  229. return 0;
  230. }
  231. len = readw(dev->mem_start + rbuf_offs);
  232. if(len > COMX_MAX_RX_SIZE) {
  233. printk(KERN_ERR "%s: packet length is %dn",dev->name,len);
  234. return 0;
  235. }
  236. if ((skb = dev_alloc_skb(len + 16)) == NULL) {
  237. ch->stats.rx_dropped++;
  238. COMX_WRITE(dev, OFF_A_L2_DAV, 0);
  239. return 0;
  240. }
  241. rbuf_offs += 2;
  242. skb_reserve(skb, 16);
  243. skb_put(skb, len);
  244. skb->dev = dev;
  245. writeptr = (word *)skb->data;
  246. while (i < len) {
  247. *writeptr++ = readw(dev->mem_start + rbuf_offs);
  248. rbuf_offs += 2; 
  249. i += 2;
  250. }
  251. COMX_WRITE(dev, OFF_A_L2_DAV, 0);
  252. ch->stats.rx_packets++;
  253. ch->stats.rx_bytes += len;
  254. if (ch->debug_flags & DEBUG_HW_RX) {
  255. comx_debug_skb(dev, skb, "COMX_interrupt receiving");
  256. }
  257. ch->LINE_rx(dev, skb);
  258. return 1;
  259. }
  260. static inline char comx_line_change(struct net_device *dev, char linestat)
  261. {
  262. struct comx_channel *ch=dev->priv;
  263. char idle=1;
  264. if (linestat & LINE_UP) { /* Vonal fol */
  265. if (ch->lineup_delay) {
  266. if (!test_and_set_bit(0, &ch->lineup_pending)) {
  267. ch->lineup_timer.function = comx_lineup_func;
  268. ch->lineup_timer.data = (unsigned long)dev;
  269. ch->lineup_timer.expires = jiffies +
  270. HZ*ch->lineup_delay;
  271. add_timer(&ch->lineup_timer);
  272. idle=0;
  273. }
  274. } else {
  275. idle=0;
  276. ch->LINE_status(dev, ch->line_status |= LINE_UP);
  277. }
  278. } else { /* Vonal le */
  279. idle=0;
  280. if (test_and_clear_bit(0, &ch->lineup_pending)) {
  281. del_timer(&ch->lineup_timer);
  282. } else {
  283. ch->line_status &= ~LINE_UP;
  284. if (ch->LINE_status) {
  285. ch->LINE_status(dev, ch->line_status);
  286. }
  287. }
  288. }
  289. return idle;
  290. }
  291. static void COMX_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  292. {
  293. struct net_device *dev = dev_id;
  294. struct comx_channel *ch = dev->priv;
  295. struct comx_privdata *hw = ch->HW_privdata;
  296. struct net_device *interrupted;
  297. unsigned long jiffs;
  298. char idle = 0;
  299. int count = 0;
  300. word tmp;
  301. if (dev == NULL) {
  302. printk(KERN_ERR "COMX_interrupt: irq %d for unknown devicen", irq);
  303. return;
  304. }
  305. jiffs = jiffies;
  306. interrupted = ch->HW_access_board(dev);
  307. while (!idle && count < 5000) {
  308. char channel = 0;
  309. idle = 1;
  310. while (channel < 2) {
  311. char linestat = 0;
  312. char buffers_emptied = 0;
  313. if (channel == 1) {
  314. if (ch->twin) {
  315. dev = ch->twin;
  316. ch = dev->priv;
  317. hw = ch->HW_privdata;
  318. } else {
  319. break;
  320. }
  321. } else {
  322. COMX_WRITE(dev, OFF_A_L1_REPENA, 
  323.     COMX_readw(dev, OFF_A_L1_REPENA) & 0xFF00);
  324. }
  325. channel++;
  326. if ((ch->init_status & (HW_OPEN | LINE_OPEN)) != 
  327.    (HW_OPEN | LINE_OPEN)) {
  328. continue;
  329. }
  330. /* Collect stats */
  331. tmp = COMX_readw(dev, OFF_A_L1_ABOREC);
  332. COMX_WRITE(dev, OFF_A_L1_ABOREC, 0);
  333. if(tmp==0xffff) {
  334. printk(KERN_ERR "%s: OFF_A_L1_ABOREC is %dn",dev->name,tmp);
  335. break;
  336. } else {
  337. ch->stats.rx_missed_errors += (tmp >> 8) & 0xff;
  338. ch->stats.rx_over_errors += tmp & 0xff;
  339. }
  340. tmp = COMX_readw(dev, OFF_A_L1_CRCREC);
  341. COMX_WRITE(dev, OFF_A_L1_CRCREC, 0);
  342. if(tmp==0xffff) {
  343. printk(KERN_ERR "%s: OFF_A_L1_CRCREC is %dn",dev->name,tmp);
  344. break;
  345. } else {
  346. ch->stats.rx_crc_errors += (tmp >> 8) & 0xff;
  347. ch->stats.rx_missed_errors += tmp & 0xff;
  348. }
  349. if ((ch->line_status & LINE_UP) && ch->LINE_rx) {
  350. tmp=COMX_readw(dev, OFF_A_L2_DAV); 
  351. while (tmp==1) {
  352. idle=0;
  353. buffers_emptied+=comx_read_buffer(dev);
  354. tmp=COMX_readw(dev, OFF_A_L2_DAV); 
  355. }
  356. if(tmp) {
  357. printk(KERN_ERR "%s: OFF_A_L2_DAV is %dn", dev->name, tmp);
  358. break;
  359. }
  360. }
  361. tmp=COMX_readw(dev, OFF_A_L2_TxEMPTY);
  362. if (tmp==1 && ch->LINE_tx) {
  363. ch->LINE_tx(dev);
  364. if(tmp==0xffff) {
  365. printk(KERN_ERR "%s: OFF_A_L2_TxEMPTY is %dn", dev->name, tmp);
  366. break;
  367. }
  368. if (COMX_readw(dev, OFF_A_L1_PBUFOVR) >> 8) {
  369. linestat &= ~LINE_UP;
  370. } else {
  371. linestat |= LINE_UP;
  372. }
  373. if ((linestat & LINE_UP) != (ch->line_status & LINE_UP)) {
  374. ch->stats.tx_carrier_errors++;
  375. idle &= comx_line_change(dev,linestat);
  376. }
  377. hw->histogram[(int)buffers_emptied]++;
  378. }
  379. count++;
  380. }
  381. if(count==5000) {
  382. printk(KERN_WARNING "%s: interrupt stuckn",dev->name);
  383. }
  384. ch->HW_release_board(dev, interrupted);
  385. }
  386. static int COMX_open(struct net_device *dev)
  387. {
  388. struct comx_channel *ch = dev->priv;
  389. struct comx_privdata *hw = ch->HW_privdata;
  390. struct proc_dir_entry *procfile = ch->procdir->subdir;
  391. unsigned long jiffs;
  392. int twin_open=0;
  393. int retval;
  394. struct net_device *savep;
  395. if (!dev->base_addr || !dev->irq || !dev->mem_start) {
  396. return -ENODEV;
  397. }
  398. if (ch->twin && (((struct comx_channel *)(ch->twin->priv))->init_status & HW_OPEN)) {
  399. twin_open=1;
  400. }
  401. if (!twin_open) {
  402. if (!request_region(dev->base_addr, hw->io_extent, dev->name)) {
  403. return -EAGAIN;
  404. }
  405. if (request_irq(dev->irq, COMX_interrupt, 0, dev->name, 
  406.    (void *)dev)) {
  407. printk(KERN_ERR "comx-hw-comx: unable to obtain irq %dn", dev->irq);
  408. release_region(dev->base_addr, hw->io_extent);
  409. return -EAGAIN;
  410. }
  411. ch->init_status |= IRQ_ALLOCATED;
  412. if (!ch->HW_load_board || ch->HW_load_board(dev)) {
  413. ch->init_status &= ~IRQ_ALLOCATED;
  414. retval=-ENODEV;
  415. goto error;
  416. }
  417. }
  418. savep = ch->HW_access_board(dev);
  419. COMX_WRITE(dev, OFF_A_L2_LINKUP, 0);
  420. if (ch->HW_set_clock) {
  421. ch->HW_set_clock(dev);
  422. }
  423. COMX_CMD(dev, COMX_CMD_INIT); 
  424. jiffs = jiffies;
  425. while (COMX_readw(dev, OFF_A_L2_LINKUP) != 1 && jiffies < jiffs + HZ) {
  426. schedule_timeout(1);
  427. }
  428. if (jiffies >= jiffs + HZ) {
  429. printk(KERN_ERR "%s: board timeout on INIT commandn", dev->name);
  430. ch->HW_release_board(dev, savep);
  431. retval=-EIO;
  432. goto error;
  433. }
  434. udelay(1000);
  435. COMX_CMD(dev, COMX_CMD_OPEN);
  436. jiffs = jiffies;
  437. while (COMX_readw(dev, OFF_A_L2_LINKUP) != 3 && jiffies < jiffs + HZ) {
  438. schedule_timeout(1);
  439. }
  440. if (jiffies >= jiffs + HZ) {
  441. printk(KERN_ERR "%s: board timeout on OPEN commandn", dev->name);
  442. ch->HW_release_board(dev, savep);
  443. retval=-EIO;
  444. goto error;
  445. }
  446. ch->init_status |= HW_OPEN;
  447. /* Ez eleg ciki, de ilyen a rendszer */
  448. if (COMX_readw(dev, OFF_A_L1_PBUFOVR) >> 8) {
  449. ch->line_status &= ~LINE_UP;
  450. } else {
  451. ch->line_status |= LINE_UP;
  452. }
  453. if (ch->LINE_status) {
  454. ch->LINE_status(dev, ch->line_status);
  455. }
  456. ch->HW_release_board(dev, savep);
  457. for ( ; procfile ; procfile = procfile->next) {
  458. if (strcmp(procfile->name, FILENAME_IRQ) == 0 
  459.     || strcmp(procfile->name, FILENAME_IO) == 0
  460.     || strcmp(procfile->name, FILENAME_MEMADDR) == 0
  461.     || strcmp(procfile->name, FILENAME_CHANNEL) == 0
  462.     || strcmp(procfile->name, FILENAME_FIRMWARE) == 0
  463.     || strcmp(procfile->name, FILENAME_CLOCK) == 0) {
  464. procfile->mode = S_IFREG | 0444;
  465. }
  466. }
  467. return 0;
  468. error:
  469. if(!twin_open) {
  470. release_region(dev->base_addr, hw->io_extent);
  471. free_irq(dev->irq, (void *)dev);
  472. }
  473. return retval;
  474. }
  475. static int COMX_close(struct net_device *dev)
  476. {
  477. struct comx_channel *ch = dev->priv;
  478. struct proc_dir_entry *procfile = ch->procdir->subdir;
  479. struct comx_privdata *hw = ch->HW_privdata;
  480. struct comx_channel *twin_ch;
  481. struct net_device *savep;
  482. savep = ch->HW_access_board(dev);
  483. COMX_CMD(dev, COMX_CMD_CLOSE);
  484. udelay(1000);
  485. COMX_CMD(dev, COMX_CMD_EXIT);
  486. ch->HW_release_board(dev, savep);
  487. if (ch->init_status & IRQ_ALLOCATED) {
  488. free_irq(dev->irq, (void *)dev);
  489. ch->init_status &= ~IRQ_ALLOCATED;
  490. }
  491. release_region(dev->base_addr, hw->io_extent);
  492. if (ch->twin && (twin_ch = ch->twin->priv) && 
  493.     (twin_ch->init_status & HW_OPEN)) {
  494. /* Pass the irq to the twin */
  495. if (request_irq(dev->irq, COMX_interrupt, 0, ch->twin->name, 
  496.    (void *)ch->twin) == 0) {
  497. twin_ch->init_status |= IRQ_ALLOCATED;
  498. }
  499. }
  500. for ( ; procfile ; procfile = procfile->next) {
  501. if (strcmp(procfile->name, FILENAME_IRQ) == 0 
  502.     || strcmp(procfile->name, FILENAME_IO) == 0
  503.     || strcmp(procfile->name, FILENAME_MEMADDR) == 0
  504.     || strcmp(procfile->name, FILENAME_CHANNEL) == 0
  505.     || strcmp(procfile->name, FILENAME_FIRMWARE) == 0
  506.     || strcmp(procfile->name, FILENAME_CLOCK) == 0) {
  507. procfile->mode = S_IFREG | 0644;
  508. }
  509. }
  510. ch->init_status &= ~HW_OPEN;
  511. return 0;
  512. }
  513. static int COMX_statistics(struct net_device *dev, char *page)
  514. {
  515. struct comx_channel *ch = dev->priv;
  516. struct comx_privdata *hw = ch->HW_privdata;
  517. struct net_device *savep;
  518. int len = 0;
  519. savep = ch->HW_access_board(dev);
  520. len += sprintf(page + len, "Board data: %s %s %s %snPBUFOVR: %02x, "
  521. "MODSTAT: %02x, LINKUP: %02x, DAV: %02xnRxBUFP: %02x, "
  522. "TxEMPTY: %02x, TxBUFP: %02xn",
  523. (ch->init_status & HW_OPEN) ? "HW_OPEN" : "",
  524. (ch->init_status & LINE_OPEN) ? "LINE_OPEN" : "",
  525. (ch->init_status & FW_LOADED) ? "FW_LOADED" : "",
  526. (ch->init_status & IRQ_ALLOCATED) ? "IRQ_ALLOCATED" : "",
  527. COMX_readw(dev, OFF_A_L1_PBUFOVR) & 0xff,
  528. (COMX_readw(dev, OFF_A_L1_PBUFOVR) >> 8) & 0xff,
  529. COMX_readw(dev, OFF_A_L2_LINKUP) & 0xff,
  530. COMX_readw(dev, OFF_A_L2_DAV) & 0xff,
  531. COMX_readw(dev, OFF_A_L2_RxBUFP) & 0xff,
  532. COMX_readw(dev, OFF_A_L2_TxEMPTY) & 0xff,
  533. COMX_readw(dev, OFF_A_L2_TxBUFP) & 0xff);
  534. len += sprintf(page + len, "hist[0]: %8lu hist[1]: %8lu hist[2]: %8lun"
  535. "hist[3]: %8lu hist[4]: %8lun",hw->histogram[0],hw->histogram[1],
  536. hw->histogram[2],hw->histogram[3],hw->histogram[4]);
  537. ch->HW_release_board(dev, savep);
  538. return len;
  539. }
  540. static int COMX_load_board(struct net_device *dev)
  541. {
  542. struct comx_channel *ch = dev->priv;
  543. struct comx_privdata *hw = ch->HW_privdata;
  544. struct comx_firmware *fw = hw->firmware;
  545. word board_segment = dev->mem_start >> 16;
  546. int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16;
  547. unsigned long flags;
  548. unsigned char id1, id2;
  549. struct net_device *saved;
  550. int retval;
  551. int loopcount;
  552. int len;
  553. byte *COMX_address;
  554. if (!fw || !fw->len) {
  555. struct comx_channel *twin_ch = ch->twin ? ch->twin->priv : NULL;
  556. struct comx_privdata *twin_hw;
  557. if (!twin_ch || !(twin_hw = twin_ch->HW_privdata)) {
  558. return -EAGAIN;
  559. }
  560. if (!(fw = twin_hw->firmware) || !fw->len) {
  561. return -EAGAIN;
  562. }
  563. }
  564. id1 = fw->data[OFF_FW_L1_ID]; 
  565. id2 = fw->data[OFF_FW_L1_ID + 1];
  566. if (id1 != FW_L1_ID_1 || id2 != FW_L1_ID_2_COMX) {
  567. printk(KERN_ERR "%s: incorrect firmware, load abortedn", 
  568. dev->name);
  569. return -EAGAIN;
  570. }
  571. printk(KERN_INFO "%s: Loading COMX Layer 1 firmware %sn", dev->name, 
  572. (char *)(fw->data + OFF_FW_L1_ID + 2));
  573. id1 = fw->data[OFF_FW_L2_ID]; 
  574. id2 = fw->data[OFF_FW_L2_ID + 1];
  575. if (id1 == FW_L2_ID_1 && (id2 == 0xc0 || id2 == 0xc1 || id2 == 0xc2)) {
  576. printk(KERN_INFO "with Layer 2 code %sn", 
  577. (char *)(fw->data + OFF_FW_L2_ID + 2));
  578. }
  579. outb_p(board_segment | COMX_BOARD_RESET, dev->base_addr);
  580. /* 10 usec should be enough here */
  581. udelay(100);
  582. save_flags(flags); cli();
  583. saved=memory_used[mempos];
  584. if(saved) {
  585. ((struct comx_channel *)saved->priv)->HW_board_off(saved);
  586. }
  587. memory_used[mempos]=dev;
  588. outb_p(board_segment | COMX_ENABLE_BOARD_MEM, dev->base_addr);
  589. writeb(0, dev->mem_start + COMX_JAIL_OFFSET);
  590. loopcount=0;
  591. while(loopcount++ < 10000 && 
  592.     readb(dev->mem_start + COMX_JAIL_OFFSET) != COMX_JAIL_VALUE) {
  593. udelay(100);
  594. }
  595. if (readb(dev->mem_start + COMX_JAIL_OFFSET) != COMX_JAIL_VALUE) {
  596. printk(KERN_ERR "%s: Can't reset board, JAIL value is %02xn",
  597. dev->name, readb(dev->mem_start + COMX_JAIL_OFFSET));
  598. retval=-ENODEV;
  599. goto out;
  600. }
  601. writeb(0x55, dev->mem_start + 0x18ff);
  602. loopcount=0;
  603. while(loopcount++ < 10000 && readb(dev->mem_start + 0x18ff) != 0) {
  604. udelay(100);
  605. }
  606. if(readb(dev->mem_start + 0x18ff) != 0) {
  607. printk(KERN_ERR "%s: Can't reset board, reset timeoutn",
  608. dev->name);
  609. retval=-ENODEV;
  610. goto out;
  611. }
  612. len = 0;
  613. COMX_address = (byte *)dev->mem_start;
  614. while (fw->len > len) {
  615. writeb(fw->data[len++], COMX_address++);
  616. }
  617. len = 0;
  618. COMX_address = (byte *)dev->mem_start;
  619. while (len != fw->len && readb(COMX_address++) == fw->data[len]) {
  620. len++;
  621. }
  622. if (len != fw->len) {
  623. printk(KERN_ERR "%s: error loading firmware: [%d] is 0x%02x "
  624. "instead of 0x%02xn", dev->name, len, 
  625. readb(COMX_address - 1), fw->data[len]);
  626. retval=-EAGAIN;
  627. goto out;
  628. }
  629. writeb(0, dev->mem_start + COMX_JAIL_OFFSET);
  630. loopcount = 0;
  631. while ( loopcount++ < 10000 && COMX_readw(dev, OFF_A_L2_LINKUP) != 1 ) {
  632. udelay(100);
  633. }
  634. if (COMX_readw(dev, OFF_A_L2_LINKUP) != 1) {
  635. printk(KERN_ERR "%s: error starting firmware, linkup word is %04xn",
  636. dev->name, COMX_readw(dev, OFF_A_L2_LINKUP));
  637. retval=-EAGAIN;
  638. goto out;
  639. }
  640. ch->init_status |= FW_LOADED;
  641. retval=0;
  642. out: 
  643. outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr);
  644. if(saved) {
  645. ((struct comx_channel *)saved->priv)->HW_board_on(saved);
  646. }
  647. memory_used[mempos]=saved;
  648. restore_flags(flags);
  649. return retval;
  650. }
  651. static int CMX_load_board(struct net_device *dev)
  652. {
  653. struct comx_channel *ch = dev->priv;
  654. struct comx_privdata *hw = ch->HW_privdata;
  655. struct comx_firmware *fw = hw->firmware;
  656. word board_segment = dev->mem_start >> 16;
  657. int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16;
  658. #if 0
  659. unsigned char id1, id2;
  660. #endif
  661. struct net_device *saved;
  662. unsigned long flags;
  663. int retval;
  664. int loopcount;
  665. int len;
  666. byte *COMX_address;
  667. if (!fw || !fw->len) {
  668. struct comx_channel *twin_ch = ch->twin ? ch->twin->priv : NULL;
  669. struct comx_privdata *twin_hw;
  670. if (!twin_ch || !(twin_hw = twin_ch->HW_privdata)) {
  671. return -EAGAIN;
  672. }
  673. if (!(fw = twin_hw->firmware) || !fw->len) {
  674. return -EAGAIN;
  675. }
  676. }
  677. /* Ide kell olyat tenni, hogy ellenorizze az ID-t */
  678. if (inb_p(dev->base_addr) != CMX_ID_BYTE) {
  679. printk(KERN_ERR "%s: CMX id byte is invalid(%02x)n", dev->name,
  680. inb_p(dev->base_addr));
  681. return -ENODEV;
  682. }
  683. printk(KERN_INFO "%s: Loading CMX Layer 1 firmware %sn", dev->name, 
  684. (char *)(fw->data + OFF_FW_L1_ID + 2));
  685. save_flags(flags); cli();
  686. saved=memory_used[mempos];
  687. if(saved) {
  688. ((struct comx_channel *)saved->priv)->HW_board_off(saved);
  689. }
  690. memory_used[mempos]=dev;
  691. outb_p(board_segment | COMX_ENABLE_BOARD_MEM | COMX_BOARD_RESET, 
  692. dev->base_addr);
  693. len = 0;
  694. COMX_address = (byte *)dev->mem_start;
  695. while (fw->len > len) {
  696. writeb(fw->data[len++], COMX_address++);
  697. }
  698. len = 0;
  699. COMX_address = (byte *)dev->mem_start;
  700. while (len != fw->len && readb(COMX_address++) == fw->data[len]) {
  701. len++;
  702. }
  703. outb_p(board_segment | COMX_ENABLE_BOARD_MEM, dev->base_addr);
  704. if (len != fw->len) {
  705. printk(KERN_ERR "%s: error loading firmware: [%d] is 0x%02x "
  706. "instead of 0x%02xn", dev->name, len, 
  707. readb(COMX_address - 1), fw->data[len]);
  708. retval=-EAGAIN;
  709. goto out;
  710. }
  711. loopcount=0;
  712. while( loopcount++ < 10000 && COMX_readw(dev, OFF_A_L2_LINKUP) != 1 ) {
  713. udelay(100);
  714. }
  715. if (COMX_readw(dev, OFF_A_L2_LINKUP) != 1) {
  716. printk(KERN_ERR "%s: error starting firmware, linkup word is %04xn",
  717. dev->name, COMX_readw(dev, OFF_A_L2_LINKUP));
  718. retval=-EAGAIN;
  719. goto out;
  720. }
  721. ch->init_status |= FW_LOADED;
  722. retval=0;
  723. out: 
  724. outb_p(board_segment | COMX_DISABLE_ALL, dev->base_addr);
  725. if(saved) {
  726. ((struct comx_channel *)saved->priv)->HW_board_on(saved);
  727. }
  728. memory_used[mempos]=saved;
  729. restore_flags(flags);
  730. return retval;
  731. }
  732. static int HICOMX_load_board(struct net_device *dev)
  733. {
  734. struct comx_channel *ch = dev->priv;
  735. struct comx_privdata *hw = ch->HW_privdata;
  736. struct comx_firmware *fw = hw->firmware;
  737. word board_segment = dev->mem_start >> 12;
  738. int mempos = (dev->mem_start - COMX_MEM_MIN) >> 16;
  739. struct net_device *saved;
  740. unsigned char id1, id2;
  741. unsigned long flags;
  742. int retval;
  743. int loopcount;
  744. int len;
  745. word *HICOMX_address;
  746. char id = 1;
  747. if (!fw || !fw->len) {
  748. struct comx_channel *twin_ch = ch->twin ? ch->twin->priv : NULL;
  749. struct comx_privdata *twin_hw;
  750. if (!twin_ch || !(twin_hw = twin_ch->HW_privdata)) {
  751. return -EAGAIN;
  752. }
  753. if (!(fw = twin_hw->firmware) || !fw->len) {
  754. return -EAGAIN;
  755. }
  756. }
  757. while (id != 4) {
  758. if (inb_p(dev->base_addr + id++) != HICOMX_ID_BYTE) {
  759. break;
  760. }
  761. }
  762. if (id != 4) {
  763. printk(KERN_ERR "%s: can't find HICOMX at 0x%04x, id[%d] = %02xn",
  764. dev->name, (unsigned int)dev->base_addr, id - 1,
  765. inb_p(dev->base_addr + id - 1));
  766. return -1;
  767. }
  768. id1 = fw->data[OFF_FW_L1_ID]; 
  769. id2 = fw->data[OFF_FW_L1_ID + 1];
  770. if (id1 != FW_L1_ID_1 || id2 != FW_L1_ID_2_HICOMX) {
  771. printk(KERN_ERR "%s: incorrect firmware, load abortedn", dev->name);
  772. return -EAGAIN;
  773. }
  774. printk(KERN_INFO "%s: Loading HICOMX Layer 1 firmware %sn", dev->name, 
  775. (char *)(fw->data + OFF_FW_L1_ID + 2));
  776. id1 = fw->data[OFF_FW_L2_ID]; 
  777. id2 = fw->data[OFF_FW_L2_ID + 1];
  778. if (id1 == FW_L2_ID_1 && (id2 == 0xc0 || id2 == 0xc1 || id2 == 0xc2)) {
  779. printk(KERN_INFO "with Layer 2 code %sn", 
  780. (char *)(fw->data + OFF_FW_L2_ID + 2));
  781. }
  782. outb_p(board_segment | HICOMX_BOARD_RESET, dev->base_addr);
  783. udelay(10);
  784. save_flags(flags); cli();
  785. saved=memory_used[mempos];
  786. if(saved) {
  787. ((struct comx_channel *)saved->priv)->HW_board_off(saved);
  788. }
  789. memory_used[mempos]=dev;
  790. outb_p(board_segment | HICOMX_ENABLE_BOARD_MEM, dev->base_addr);
  791. outb_p(HICOMX_PRG_MEM, dev->base_addr + 1);
  792. len = 0;
  793. HICOMX_address = (word *)dev->mem_start;
  794. while (fw->len > len) {
  795. writeb(fw->data[len++], HICOMX_address++);
  796. }
  797. len = 0;
  798. HICOMX_address = (word *)dev->mem_start;
  799. while (len != fw->len && (readw(HICOMX_address++) & 0xff) == fw->data[len]) {
  800. len++;
  801. }
  802. if (len != fw->len) {
  803. printk(KERN_ERR "%s: error loading firmware: [%d] is 0x%02x "
  804. "instead of 0x%02xn", dev->name, len, 
  805. readw(HICOMX_address - 1) & 0xff, fw->data[len]);
  806. retval=-EAGAIN;
  807. goto out;
  808. }
  809. outb_p(board_segment | HICOMX_BOARD_RESET, dev->base_addr);
  810. outb_p(HICOMX_DATA_MEM, dev->base_addr + 1);
  811. outb_p(board_segment | HICOMX_ENABLE_BOARD_MEM, dev->base_addr);
  812. loopcount=0;
  813. while(loopcount++ < 10000 && COMX_readw(dev, OFF_A_L2_LINKUP) != 1) {
  814. udelay(100);
  815. }
  816. if ( COMX_readw(dev, OFF_A_L2_LINKUP) != 1 ) {
  817. printk(KERN_ERR "%s: error starting firmware, linkup word is %04xn",
  818. dev->name, COMX_readw(dev, OFF_A_L2_LINKUP));
  819. retval=-EAGAIN;
  820. goto out;
  821. }
  822. ch->init_status |= FW_LOADED;
  823. retval=0;
  824. out:
  825. outb_p(board_segment | HICOMX_DISABLE_ALL, dev->base_addr);
  826. outb_p(HICOMX_DATA_MEM, dev->base_addr + 1);
  827. if(saved) {
  828. ((struct comx_channel *)saved->priv)->HW_board_on(saved);
  829. }
  830. memory_used[mempos]=saved;
  831. restore_flags(flags);
  832. return retval;
  833. }
  834. static struct net_device *comx_twin_check(struct net_device *dev)
  835. {
  836. struct comx_channel *ch = dev->priv;
  837. struct proc_dir_entry *procfile = ch->procdir->parent->subdir;
  838. struct comx_privdata *hw = ch->HW_privdata;
  839. struct net_device *twin;
  840. struct comx_channel *ch_twin;
  841. struct comx_privdata *hw_twin;
  842. for ( ; procfile ; procfile = procfile->next) {
  843. if(!S_ISDIR(procfile->mode)) {
  844. continue;
  845. }
  846. twin=procfile->data;
  847. ch_twin=twin->priv;
  848. hw_twin=ch_twin->HW_privdata;
  849. if (twin != dev && dev->irq && dev->base_addr && dev->mem_start &&
  850.    dev->irq == twin->irq && dev->base_addr == twin->base_addr &&
  851.       dev->mem_start == twin->mem_start &&
  852.    hw->channel == (1 - hw_twin->channel) &&
  853.    ch->hardware == ch_twin->hardware) {
  854.     return twin;
  855. }
  856. }
  857. return NULL;
  858. }
  859. static int comxhw_write_proc(struct file *file, const char *buffer, 
  860. u_long count, void *data)
  861. {
  862. struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
  863. struct net_device *dev = entry->parent->data;
  864. struct comx_channel *ch = dev->priv;
  865. struct comx_privdata *hw = ch->HW_privdata;
  866. char *page;
  867. if(ch->init_status & HW_OPEN) {
  868. return -EAGAIN;
  869. }
  870. if (strcmp(FILENAME_FIRMWARE, entry->name) != 0) {
  871. if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
  872. return -ENOMEM;
  873. }
  874. if(copy_from_user(page, buffer, count = (min_t(int, count, PAGE_SIZE))))
  875. {
  876. count = -EFAULT;
  877. goto out;
  878. }
  879. if (page[count-1] == 'n')
  880. page[count-1] = '';
  881. else if (count < PAGE_SIZE)
  882. page[count] = '';
  883. else if (page[count]) {
  884.   count = -EINVAL;
  885. goto out;
  886. }
  887. page[count]=0; /* Null terminate */
  888. } else {
  889. byte *tmp;
  890. if (!hw->firmware) {
  891. if ((hw->firmware = kmalloc(sizeof(struct comx_firmware), 
  892.     GFP_KERNEL)) == NULL) {
  893.      return -ENOMEM;
  894. }
  895. hw->firmware->len = 0;
  896. hw->firmware->data = NULL;
  897. }
  898. if ((tmp = kmalloc(count + file->f_pos, GFP_KERNEL)) == NULL) {
  899. return -ENOMEM;
  900. }
  901. /* Ha nem 0 a fpos, akkor meglevo file-t irunk. Gyenge trukk. */
  902. if (hw->firmware && hw->firmware->len && file->f_pos 
  903.     && hw->firmware->len < count + file->f_pos) {
  904. memcpy(tmp, hw->firmware->data, hw->firmware->len);
  905. }
  906. if (hw->firmware->data) {
  907. kfree(hw->firmware->data);
  908. }
  909. copy_from_user(tmp + file->f_pos, buffer, count);
  910. hw->firmware->len = entry->size = file->f_pos + count;
  911. hw->firmware->data = tmp;
  912. file->f_pos += count;
  913. return count;
  914. }
  915. if (strcmp(entry->name, FILENAME_CHANNEL) == 0) {
  916. hw->channel = simple_strtoul(page, NULL, 0);
  917. if (hw->channel >= MAX_CHANNELNO) {
  918. printk(KERN_ERR "Invalid channel numbern");
  919. hw->channel = 0;
  920. }
  921. if ((ch->twin = comx_twin_check(dev)) != NULL) {
  922. struct comx_channel *twin_ch = ch->twin->priv;
  923. twin_ch->twin = dev;
  924. }
  925. } else if (strcmp(entry->name, FILENAME_IRQ) == 0) {
  926. dev->irq = simple_strtoul(page, NULL, 0);
  927. if (dev->irq == 2) {
  928. dev->irq = 9;
  929. }
  930. if (dev->irq < 3 || dev->irq > 15) {
  931. printk(KERN_ERR "comxhw: Invalid irq numbern");
  932. dev->irq = 0;
  933. }
  934. if ((ch->twin = comx_twin_check(dev)) != NULL) {
  935. struct comx_channel *twin_ch = ch->twin->priv;
  936. twin_ch->twin = dev;
  937. }
  938. } else if (strcmp(entry->name, FILENAME_IO) == 0) {
  939. dev->base_addr = simple_strtoul(page, NULL, 0);
  940. if ((dev->base_addr & 3) != 0 || dev->base_addr < 0x300 
  941.    || dev->base_addr > 0x3fc) {
  942. printk(KERN_ERR "Invalid io valuen");
  943. dev->base_addr = 0;
  944. }
  945. if ((ch->twin = comx_twin_check(dev)) != NULL) {
  946. struct comx_channel *twin_ch = ch->twin->priv;
  947. twin_ch->twin = dev;
  948. }
  949. } else if (strcmp(entry->name, FILENAME_MEMADDR) == 0) {
  950. dev->mem_start = simple_strtoul(page, NULL, 0);
  951. if (dev->mem_start <= 0xf000 && dev->mem_start >= 0xa000) {
  952. dev->mem_start *= 16;
  953. }
  954. if ((dev->mem_start & 0xfff) != 0 || dev->mem_start < COMX_MEM_MIN
  955.     || dev->mem_start + hw->memory_size > COMX_MEM_MAX) {
  956. printk(KERN_ERR "Invalid memory pagen");
  957. dev->mem_start = 0;
  958. }
  959. dev->mem_end = dev->mem_start + hw->memory_size;
  960. if ((ch->twin = comx_twin_check(dev)) != NULL) {
  961. struct comx_channel *twin_ch = ch->twin->priv;
  962. twin_ch->twin = dev;
  963. }
  964. } else if (strcmp(entry->name, FILENAME_CLOCK) == 0) {
  965. if (strncmp("ext", page, 3) == 0) {
  966. hw->clock = 0;
  967. } else {
  968. int kbps;
  969. kbps = simple_strtoul(page, NULL, 0);
  970. hw->clock = kbps ? COMX_CLOCK_CONST/kbps : 0;
  971. }
  972. }
  973. out:
  974. free_page((unsigned long)page);
  975. return count;
  976. }
  977. static int comxhw_read_proc(char *page, char **start, off_t off, int count,
  978. int *eof, void *data)
  979. {
  980. struct proc_dir_entry *file = (struct proc_dir_entry *)data;
  981. struct net_device *dev = file->parent->data;
  982. struct comx_channel *ch = dev->priv;
  983. struct comx_privdata *hw = ch->HW_privdata;
  984. int len = 0;
  985. if (strcmp(file->name, FILENAME_IO) == 0) {
  986. len = sprintf(page, "0x%03xn", (unsigned int)dev->base_addr);
  987. } else if (strcmp(file->name, FILENAME_IRQ) == 0) {
  988. len = sprintf(page, "0x%02xn", dev->irq == 9 ? 2 : dev->irq);
  989. } else if (strcmp(file->name, FILENAME_CHANNEL) == 0) {
  990. len = sprintf(page, "%01dn", hw->channel);
  991. } else if (strcmp(file->name, FILENAME_MEMADDR) == 0) {
  992. len = sprintf(page, "0x%05xn", (unsigned int)dev->mem_start);
  993. } else if (strcmp(file->name, FILENAME_TWIN) == 0) {
  994. len = sprintf(page, "%sn", ch->twin ? ch->twin->name : "none");
  995. } else if (strcmp(file->name, FILENAME_CLOCK) == 0) {
  996. if (hw->clock) {
  997. len = sprintf(page, "%-8dn", COMX_CLOCK_CONST/hw->clock);
  998. } else {
  999. len = sprintf(page, "externaln");
  1000. }
  1001. } else if (strcmp(file->name, FILENAME_FIRMWARE) == 0) {
  1002. len = min_t(int, FILE_PAGESIZE,
  1003.   min_t(int, count, 
  1004.       hw->firmware ?
  1005.       (hw->firmware->len - off) : 0));
  1006. if (len < 0) {
  1007. len = 0;
  1008. }
  1009. *start = hw->firmware ? (hw->firmware->data + off) : NULL;
  1010. if (off + len >= (hw->firmware ? hw->firmware->len : 0) || len == 0) {
  1011. *eof = 1;
  1012. }
  1013. return len;
  1014. }
  1015. if (off >= len) {
  1016. *eof = 1;
  1017. return 0;
  1018. }
  1019. *start = page + off;
  1020. if (count >= len - off) {
  1021. *eof = 1;
  1022. }
  1023. return min_t(int, count, len - off);
  1024. }
  1025. /* Called on echo comx >boardtype */
  1026. static int COMX_init(struct net_device *dev)
  1027. {
  1028. struct comx_channel *ch = dev->priv;
  1029. struct comx_privdata *hw;
  1030. struct proc_dir_entry *new_file;
  1031. if ((ch->HW_privdata = kmalloc(sizeof(struct comx_privdata), 
  1032.     GFP_KERNEL)) == NULL) {
  1033.      return -ENOMEM;
  1034. }
  1035. memset(hw = ch->HW_privdata, 0, sizeof(struct comx_privdata));
  1036. if (ch->hardware == &comx_hw || ch->hardware == &cmx_hw) {
  1037. hw->memory_size = COMX_MEMORY_SIZE;
  1038. hw->io_extent = COMX_IO_EXTENT;
  1039. dev->base_addr = COMX_DEFAULT_IO;
  1040. dev->irq = COMX_DEFAULT_IRQ;
  1041. dev->mem_start = COMX_DEFAULT_MEMADDR;
  1042. dev->mem_end = COMX_DEFAULT_MEMADDR + COMX_MEMORY_SIZE;
  1043. } else if (ch->hardware == &hicomx_hw) {
  1044. hw->memory_size = HICOMX_MEMORY_SIZE;
  1045. hw->io_extent = HICOMX_IO_EXTENT;
  1046. dev->base_addr = HICOMX_DEFAULT_IO;
  1047. dev->irq = HICOMX_DEFAULT_IRQ;
  1048. dev->mem_start = HICOMX_DEFAULT_MEMADDR;
  1049. dev->mem_end = HICOMX_DEFAULT_MEMADDR + HICOMX_MEMORY_SIZE;
  1050. } else {
  1051. printk(KERN_ERR "SERIOUS INTERNAL ERROR in %s, line %dn", __FILE__, __LINE__);
  1052. }
  1053. if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, ch->procdir))
  1054.     == NULL) {
  1055.     goto cleanup_HW_privdata;
  1056. }
  1057. new_file->data = (void *)new_file;
  1058. new_file->read_proc = &comxhw_read_proc;
  1059. new_file->write_proc = &comxhw_write_proc;
  1060. new_file->size = 6;
  1061. new_file->nlink = 1;
  1062. if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, ch->procdir))
  1063.     == NULL) {
  1064.     goto cleanup_filename_io;
  1065. }
  1066. new_file->data = (void *)new_file;
  1067. new_file->read_proc = &comxhw_read_proc;
  1068. new_file->write_proc = &comxhw_write_proc;
  1069. new_file->size = 5;
  1070. new_file->nlink = 1;
  1071. if ((new_file = create_proc_entry(FILENAME_CHANNEL, S_IFREG | 0644, 
  1072.     ch->procdir)) == NULL) {
  1073.     goto cleanup_filename_irq;
  1074. }
  1075. new_file->data = (void *)new_file;
  1076. new_file->read_proc = &comxhw_read_proc;
  1077. new_file->write_proc = &comxhw_write_proc;
  1078. new_file->size = 2; // Ezt tudjuk
  1079. new_file->nlink = 1;
  1080. if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) {
  1081. if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, 
  1082.    ch->procdir)) == NULL) {
  1083.     goto cleanup_filename_channel;
  1084. }
  1085. new_file->data = (void *)new_file;
  1086. new_file->read_proc = &comxhw_read_proc;
  1087. new_file->write_proc = &comxhw_write_proc;
  1088. new_file->size = 9;
  1089. new_file->nlink = 1;
  1090. }
  1091. if ((new_file = create_proc_entry(FILENAME_MEMADDR, S_IFREG | 0644, 
  1092.     ch->procdir)) == NULL) {
  1093.     goto cleanup_filename_clock;
  1094. }
  1095. new_file->data = (void *)new_file;
  1096. new_file->read_proc = &comxhw_read_proc;
  1097. new_file->write_proc = &comxhw_write_proc;
  1098. new_file->size = 8;
  1099. new_file->nlink = 1;
  1100. if ((new_file = create_proc_entry(FILENAME_TWIN, S_IFREG | 0444, 
  1101.     ch->procdir)) == NULL) {
  1102.     goto cleanup_filename_memaddr;
  1103. }
  1104. new_file->data = (void *)new_file;
  1105. new_file->read_proc = &comxhw_read_proc;
  1106. new_file->write_proc = NULL;
  1107. new_file->nlink = 1;
  1108. if ((new_file = create_proc_entry(FILENAME_FIRMWARE, S_IFREG | 0644, 
  1109.     ch->procdir)) == NULL) {
  1110.     goto cleanup_filename_twin;
  1111. }
  1112. new_file->data = (void *)new_file;
  1113. new_file->read_proc = &comxhw_read_proc;
  1114. new_file->write_proc = &comxhw_write_proc;
  1115. new_file->nlink = 1;
  1116. if (ch->hardware == &comx_hw) {
  1117. ch->HW_board_on = COMX_board_on;
  1118. ch->HW_board_off = COMX_board_off;
  1119. ch->HW_load_board = COMX_load_board;
  1120. } else if (ch->hardware == &cmx_hw) {
  1121. ch->HW_board_on = COMX_board_on;
  1122. ch->HW_board_off = COMX_board_off;
  1123. ch->HW_load_board = CMX_load_board;
  1124. ch->HW_set_clock = COMX_set_clock;
  1125. } else if (ch->hardware == &hicomx_hw) {
  1126. ch->HW_board_on = HICOMX_board_on;
  1127. ch->HW_board_off = HICOMX_board_off;
  1128. ch->HW_load_board = HICOMX_load_board;
  1129. ch->HW_set_clock = COMX_set_clock;
  1130. } else {
  1131. printk(KERN_ERR "SERIOUS INTERNAL ERROR in %s, line %dn", __FILE__, __LINE__);
  1132. }
  1133. ch->HW_access_board = COMX_access_board;
  1134. ch->HW_release_board = COMX_release_board;
  1135. ch->HW_txe = COMX_txe;
  1136. ch->HW_open = COMX_open;
  1137. ch->HW_close = COMX_close;
  1138. ch->HW_send_packet = COMX_send_packet;
  1139. ch->HW_statistics = COMX_statistics;
  1140. if ((ch->twin = comx_twin_check(dev)) != NULL) {
  1141. struct comx_channel *twin_ch = ch->twin->priv;
  1142. twin_ch->twin = dev;
  1143. }
  1144. MOD_INC_USE_COUNT;
  1145. return 0;
  1146. cleanup_filename_twin:
  1147. remove_proc_entry(FILENAME_TWIN, ch->procdir);
  1148. cleanup_filename_memaddr:
  1149. remove_proc_entry(FILENAME_MEMADDR, ch->procdir);
  1150. cleanup_filename_clock:
  1151. if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw)
  1152. remove_proc_entry(FILENAME_CLOCK, ch->procdir);
  1153. cleanup_filename_channel:
  1154. remove_proc_entry(FILENAME_CHANNEL, ch->procdir);
  1155. cleanup_filename_irq:
  1156. remove_proc_entry(FILENAME_IRQ, ch->procdir);
  1157. cleanup_filename_io:
  1158. remove_proc_entry(FILENAME_IO, ch->procdir);
  1159. cleanup_HW_privdata:
  1160. kfree(ch->HW_privdata);
  1161. return -EIO;
  1162. }
  1163. /* Called on echo valami >boardtype */
  1164. static int COMX_exit(struct net_device *dev)
  1165. {
  1166. struct comx_channel *ch = dev->priv;
  1167. struct comx_privdata *hw = ch->HW_privdata;
  1168. if (hw->firmware) {
  1169. if (hw->firmware->data) kfree(hw->firmware->data);
  1170. kfree(hw->firmware);
  1171. } if (ch->twin) {
  1172. struct comx_channel *twin_ch = ch->twin->priv;
  1173. twin_ch->twin = NULL;
  1174. }
  1175. kfree(ch->HW_privdata);
  1176. remove_proc_entry(FILENAME_IO, ch->procdir);
  1177. remove_proc_entry(FILENAME_IRQ, ch->procdir);
  1178. remove_proc_entry(FILENAME_CHANNEL, ch->procdir);
  1179. remove_proc_entry(FILENAME_MEMADDR, ch->procdir);
  1180. remove_proc_entry(FILENAME_FIRMWARE, ch->procdir);
  1181. remove_proc_entry(FILENAME_TWIN, ch->procdir);
  1182. if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) {
  1183. remove_proc_entry(FILENAME_CLOCK, ch->procdir);
  1184. }
  1185. MOD_DEC_USE_COUNT;
  1186. return 0;
  1187. }
  1188. static int COMX_dump(struct net_device *dev)
  1189. {
  1190. printk(KERN_INFO "%s: COMX_dump called, why ?n", dev->name);
  1191. return 0;
  1192. }
  1193. static struct comx_hardware comx_hw = {
  1194. "comx",
  1195. VERSION,
  1196. COMX_init,
  1197. COMX_exit,
  1198. COMX_dump,
  1199. NULL
  1200. };
  1201. static struct comx_hardware cmx_hw = {
  1202. "cmx",
  1203. VERSION,
  1204. COMX_init,
  1205. COMX_exit,
  1206. COMX_dump,
  1207. NULL
  1208. };
  1209. static struct comx_hardware hicomx_hw = {
  1210. "hicomx",
  1211. VERSION,
  1212. COMX_init,
  1213. COMX_exit,
  1214. COMX_dump,
  1215. NULL
  1216. };
  1217. #ifdef MODULE
  1218. #define comx_hw_comx_init init_module
  1219. #endif
  1220. int __init comx_hw_comx_init(void)
  1221. {
  1222. comx_register_hardware(&comx_hw);
  1223. comx_register_hardware(&cmx_hw);
  1224. comx_register_hardware(&hicomx_hw);
  1225. memset(memory_used, 0, sizeof(memory_used));
  1226. return 0;
  1227. }
  1228. #ifdef MODULE
  1229. void cleanup_module(void)
  1230. {
  1231. comx_unregister_hardware("comx");
  1232. comx_unregister_hardware("cmx");
  1233. comx_unregister_hardware("hicomx");
  1234. }
  1235. #endif