comx.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:29k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Device driver framework for the COMX line of synchronous serial boards
  3.  * 
  4.  * for Linux kernel 2.2.X
  5.  *
  6.  * Original authors:  Arpad Bakay <bakay.arpad@synergon.hu>,
  7.  *                    Peter Bajan <bajan.peter@synergon.hu>,
  8.  * Previous maintainer: Tivadar Szemethy <tiv@itc.hu>
  9.  * Current maintainer: Gergely Madarasz <gorgo@itc.hu>
  10.  *
  11.  * Copyright (C) 1995-1999 ITConsult-Pro Co.
  12.  *
  13.  * Contributors:
  14.  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.85)
  15.  *
  16.  * This program is free software; you can redistribute it and/or
  17.  * modify it under the terms of the GNU General Public License
  18.  * as published by the Free Software Foundation; either version
  19.  * 2 of the License, or (at your option) any later version.
  20.  *
  21.  * Version 0.80 (99/06/11):
  22.  * - clean up source code (playing a bit of indent)
  23.  * - port back to kernel, add support for non-module versions
  24.  * - add support for board resets when channel protocol is down
  25.  * - reset the device structure after protocol exit
  26.  *   the syncppp driver needs it
  27.  * - add support for /proc/comx/protocols and 
  28.  *   /proc/comx/boardtypes
  29.  *
  30.  * Version 0.81 (99/06/21):
  31.  * - comment out the board reset support code, the locomx
  32.  *   driver seems not buggy now
  33.  * - printk() levels fixed
  34.  *
  35.  * Version 0.82 (99/07/08):
  36.  * - Handle stats correctly if the lowlevel driver is
  37.  *   is not a comx one (locomx - z85230)
  38.  *
  39.  * Version 0.83 (99/07/15):
  40.  * - reset line_status when interface is down
  41.  *
  42.  * Version 0.84 (99/12/01):
  43.  * - comx_status should not check for IFF_UP (to report
  44.  *   line status from dev->open())
  45.  *
  46.  * Version 0.85 (00/08/15):
  47.  *  - resource release on failure in comx_mkdir
  48.  *  - fix return value on failure at comx_write_proc
  49.  *
  50.  * Changed      (00/10/29, Henner Eisen):
  51.  *  - comx_rx() / comxlapb_data_indication() return status.
  52.  */
  53. #define VERSION "0.85"
  54. #include <linux/config.h>
  55. #include <linux/module.h>
  56. #include <linux/version.h>
  57. #include <linux/types.h>
  58. #include <linux/sched.h>
  59. #include <linux/netdevice.h>
  60. #include <linux/proc_fs.h>
  61. #include <asm/uaccess.h>
  62. #include <linux/ctype.h>
  63. #include <linux/init.h>
  64. #ifdef CONFIG_KMOD
  65. #include <linux/kmod.h>
  66. #endif
  67. #ifndef CONFIG_PROC_FS
  68. #error For now, COMX really needs the /proc filesystem
  69. #endif
  70. #include <net/syncppp.h>
  71. #include "comx.h"
  72. MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
  73. MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");
  74. MODULE_LICENSE("GPL");
  75. extern int comx_hw_comx_init(void);
  76. extern int comx_hw_locomx_init(void);
  77. extern int comx_hw_mixcom_init(void);
  78. extern int comx_proto_hdlc_init(void);
  79. extern int comx_proto_ppp_init(void);
  80. extern int comx_proto_syncppp_init(void);
  81. extern int comx_proto_lapb_init(void);
  82. extern int comx_proto_fr_init(void);
  83. static struct comx_hardware *comx_channels = NULL;
  84. static struct comx_protocol *comx_lines = NULL;
  85. static int comx_mkdir(struct inode *, struct dentry *, int);
  86. static int comx_rmdir(struct inode *, struct dentry *);
  87. static struct dentry *comx_lookup(struct inode *, struct dentry *);
  88. static struct inode_operations comx_root_inode_ops = {
  89. lookup: comx_lookup,
  90. mkdir: comx_mkdir,
  91. rmdir: comx_rmdir,
  92. };
  93. static int comx_delete_dentry(struct dentry *dentry);
  94. static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
  95. int size, struct proc_dir_entry *dir);
  96. static struct dentry_operations comx_dentry_operations = {
  97. d_delete: comx_delete_dentry,
  98. };
  99. static struct proc_dir_entry * comx_root_dir;
  100. struct comx_debugflags_struct comx_debugflags[] = {
  101. { "comx_rx", DEBUG_COMX_RX },
  102. { "comx_tx",  DEBUG_COMX_TX },
  103. { "hw_tx", DEBUG_HW_TX },
  104. { "hw_rx",  DEBUG_HW_RX },
  105. { "hdlc_keepalive", DEBUG_HDLC_KEEPALIVE },
  106. { "comxppp", DEBUG_COMX_PPP },
  107. { "comxlapb", DEBUG_COMX_LAPB },
  108. { "dlci", DEBUG_COMX_DLCI },
  109. { NULL, 0 } 
  110. };
  111. int comx_debug(struct net_device *dev, char *fmt, ...)
  112. {
  113. struct comx_channel *ch = dev->priv;
  114. char *page,*str;
  115. va_list args;
  116. int len;
  117. if (!ch->debug_area) return 0;
  118. if (!(page = (char *)__get_free_page(GFP_ATOMIC))) return -ENOMEM;
  119. va_start(args, fmt);
  120. len = vsprintf(str = page, fmt, args);
  121. va_end(args);
  122. if (len >= PAGE_SIZE) {
  123. printk(KERN_ERR "comx_debug: PANIC! len = %d !!!n", len);
  124. free_page((unsigned long)page);
  125. return -EINVAL;
  126. }
  127. while (len) {
  128. int to_copy;
  129. int free = (ch->debug_start - ch->debug_end + ch->debug_size) 
  130. % ch->debug_size;
  131. to_copy = min_t(int, free ? free : ch->debug_size, 
  132.       min_t(int, ch->debug_size - ch->debug_end, len));
  133. memcpy(ch->debug_area + ch->debug_end, str, to_copy);
  134. str += to_copy;
  135. len -= to_copy;
  136. ch->debug_end = (ch->debug_end + to_copy) % ch->debug_size;
  137. if (ch->debug_start == ch->debug_end) // Full ? push start away
  138. ch->debug_start = (ch->debug_start + len + 1) % 
  139. ch->debug_size;
  140. ch->debug_file->size = (ch->debug_end - ch->debug_start +
  141. ch->debug_size) % ch->debug_size;
  142. free_page((unsigned long)page);
  143. return 0;
  144. }
  145. int comx_debug_skb(struct net_device *dev, struct sk_buff *skb, char *msg)
  146. {
  147. struct comx_channel *ch = dev->priv;
  148. if (!ch->debug_area) return 0;
  149. if (!skb) comx_debug(dev, "%s: %s NULL skbnn", dev->name, msg);
  150. if (!skb->len) comx_debug(dev, "%s: %s empty skbnn", dev->name, msg);
  151. return comx_debug_bytes(dev, skb->data, skb->len, msg);
  152. }
  153. int comx_debug_bytes(struct net_device *dev, unsigned char *bytes, int len, 
  154. char *msg)
  155. {
  156. int pos = 0;
  157. struct comx_channel *ch = dev->priv;
  158. if (!ch->debug_area) return 0;
  159. comx_debug(dev, "%s: %s len %dn", dev->name, msg, len);
  160. while (pos != len) {
  161. char line[80];
  162. int i = 0;
  163. memset(line, 0, 80);
  164. sprintf(line,"%04d ", pos);
  165. do {
  166. sprintf(line + 5 + (pos % 16) * 3, "%02x", bytes[pos]);
  167. sprintf(line + 60 + (pos % 16), "%c", 
  168. isprint(bytes[pos]) ? bytes[pos] : '.');
  169. pos++;
  170. } while (pos != len && pos % 16);
  171. while ( i++ != 78 ) if (line[i] == 0) line[i] = ' ';
  172. line[77] = 'n';
  173. line[78] = 0;
  174. comx_debug(dev, "%s", line);
  175. }
  176. comx_debug(dev, "n");
  177. return 0;
  178. }
  179. static void comx_loadavg_timerfun(unsigned long d)
  180. {
  181. struct net_device *dev = (struct net_device *)d;
  182. struct comx_channel *ch = dev->priv;
  183. ch->avg_bytes[ch->loadavg_counter] = ch->current_stats->rx_bytes;
  184. ch->avg_bytes[ch->loadavg_counter + ch->loadavg_size] = 
  185. ch->current_stats->tx_bytes;
  186. ch->loadavg_counter = (ch->loadavg_counter + 1) % ch->loadavg_size;
  187. mod_timer(&ch->loadavg_timer,jiffies + HZ * ch->loadavg[0]);
  188. }
  189. #if 0
  190. static void comx_reset_timerfun(unsigned long d)
  191. struct net_device *dev = (struct net_device *)d;
  192. struct comx_channel *ch = dev->priv;
  193. if(!(ch->line_status & (PROTO_LOOP | PROTO_UP))) {
  194. if(test_and_set_bit(0,&ch->reset_pending) && ch->HW_reset) {
  195. ch->HW_reset(dev);
  196. }
  197. }
  198. mod_timer(&ch->reset_timer, jiffies + HZ * ch->reset_timeout);
  199. }
  200. #endif                                            
  201. static int comx_open(struct net_device *dev)
  202. {
  203. struct comx_channel *ch = dev->priv;
  204. struct proc_dir_entry *comxdir = ch->procdir->subdir;
  205. int ret=0;
  206. if (!ch->protocol || !ch->hardware) return -ENODEV;
  207. if ((ret = ch->HW_open(dev))) return ret;
  208. if ((ret = ch->LINE_open(dev))) { 
  209. ch->HW_close(dev); 
  210. return ret; 
  211. };
  212. for (; comxdir ; comxdir = comxdir->next) {
  213. if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
  214.    strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
  215. comxdir->mode = S_IFREG | 0444;
  216. }
  217. #if 0
  218. ch->reset_pending = 1;
  219. ch->reset_timeout = 30;
  220. ch->reset_timer.function = comx_reset_timerfun;
  221. ch->reset_timer.data = (unsigned long)dev;
  222. ch->reset_timer.expires = jiffies + HZ * ch->reset_timeout;
  223. add_timer(&ch->reset_timer);
  224. #endif
  225. return 0;
  226. }
  227. static int comx_close(struct net_device *dev)
  228. {
  229. struct comx_channel *ch = dev->priv;
  230. struct proc_dir_entry *comxdir = ch->procdir->subdir;
  231. int ret = -ENODEV;
  232. if (test_and_clear_bit(0, &ch->lineup_pending)) {
  233. del_timer(&ch->lineup_timer);
  234. }
  235. #if 0
  236. del_timer(&ch->reset_timer);
  237. #endif
  238. if (ch->init_status & LINE_OPEN && ch->protocol && ch->LINE_close) {
  239. ret = ch->LINE_close(dev);
  240. }
  241. if (ret) return ret;
  242. if (ch->init_status & HW_OPEN && ch->hardware && ch->HW_close) {
  243. ret = ch->HW_close(dev);
  244. }
  245. ch->line_status=0;
  246. for (; comxdir ; comxdir = comxdir->next) {
  247. if (strcmp(comxdir->name, FILENAME_HARDWARE) == 0 ||
  248.     strcmp(comxdir->name, FILENAME_PROTOCOL) == 0)
  249. comxdir->mode = S_IFREG | 0644;
  250. }
  251. return ret;
  252. }
  253. void comx_status(struct net_device *dev, int status)
  254. {
  255. struct comx_channel *ch = dev->priv;
  256. #if 0
  257. if(status & (PROTO_UP | PROTO_LOOP)) {
  258. clear_bit(0,&ch->reset_pending);
  259. }
  260. #endif
  261. printk(KERN_NOTICE "Interface %s: modem status %s, line protocol %sn",
  262.     dev->name, status & LINE_UP ? "UP" : "DOWN", 
  263.     status & PROTO_LOOP ? "LOOP" : status & PROTO_UP ? 
  264.     "UP" : "DOWN");
  265. ch->line_status = status;
  266. }
  267. static int comx_xmit(struct sk_buff *skb, struct net_device *dev)
  268. {
  269. struct comx_channel *ch = dev->priv;
  270. int rc;
  271. if (skb->len > dev->mtu + dev->hard_header_len) {
  272. printk(KERN_ERR "comx_xmit: %s: skb->len %d > dev->mtu %dn", dev->name,
  273. (int)skb->len, dev->mtu);
  274. }
  275. if (ch->debug_flags & DEBUG_COMX_TX) {
  276. comx_debug_skb(dev, skb, "comx_xmit skb");
  277. }
  278. rc=ch->LINE_xmit(skb, dev);
  279. // if (!rc) dev_kfree_skb(skb);
  280. return rc;
  281. }
  282. static int comx_header(struct sk_buff *skb, struct net_device *dev, 
  283. unsigned short type, void *daddr, void *saddr, unsigned len) 
  284. {
  285. struct comx_channel *ch = dev->priv;
  286. if (ch->LINE_header) {
  287. return (ch->LINE_header(skb, dev, type, daddr, saddr, len));
  288. } else {
  289. return 0;
  290. }
  291. }
  292. static int comx_rebuild_header(struct sk_buff *skb) 
  293. {
  294. struct net_device *dev = skb->dev;
  295. struct comx_channel *ch = dev->priv;
  296. if (ch->LINE_rebuild_header) {
  297. return(ch->LINE_rebuild_header(skb));
  298. } else {
  299. return 0;
  300. }
  301. }
  302. int comx_rx(struct net_device *dev, struct sk_buff *skb)
  303. {
  304. struct comx_channel *ch = dev->priv;
  305. if (ch->debug_flags & DEBUG_COMX_RX) {
  306. comx_debug_skb(dev, skb, "comx_rx skb");
  307. }
  308. if (skb) {
  309. netif_rx(skb);
  310. dev->last_rx = jiffies;
  311. }
  312. return 0;
  313. }
  314. static struct net_device_stats *comx_stats(struct net_device *dev)
  315. {
  316. struct comx_channel *ch = (struct comx_channel *)dev->priv;
  317. return ch->current_stats;
  318. }
  319. void comx_lineup_func(unsigned long d)
  320. {
  321. struct net_device *dev = (struct net_device *)d;
  322. struct comx_channel *ch = dev->priv;
  323. del_timer(&ch->lineup_timer);
  324. clear_bit(0, &ch->lineup_pending);
  325. if (ch->LINE_status) {
  326. ch->LINE_status(dev, ch->line_status |= LINE_UP);
  327. }
  328. }
  329. #define LOADAVG(avg, off) (int) 
  330. ((ch->avg_bytes[(ch->loadavg_counter - 1 + ch->loadavg_size * 2) 
  331. % ch->loadavg_size + off] -  ch->avg_bytes[(ch->loadavg_counter - 1 
  332. - ch->loadavg[avg] / ch->loadavg[0] + ch->loadavg_size * 2) 
  333. % ch->loadavg_size + off]) / ch->loadavg[avg] * 8)
  334. static int comx_statistics(struct net_device *dev, char *page)
  335. {
  336. struct comx_channel *ch = dev->priv;
  337. int len = 0;
  338. int tmp;
  339. int i = 0;
  340. char tmpstr[20];
  341. int tmpstrlen = 0;
  342. len += sprintf(page + len, "Interface administrative status is %s, "
  343. "modem status is %s, protocol is %sn", 
  344. dev->flags & IFF_UP ? "UP" : "DOWN",
  345. ch->line_status & LINE_UP ? "UP" : "DOWN",
  346. ch->line_status & PROTO_LOOP ? "LOOP" : 
  347. ch->line_status & PROTO_UP ? "UP" : "DOWN");
  348. len += sprintf(page + len, "Modem status changes: %lu, Transmitter status "
  349. "is %s, tbusy: %dn", ch->current_stats->tx_carrier_errors, ch->HW_txe ? 
  350. ch->HW_txe(dev) ? "IDLE" : "BUSY" : "NOT READY", netif_running(dev));
  351. len += sprintf(page + len, "Interface load (input): %d / %d / %d bits/s (",
  352. LOADAVG(0,0), LOADAVG(1, 0), LOADAVG(2, 0));
  353. tmpstr[0] = 0;
  354. for (i=0; i != 3; i++) {
  355. char tf;
  356. tf = ch->loadavg[i] % 60 == 0 && 
  357. ch->loadavg[i] / 60 > 0 ? 'm' : 's';
  358. tmpstrlen += sprintf(tmpstr + tmpstrlen, "%d%c%s", 
  359. ch->loadavg[i] / (tf == 'm' ? 60 : 1), tf, 
  360. i == 2 ? ")n" : "/");
  361. }
  362. len += sprintf(page + len, 
  363. "%s              (output): %d / %d / %d bits/s (%s", tmpstr, 
  364. LOADAVG(0,ch->loadavg_size), LOADAVG(1, ch->loadavg_size), 
  365. LOADAVG(2, ch->loadavg_size), tmpstr);
  366. len += sprintf(page + len, "Debug flags: ");
  367. tmp = len; i = 0;
  368. while (comx_debugflags[i].name) {
  369. if (ch->debug_flags & comx_debugflags[i].value) 
  370. len += sprintf(page + len, "%s ", 
  371. comx_debugflags[i].name);
  372. i++;
  373. }
  374. len += sprintf(page + len, "%sn", tmp == len ? "none" : "");
  375. len += sprintf(page + len, "RX errors: len: %lu, overrun: %lu, crc: %lu, "
  376. "aborts: %lun           buffer overrun: %lu, pbuffer overrun: %lun"
  377. "TX errors: underrun: %lun",
  378. ch->current_stats->rx_length_errors, ch->current_stats->rx_over_errors, 
  379. ch->current_stats->rx_crc_errors, ch->current_stats->rx_frame_errors, 
  380. ch->current_stats->rx_missed_errors, ch->current_stats->rx_fifo_errors,
  381. ch->current_stats->tx_fifo_errors);
  382. if (ch->LINE_statistics && (ch->init_status & LINE_OPEN)) {
  383. len += ch->LINE_statistics(dev, page + len);
  384. } else {
  385. len += sprintf(page+len, "Line status: driver not initializedn");
  386. }
  387. if (ch->HW_statistics && (ch->init_status & HW_OPEN)) {
  388. len += ch->HW_statistics(dev, page + len);
  389. } else {
  390. len += sprintf(page+len, "Board status: driver not initializedn");
  391. }
  392. return len;
  393. }
  394. static int comx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
  395. {
  396. struct comx_channel *ch = dev->priv;
  397. if (ch->LINE_ioctl) {
  398. return(ch->LINE_ioctl(dev, ifr, cmd));
  399. }
  400. return -EINVAL;
  401. }
  402. static void comx_reset_dev(struct net_device *dev)
  403. {
  404. dev->open = comx_open;
  405. dev->stop = comx_close;
  406. dev->hard_start_xmit = comx_xmit;
  407. dev->hard_header = comx_header;
  408. dev->rebuild_header = comx_rebuild_header;
  409. dev->get_stats = comx_stats;
  410. dev->do_ioctl = comx_ioctl;
  411. dev->change_mtu = NULL;
  412. dev->tx_queue_len = 20;
  413. dev->flags = IFF_NOARP;
  414. }
  415. static int comx_init_dev(struct net_device *dev)
  416. {
  417. struct comx_channel *ch;
  418. if ((ch = kmalloc(sizeof(struct comx_channel), GFP_KERNEL)) == NULL) {
  419. return -ENOMEM;
  420. }
  421. memset(ch, 0, sizeof(struct comx_channel));
  422. ch->loadavg[0] = 5;
  423. ch->loadavg[1] = 300;
  424. ch->loadavg[2] = 900;
  425. ch->loadavg_size = ch->loadavg[2] / ch->loadavg[0] + 1; 
  426. if ((ch->avg_bytes = kmalloc(ch->loadavg_size * 
  427. sizeof(unsigned long) * 2, GFP_KERNEL)) == NULL) {
  428. kfree(ch);
  429. return -ENOMEM;
  430. }
  431. memset(ch->avg_bytes, 0, ch->loadavg_size * sizeof(unsigned long) * 2);
  432. ch->loadavg_counter = 0;
  433. ch->loadavg_timer.function = comx_loadavg_timerfun;
  434. ch->loadavg_timer.data = (unsigned long)dev;
  435. ch->loadavg_timer.expires = jiffies + HZ * ch->loadavg[0];
  436. add_timer(&ch->loadavg_timer);
  437. dev->priv = (void *)ch;
  438. ch->dev = dev;
  439. ch->line_status &= ~LINE_UP;
  440. ch->current_stats = &ch->stats;
  441. comx_reset_dev(dev);
  442. return 0;
  443. }
  444. static int comx_read_proc(char *page, char **start, off_t off, int count, 
  445. int *eof, void *data)
  446. {
  447. struct proc_dir_entry *file = (struct proc_dir_entry *)data;
  448. struct net_device *dev = file->parent->data;
  449. struct comx_channel *ch=(struct comx_channel *)dev->priv;
  450. int len = 0;
  451. if (strcmp(file->name, FILENAME_STATUS) == 0) {
  452. len = comx_statistics(dev, page);
  453. } else if (strcmp(file->name, FILENAME_HARDWARE) == 0) {
  454. len = sprintf(page, "%sn", ch->hardware ? 
  455. ch->hardware->name : HWNAME_NONE);
  456. } else if (strcmp(file->name, FILENAME_PROTOCOL) == 0) {
  457. len = sprintf(page, "%sn", ch->protocol ? 
  458. ch->protocol->name : PROTONAME_NONE);
  459. } else if (strcmp(file->name, FILENAME_LINEUPDELAY) == 0) {
  460. len = sprintf(page, "%01dn", ch->lineup_delay);
  461. }
  462. if (off >= len) {
  463. *eof = 1;
  464. return 0;
  465. }
  466. *start = page + off;
  467. if (count >= len - off) {
  468. *eof = 1;
  469. }
  470. return min_t(int, count, len - off);
  471. }
  472. static int comx_root_read_proc(char *page, char **start, off_t off, int count, 
  473. int *eof, void *data)
  474. {
  475. struct proc_dir_entry *file = (struct proc_dir_entry *)data;
  476. struct comx_hardware *hw;
  477. struct comx_protocol *line;
  478. int len = 0;
  479. if (strcmp(file->name, FILENAME_HARDWARELIST) == 0) {
  480. for(hw=comx_channels;hw;hw=hw->next) 
  481. len+=sprintf(page+len, "%sn", hw->name);
  482. } else if (strcmp(file->name, FILENAME_PROTOCOLLIST) == 0) {
  483. for(line=comx_lines;line;line=line->next)
  484. len+=sprintf(page+len, "%sn", line->name);
  485. }
  486. if (off >= len) {
  487. *eof = 1;
  488. return 0;
  489. }
  490. *start = page + off;
  491. if (count >= len - off) {
  492. *eof = 1;
  493. }
  494. return min_t(int, count, len - off);
  495. }
  496. static int comx_write_proc(struct file *file, const char *buffer, u_long count,
  497. void *data)
  498. {
  499. struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
  500. struct net_device *dev = (struct net_device *)entry->parent->data;
  501. struct comx_channel *ch=(struct comx_channel *)dev->priv;
  502. char *page;
  503. struct comx_hardware *hw = comx_channels;
  504. struct comx_protocol *line = comx_lines;
  505. char str[30];
  506. int ret=0;
  507. if (count > PAGE_SIZE) {
  508. printk(KERN_ERR "count is %lu > %d!!!n", count, (int)PAGE_SIZE);
  509. return -ENOSPC;
  510. }
  511. if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
  512. if(copy_from_user(page, buffer, count))
  513. {
  514. count = -EFAULT;
  515. goto out;
  516. }
  517. if (page[count-1] == 'n')
  518. page[count-1] = '';
  519. else if (count < PAGE_SIZE)
  520. page[count] = '';
  521. else if (page[count]) {
  522. count = -EINVAL;
  523. goto out;
  524. }
  525. if (strcmp(entry->name, FILENAME_DEBUG) == 0) {
  526. int i;
  527. int ret = 0;
  528. if ((i = simple_strtoul(page, NULL, 10)) != 0) {
  529. unsigned long flags;
  530. save_flags(flags); cli();
  531. if (ch->debug_area) kfree(ch->debug_area);
  532. if ((ch->debug_area = kmalloc(ch->debug_size = i, 
  533. GFP_KERNEL)) == NULL) {
  534. ret = -ENOMEM;
  535. }
  536. ch->debug_start = ch->debug_end = 0;
  537. restore_flags(flags);
  538. free_page((unsigned long)page);
  539. return ret ? ret : count;
  540. }
  541. if (*page != '+' && *page != '-') {
  542. free_page((unsigned long)page);
  543. return -EINVAL;
  544. }
  545. while (comx_debugflags[i].value && 
  546. strncmp(comx_debugflags[i].name, page + 1, 
  547. strlen(comx_debugflags[i].name))) {
  548. i++;
  549. }
  550. if (comx_debugflags[i].value == 0) {
  551. printk(KERN_ERR "Invalid debug optionn");
  552. free_page((unsigned long)page);
  553. return -EINVAL;
  554. }
  555. if (*page == '+') {
  556. ch->debug_flags |= comx_debugflags[i].value;
  557. } else {
  558. ch->debug_flags &= ~comx_debugflags[i].value;
  559. }
  560. } else if (strcmp(entry->name, FILENAME_HARDWARE) == 0) {
  561. if(strlen(page)>10) {
  562. free_page((unsigned long)page);
  563. return -EINVAL;
  564. }
  565. while (hw) { 
  566. if (strcmp(hw->name, page) == 0) {
  567. break;
  568. } else {
  569. hw = hw->next;
  570. }
  571. }
  572. #ifdef CONFIG_KMOD
  573. if(!hw && comx_strcasecmp(HWNAME_NONE,page) != 0){
  574. sprintf(str,"comx-hw-%s",page);
  575. request_module(str);
  576. }
  577. hw=comx_channels;
  578. while (hw) {
  579. if (comx_strcasecmp(hw->name, page) == 0) {
  580. break;
  581. } else {
  582. hw = hw->next;
  583. }
  584. }
  585. #endif
  586. if (comx_strcasecmp(HWNAME_NONE, page) != 0 && !hw)  {
  587. free_page((unsigned long)page);
  588. return -ENODEV;
  589. }
  590. if (ch->init_status & HW_OPEN) {
  591. free_page((unsigned long)page);
  592. return -EBUSY;
  593. }
  594. if (ch->hardware && ch->hardware->hw_exit && 
  595.    (ret=ch->hardware->hw_exit(dev))) {
  596. free_page((unsigned long)page);
  597. return ret;
  598. }
  599. ch->hardware = hw;
  600. entry->size = strlen(page) + 1;
  601. if (hw && hw->hw_init) hw->hw_init(dev);
  602. } else if (strcmp(entry->name, FILENAME_PROTOCOL) == 0) {
  603. if(strlen(page)>10) {
  604. free_page((unsigned long)page);
  605. return -EINVAL;
  606. }
  607. while (line) {
  608. if (comx_strcasecmp(line->name, page) == 0) {
  609. break;
  610. } else {
  611. line = line->next;
  612. }
  613. }
  614. #ifdef CONFIG_KMOD
  615. if(!line && comx_strcasecmp(PROTONAME_NONE, page) != 0) {
  616. sprintf(str,"comx-proto-%s",page);
  617. request_module(str);
  618. }
  619. line=comx_lines;
  620. while (line) {
  621. if (comx_strcasecmp(line->name, page) == 0) {
  622. break;
  623. } else {
  624. line = line->next;
  625. }
  626. }
  627. #endif
  628. if (comx_strcasecmp(PROTONAME_NONE, page) != 0 && !line) {
  629. free_page((unsigned long)page);
  630. return -ENODEV;
  631. }
  632. if (ch->init_status & LINE_OPEN) {
  633. free_page((unsigned long)page);
  634. return -EBUSY;
  635. }
  636. if (ch->protocol && ch->protocol->line_exit && 
  637.     (ret=ch->protocol->line_exit(dev))) {
  638. free_page((unsigned long)page);
  639. return ret;
  640. }
  641. ch->protocol = line;
  642. entry->size = strlen(page) + 1;
  643. comx_reset_dev(dev);
  644. if (line && line->line_init) line->line_init(dev);
  645. } else if (strcmp(entry->name, FILENAME_LINEUPDELAY) == 0) {
  646. int i;
  647. if ((i = simple_strtoul(page, NULL, 10)) != 0) {
  648. if (i >=0 && i < 10) { 
  649. ch->lineup_delay = i; 
  650. } else {
  651. printk(KERN_ERR "comx: invalid lineup_delay valuen");
  652. }
  653. }
  654. }
  655. out:
  656. free_page((unsigned long)page);
  657. return count;
  658. }
  659. static int comx_mkdir(struct inode *dir, struct dentry *dentry, int mode)
  660. {
  661. struct proc_dir_entry *new_dir, *debug_file;
  662. struct net_device *dev;
  663. struct comx_channel *ch;
  664. int ret = -EIO;
  665. if ((dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL) {
  666. return -ENOMEM;
  667. }
  668. memset(dev, 0, sizeof(struct net_device));
  669. if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR, 
  670. comx_root_dir)) == NULL) {
  671. goto cleanup_dev;
  672. }
  673. new_dir->nlink = 2;
  674. new_dir->data = NULL; // ide jon majd a struct dev
  675. /* Ezek kellenek */
  676. if (!create_comx_proc_entry(FILENAME_HARDWARE, 0644, 
  677.     strlen(HWNAME_NONE) + 1, new_dir)) {
  678. goto cleanup_new_dir;
  679. }
  680. if (!create_comx_proc_entry(FILENAME_PROTOCOL, 0644, 
  681.     strlen(PROTONAME_NONE) + 1, new_dir)) {
  682. goto cleanup_filename_hardware;
  683. }
  684. if (!create_comx_proc_entry(FILENAME_STATUS, 0444, 0, new_dir)) {
  685. goto cleanup_filename_protocol;
  686. }
  687. if (!create_comx_proc_entry(FILENAME_LINEUPDELAY, 0644, 2, new_dir)) {
  688. goto cleanup_filename_status;
  689. }
  690. if ((debug_file = create_proc_entry(FILENAME_DEBUG, 
  691.     S_IFREG | 0644, new_dir)) == NULL) {
  692. goto cleanup_filename_lineupdelay;
  693. }
  694. debug_file->data = (void *)debug_file; 
  695. debug_file->read_proc = NULL; // see below
  696. debug_file->write_proc = &comx_write_proc;
  697. debug_file->nlink = 1;
  698. strcpy(dev->name, (char *)new_dir->name);
  699. dev->init = comx_init_dev;
  700. if (register_netdevice(dev)) {
  701. goto cleanup_filename_debug;
  702. }
  703. ch=dev->priv;
  704. if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device), 
  705.  GFP_KERNEL)) == NULL) {
  706. goto cleanup_register;
  707. }
  708. memset(ch->if_ptr, 0, sizeof(struct ppp_device));
  709. ch->debug_file = debug_file; 
  710. ch->procdir = new_dir;
  711. new_dir->data = dev;
  712. ch->debug_start = ch->debug_end = 0;
  713. if ((ch->debug_area = kmalloc(ch->debug_size = DEFAULT_DEBUG_SIZE, 
  714.     GFP_KERNEL)) == NULL) {
  715. ret = -ENOMEM;
  716. goto cleanup_if_ptr;
  717. }
  718. ch->lineup_delay = DEFAULT_LINEUP_DELAY;
  719. MOD_INC_USE_COUNT;
  720. return 0;
  721. cleanup_if_ptr:
  722. kfree(ch->if_ptr);
  723. cleanup_register:
  724. unregister_netdevice(dev);
  725. cleanup_filename_debug:
  726. remove_proc_entry(FILENAME_DEBUG, new_dir);
  727. cleanup_filename_lineupdelay:
  728. remove_proc_entry(FILENAME_LINEUPDELAY, new_dir);
  729. cleanup_filename_status:
  730. remove_proc_entry(FILENAME_STATUS, new_dir);
  731. cleanup_filename_protocol:
  732. remove_proc_entry(FILENAME_PROTOCOL, new_dir);
  733. cleanup_filename_hardware:
  734. remove_proc_entry(FILENAME_HARDWARE, new_dir);
  735. cleanup_new_dir:
  736. remove_proc_entry(dentry->d_name.name, comx_root_dir);
  737. cleanup_dev:
  738. kfree(dev);
  739. return ret;
  740. }
  741. static int comx_rmdir(struct inode *dir, struct dentry *dentry)
  742. {
  743. struct proc_dir_entry *entry = dentry->d_inode->u.generic_ip;
  744. struct net_device *dev = entry->data;
  745. struct comx_channel *ch = dev->priv;
  746. int ret;
  747. if (dev->flags & IFF_UP) {
  748. printk(KERN_ERR "%s: down interface before removing itn", dev->name);
  749. return -EBUSY;
  750. }
  751. if (ch->protocol && ch->protocol->line_exit && 
  752.     (ret=ch->protocol->line_exit(dev))) {
  753. return ret;
  754. }
  755. if (ch->hardware && ch->hardware->hw_exit && 
  756.    (ret=ch->hardware->hw_exit(dev))) { 
  757. if(ch->protocol && ch->protocol->line_init) {
  758. ch->protocol->line_init(dev);
  759. }
  760. return ret;
  761. }
  762. ch->protocol = NULL;
  763. ch->hardware = NULL;
  764. del_timer(&ch->loadavg_timer);
  765. kfree(ch->avg_bytes);
  766. unregister_netdev(dev);
  767. if (ch->debug_area) {
  768. kfree(ch->debug_area);
  769. }
  770. if (dev->priv) {
  771. kfree(dev->priv);
  772. }
  773. kfree(dev);
  774. remove_proc_entry(FILENAME_DEBUG, entry);
  775. remove_proc_entry(FILENAME_LINEUPDELAY, entry);
  776. remove_proc_entry(FILENAME_STATUS, entry);
  777. remove_proc_entry(FILENAME_HARDWARE, entry);
  778. remove_proc_entry(FILENAME_PROTOCOL, entry);
  779. remove_proc_entry(dentry->d_name.name, comx_root_dir);
  780. MOD_DEC_USE_COUNT;
  781. return 0;
  782. }
  783. static struct dentry *comx_lookup(struct inode *dir, struct dentry *dentry)
  784. {
  785. struct proc_dir_entry *de;
  786. struct inode *inode = NULL;
  787. if ((de = (struct proc_dir_entry *) dir->u.generic_ip) != NULL) {
  788. for (de = de->subdir ; de ; de = de->next) {
  789. if ((de && de->low_ino) && 
  790.     (de->namelen == dentry->d_name.len) &&
  791.     (memcmp(dentry->d_name.name, de->name, 
  792.     de->namelen) == 0)) {
  793.   if ((inode = proc_get_inode(dir->i_sb, 
  794.       de->low_ino, de)) == NULL) { 
  795.   printk(KERN_ERR "COMX: lookup errorn"); 
  796.   return ERR_PTR(-EINVAL); 
  797.   }
  798. break;
  799. }
  800. }
  801. }
  802. dentry->d_op = &comx_dentry_operations;
  803. d_add(dentry, inode);
  804. return NULL;
  805. }
  806. int comx_strcasecmp(const char *cs, const char *ct)
  807. {
  808. register signed char __res;
  809. while (1) {
  810. if ((__res = toupper(*cs) - toupper(*ct++)) != 0 || !*cs++) {
  811. break;
  812. }
  813. }
  814. return __res;
  815. }
  816. static int comx_delete_dentry(struct dentry *dentry)
  817. {
  818. return 1;
  819. }
  820. static struct proc_dir_entry *create_comx_proc_entry(char *name, int mode,
  821. int size, struct proc_dir_entry *dir)
  822. {
  823. struct proc_dir_entry *new_file;
  824. if ((new_file = create_proc_entry(name, S_IFREG | mode, dir)) != NULL) {
  825. new_file->data = (void *)new_file;
  826. new_file->read_proc = &comx_read_proc;
  827. new_file->write_proc = &comx_write_proc;
  828. new_file->size = size;
  829. new_file->nlink = 1;
  830. }
  831. return(new_file);
  832. }
  833. int comx_register_hardware(struct comx_hardware *comx_hw)
  834. {
  835. struct comx_hardware *hw = comx_channels;
  836. if (!hw) {
  837. comx_channels = comx_hw;
  838. } else {
  839. while (hw->next != NULL && strcmp(comx_hw->name, hw->name) != 0) {
  840. hw = hw->next;
  841. }
  842. if (strcmp(comx_hw->name, hw->name) == 0) {
  843. return -1;
  844. }
  845. hw->next = comx_hw;
  846. }
  847. printk(KERN_INFO "COMX: driver for hardware type %s, version %sn", comx_hw->name, comx_hw->version);
  848. return 0;
  849. }
  850. int comx_unregister_hardware(char *name)
  851. {
  852. struct comx_hardware *hw = comx_channels;
  853. if (!hw) {
  854. return -1;
  855. }
  856. if (strcmp(hw->name, name) == 0) {
  857. comx_channels = comx_channels->next;
  858. return 0;
  859. }
  860. while (hw->next != NULL && strcmp(hw->next->name,name) != 0) {
  861. hw = hw->next;
  862. }
  863. if (hw->next != NULL && strcmp(hw->next->name, name) == 0) {
  864. hw->next = hw->next->next;
  865. return 0;
  866. }
  867. return -1;
  868. }
  869. int comx_register_protocol(struct comx_protocol *comx_line)
  870. {
  871. struct comx_protocol *pr = comx_lines;
  872. if (!pr) {
  873. comx_lines = comx_line;
  874. } else {
  875. while (pr->next != NULL && strcmp(comx_line->name, pr->name) !=0) {
  876. pr = pr->next;
  877. }
  878. if (strcmp(comx_line->name, pr->name) == 0) {
  879. return -1;
  880. }
  881. pr->next = comx_line;
  882. }
  883. printk(KERN_INFO "COMX: driver for protocol type %s, version %sn", comx_line->name, comx_line->version);
  884. return 0;
  885. }
  886. int comx_unregister_protocol(char *name)
  887. {
  888. struct comx_protocol *pr = comx_lines;
  889. if (!pr) {
  890. return -1;
  891. }
  892. if (strcmp(pr->name, name) == 0) {
  893. comx_lines = comx_lines->next;
  894. return 0;
  895. }
  896. while (pr->next != NULL && strcmp(pr->next->name,name) != 0) {
  897. pr = pr->next;
  898. }
  899. if (pr->next != NULL && strcmp(pr->next->name, name) == 0) {
  900. pr->next = pr->next->next;
  901. return 0;
  902. }
  903. return -1;
  904. }
  905. #ifdef MODULE
  906. #define comx_init init_module
  907. #endif
  908. int __init comx_init(void)
  909. {
  910. struct proc_dir_entry *new_file;
  911. comx_root_dir = create_proc_entry("comx", 
  912. S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, &proc_root);
  913. if (!comx_root_dir)
  914. return -ENOMEM;
  915. comx_root_dir->proc_iops = &comx_root_inode_ops;
  916. if ((new_file = create_proc_entry(FILENAME_HARDWARELIST, 
  917.    S_IFREG | 0444, comx_root_dir)) == NULL) {
  918. return -ENOMEM;
  919. }
  920. new_file->data = new_file;
  921. new_file->read_proc = &comx_root_read_proc;
  922. new_file->write_proc = NULL;
  923. new_file->nlink = 1;
  924. if ((new_file = create_proc_entry(FILENAME_PROTOCOLLIST, 
  925.    S_IFREG | 0444, comx_root_dir)) == NULL) {
  926. return -ENOMEM;
  927. }
  928. new_file->data = new_file;
  929. new_file->read_proc = &comx_root_read_proc;
  930. new_file->write_proc = NULL;
  931. new_file->nlink = 1;
  932. printk(KERN_INFO "COMX: driver version %s (C) 1995-1999 ITConsult-Pro Co. <info@itc.hu>n", 
  933. VERSION);
  934. #ifndef MODULE
  935. #ifdef CONFIG_COMX_HW_COMX
  936. comx_hw_comx_init();
  937. #endif
  938. #ifdef CONFIG_COMX_HW_LOCOMX
  939. comx_hw_locomx_init();
  940. #endif
  941. #ifdef CONFIG_COMX_HW_MIXCOM
  942. comx_hw_mixcom_init();
  943. #endif
  944. #ifdef CONFIG_COMX_PROTO_HDLC
  945. comx_proto_hdlc_init();
  946. #endif
  947. #ifdef CONFIG_COMX_PROTO_PPP
  948. comx_proto_ppp_init();
  949. #endif
  950. #ifdef CONFIG_COMX_PROTO_LAPB
  951. comx_proto_lapb_init();
  952. #endif
  953. #ifdef CONFIG_COMX_PROTO_FR
  954. comx_proto_fr_init();
  955. #endif
  956. #endif
  957. return 0;
  958. }
  959. #ifdef MODULE
  960. void cleanup_module(void)
  961. {
  962. remove_proc_entry(FILENAME_HARDWARELIST, comx_root_dir);
  963. remove_proc_entry(FILENAME_PROTOCOLLIST, comx_root_dir);
  964. remove_proc_entry(comx_root_dir->name, &proc_root);
  965. }
  966. #endif
  967. EXPORT_SYMBOL(comx_register_hardware);
  968. EXPORT_SYMBOL(comx_unregister_hardware);
  969. EXPORT_SYMBOL(comx_register_protocol);
  970. EXPORT_SYMBOL(comx_unregister_protocol);
  971. EXPORT_SYMBOL(comx_debug_skb);
  972. EXPORT_SYMBOL(comx_debug_bytes);
  973. EXPORT_SYMBOL(comx_debug);
  974. EXPORT_SYMBOL(comx_lineup_func);
  975. EXPORT_SYMBOL(comx_status);
  976. EXPORT_SYMBOL(comx_rx);
  977. EXPORT_SYMBOL(comx_strcasecmp);
  978. EXPORT_SYMBOL(comx_root_dir);