File: /usr/src/linux/drivers/net/wan/comx-hw-locomx.c
1 /*
2 * Hardware driver for the LoCOMX card, using the generic z85230
3 * functions
4 *
5 * Author: Gergely Madarasz <gorgo@itc.hu>
6 *
7 * Based on skeleton code and old LoCOMX driver by Tivadar Szemethy <tiv@itc.hu>
8 * and the hostess_sv11 driver
9 *
10 * Contributors:
11 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.14)
12 *
13 * Copyright (C) 1999 ITConsult-Pro Co. <info@itc.hu>
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.10 (99/06/17):
21 * - rewritten for the z85230 layer
22 *
23 * Version 0.11 (99/06/21):
24 * - some printk's fixed
25 * - get rid of a memory leak (it was impossible though :))
26 *
27 * Version 0.12 (99/07/07):
28 * - check CTS for modem lines, not DCD (which is always high
29 * in case of this board)
30 * Version 0.13 (99/07/08):
31 * - Fix the transmitter status check
32 * - Handle the net device statistics better
33 * Version 0.14 (00/08/15):
34 * - resource release on failure at LOCOMX_init
35 */
36
37 #define VERSION "0.14"
38
39 #include <linux/module.h>
40 #include <linux/version.h>
41 #include <linux/types.h>
42 #include <linux/sched.h>
43 #include <linux/netdevice.h>
44 #include <linux/proc_fs.h>
45 #include <asm/types.h>
46 #include <asm/uaccess.h>
47 #include <asm/io.h>
48 #include <asm/dma.h>
49 #include <linux/ioport.h>
50 #include <linux/init.h>
51
52 #include "comx.h"
53 #include "z85230.h"
54
55 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
56 MODULE_DESCRIPTION("Hardware driver for the LoCOMX board");
57 MODULE_LICENSE("GPL");
58
59 #define RX_DMA 3
60 #define TX_DMA 1
61 #define LOCOMX_ID 0x33
62 #define LOCOMX_IO_EXTENT 8
63 #define LOCOMX_DEFAULT_IO 0x368
64 #define LOCOMX_DEFAULT_IRQ 7
65
66 u8 z8530_locomx[] = {
67 11, TCRTxCP,
68 14, DTRREQ,
69 255
70 };
71
72 struct locomx_data {
73 int io_extent;
74 struct z8530_dev board;
75 struct timer_list status_timer;
76 };
77
78 static int LOCOMX_txe(struct net_device *dev)
79 {
80 struct comx_channel *ch = dev->priv;
81 struct locomx_data *hw = ch->HW_privdata;
82
83 return (!hw->board.chanA.tx_next_skb);
84 }
85
86
87 static void locomx_rx(struct z8530_channel *c, struct sk_buff *skb)
88 {
89 struct net_device *dev=c->netdevice;
90 struct comx_channel *ch=dev->priv;
91
92 if (ch->debug_flags & DEBUG_HW_RX) {
93 comx_debug_skb(dev, skb, "locomx_rx receiving");
94 }
95 ch->LINE_rx(dev,skb);
96 }
97
98 static int LOCOMX_send_packet(struct net_device *dev, struct sk_buff *skb)
99 {
100 struct comx_channel *ch = (struct comx_channel *)dev->priv;
101 struct locomx_data *hw = ch->HW_privdata;
102
103 if (ch->debug_flags & DEBUG_HW_TX) {
104 comx_debug_bytes(dev, skb->data, skb->len, "LOCOMX_send_packet");
105 }
106
107 if (!(ch->line_status & LINE_UP)) {
108 return FRAME_DROPPED;
109 }
110
111 if(z8530_queue_xmit(&hw->board.chanA,skb)) {
112 printk(KERN_WARNING "%s: FRAME_DROPPED\n",dev->name);
113 return FRAME_DROPPED;
114 }
115
116 if (ch->debug_flags & DEBUG_HW_TX) {
117 comx_debug(dev, "%s: LOCOMX_send_packet was successful\n\n", dev->name);
118 }
119
120 if(!hw->board.chanA.tx_next_skb) {
121 return FRAME_QUEUED;
122 } else {
123 return FRAME_ACCEPTED;
124 }
125 }
126
127 static void locomx_status_timerfun(unsigned long d)
128 {
129 struct net_device *dev=(struct net_device *)d;
130 struct comx_channel *ch=dev->priv;
131 struct locomx_data *hw=ch->HW_privdata;
132
133 if(!(ch->line_status & LINE_UP) &&
134 (hw->board.chanA.status & CTS)) {
135 ch->LINE_status(dev, ch->line_status | LINE_UP);
136 }
137 if((ch->line_status & LINE_UP) &&
138 !(hw->board.chanA.status & CTS)) {
139 ch->LINE_status(dev, ch->line_status & ~LINE_UP);
140 }
141 mod_timer(&hw->status_timer,jiffies + ch->lineup_delay * HZ);
142 }
143
144
145 static int LOCOMX_open(struct net_device *dev)
146 {
147 struct comx_channel *ch = dev->priv;
148 struct locomx_data *hw = ch->HW_privdata;
149 struct proc_dir_entry *procfile = ch->procdir->subdir;
150 unsigned long flags;
151 int ret;
152
153 if (!dev->base_addr || !dev->irq) {
154 return -ENODEV;
155 }
156
157 if (check_region(dev->base_addr, hw->io_extent)) {
158 return -EAGAIN;
159 }
160
161 request_region(dev->base_addr, hw->io_extent, dev->name);
162
163 hw->board.chanA.ctrlio=dev->base_addr + 5;
164 hw->board.chanA.dataio=dev->base_addr + 7;
165
166 hw->board.irq=dev->irq;
167 hw->board.chanA.netdevice=dev;
168 hw->board.chanA.dev=&hw->board;
169 hw->board.name=dev->name;
170 hw->board.chanA.txdma=TX_DMA;
171 hw->board.chanA.rxdma=RX_DMA;
172 hw->board.chanA.irqs=&z8530_nop;
173 hw->board.chanB.irqs=&z8530_nop;
174
175 if(request_irq(dev->irq, z8530_interrupt, SA_INTERRUPT,
176 dev->name, &hw->board)) {
177 printk(KERN_ERR "%s: unable to obtain irq %d\n", dev->name,
178 dev->irq);
179 ret=-EAGAIN;
180 goto irq_fail;
181 }
182 if(request_dma(TX_DMA,"LoCOMX (TX)")) {
183 printk(KERN_ERR "%s: unable to obtain TX DMA (DMA channel %d)\n",
184 dev->name, TX_DMA);
185 ret=-EAGAIN;
186 goto dma1_fail;
187 }
188
189 if(request_dma(RX_DMA,"LoCOMX (RX)")) {
190 printk(KERN_ERR "%s: unable to obtain RX DMA (DMA channel %d)\n",
191 dev->name, RX_DMA);
192 ret=-EAGAIN;
193 goto dma2_fail;
194 }
195
196 save_flags(flags);
197 cli();
198
199 if(z8530_init(&hw->board)!=0)
200 {
201 printk(KERN_ERR "%s: Z8530 device not found.\n",dev->name);
202 ret=-ENODEV;
203 goto z8530_fail;
204 }
205
206 hw->board.chanA.dcdcheck=CTS;
207
208 z8530_channel_load(&hw->board.chanA, z8530_hdlc_kilostream_85230);
209 z8530_channel_load(&hw->board.chanA, z8530_locomx);
210 z8530_channel_load(&hw->board.chanB, z8530_dead_port);
211
212 z8530_describe(&hw->board, "I/O", dev->base_addr);
213
214 if((ret=z8530_sync_dma_open(dev, &hw->board.chanA))!=0) {
215 goto z8530_fail;
216 }
217
218 restore_flags(flags);
219
220
221 hw->board.active=1;
222 hw->board.chanA.rx_function=locomx_rx;
223
224 ch->init_status |= HW_OPEN;
225 if (hw->board.chanA.status & DCD) {
226 ch->line_status |= LINE_UP;
227 } else {
228 ch->line_status &= ~LINE_UP;
229 }
230
231 comx_status(dev, ch->line_status);
232
233 init_timer(&hw->status_timer);
234 hw->status_timer.function=locomx_status_timerfun;
235 hw->status_timer.data=(unsigned long)dev;
236 hw->status_timer.expires=jiffies + ch->lineup_delay * HZ;
237 add_timer(&hw->status_timer);
238
239 for (; procfile ; procfile = procfile->next) {
240 if (strcmp(procfile->name, FILENAME_IO) == 0 ||
241 strcmp(procfile->name, FILENAME_IRQ) == 0) {
242 procfile->mode = S_IFREG | 0444;
243 }
244 }
245 return 0;
246
247 z8530_fail:
248 restore_flags(flags);
249 free_dma(RX_DMA);
250 dma2_fail:
251 free_dma(TX_DMA);
252 dma1_fail:
253 free_irq(dev->irq, &hw->board);
254 irq_fail:
255 release_region(dev->base_addr, hw->io_extent);
256 return ret;
257 }
258
259 static int LOCOMX_close(struct net_device *dev)
260 {
261 struct comx_channel *ch = dev->priv;
262 struct locomx_data *hw = ch->HW_privdata;
263 struct proc_dir_entry *procfile = ch->procdir->subdir;
264
265 hw->board.chanA.rx_function=z8530_null_rx;
266 netif_stop_queue(dev);
267 z8530_sync_dma_close(dev, &hw->board.chanA);
268
269 z8530_shutdown(&hw->board);
270
271 del_timer(&hw->status_timer);
272 free_dma(RX_DMA);
273 free_dma(TX_DMA);
274 free_irq(dev->irq,&hw->board);
275 release_region(dev->base_addr,8);
276
277 for (; procfile ; procfile = procfile->next) {
278 if (strcmp(procfile->name, FILENAME_IO) == 0 ||
279 strcmp(procfile->name, FILENAME_IRQ) == 0) {
280 procfile->mode = S_IFREG | 0644;
281 }
282 }
283
284 ch->init_status &= ~HW_OPEN;
285 return 0;
286 }
287
288 static int LOCOMX_statistics(struct net_device *dev,char *page)
289 {
290 int len = 0;
291
292 len += sprintf(page + len, "Hello\n");
293
294 return len;
295 }
296
297 static int LOCOMX_dump(struct net_device *dev) {
298 printk(KERN_INFO "LOCOMX_dump called\n");
299 return(-1);
300 }
301
302 static int locomx_read_proc(char *page, char **start, off_t off, int count,
303 int *eof, void *data)
304 {
305 struct proc_dir_entry *file = (struct proc_dir_entry *)data;
306 struct net_device *dev = file->parent->data;
307 int len = 0;
308
309 if (strcmp(file->name, FILENAME_IO) == 0) {
310 len = sprintf(page, "0x%x\n", (unsigned int)dev->base_addr);
311 } else if (strcmp(file->name, FILENAME_IRQ) == 0) {
312 len = sprintf(page, "%d\n", (unsigned int)dev->irq);
313 } else {
314 printk(KERN_ERR "hw_read_proc: internal error, filename %s\n",
315 file->name);
316 return -EBADF;
317 }
318
319 if (off >= len) {
320 *eof = 1;
321 return 0;
322 }
323
324 *start = page + off;
325 if (count >= len - off) {
326 *eof = 1;
327 }
328 return min_t(int, count, len - off);
329 }
330
331 static int locomx_write_proc(struct file *file, const char *buffer,
332 u_long count, void *data)
333 {
334 struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
335 struct net_device *dev = (struct net_device *)entry->parent->data;
336 int val;
337 char *page;
338
339 if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
340 return -ENOMEM;
341 }
342
343 copy_from_user(page, buffer, count = min_t(unsigned long, count, PAGE_SIZE));
344 if (*(page + count - 1) == '\n') {
345 *(page + count - 1) = 0;
346 }
347
348 if (strcmp(entry->name, FILENAME_IO) == 0) {
349 val = simple_strtoul(page, NULL, 0);
350 if (val != 0x360 && val != 0x368 && val != 0x370 &&
351 val != 0x378) {
352 printk(KERN_ERR "LoCOMX: incorrect io address!\n");
353 } else {
354 dev->base_addr = val;
355 }
356 } else if (strcmp(entry->name, FILENAME_IRQ) == 0) {
357 val = simple_strtoul(page, NULL, 0);
358 if (val != 3 && val != 4 && val != 5 && val != 6 && val != 7) {
359 printk(KERN_ERR "LoCOMX: incorrect irq value!\n");
360 } else {
361 dev->irq = val;
362 }
363 } else {
364 printk(KERN_ERR "locomx_write_proc: internal error, filename %s\n",
365 entry->name);
366 free_page((unsigned long)page);
367 return -EBADF;
368 }
369
370 free_page((unsigned long)page);
371 return count;
372 }
373
374
375
376 static int LOCOMX_init(struct net_device *dev)
377 {
378 struct comx_channel *ch = (struct comx_channel *)dev->priv;
379 struct locomx_data *hw;
380 struct proc_dir_entry *new_file;
381
382 /* Alloc data for private structure */
383 if ((ch->HW_privdata = kmalloc(sizeof(struct locomx_data),
384 GFP_KERNEL)) == NULL) {
385 return -ENOMEM;
386 }
387
388 memset(hw = ch->HW_privdata, 0, sizeof(struct locomx_data));
389 hw->io_extent = LOCOMX_IO_EXTENT;
390
391 /* Register /proc files */
392 if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644,
393 ch->procdir)) == NULL) {
394 goto cleanup_HW_privdata;
395 }
396 new_file->data = (void *)new_file;
397 new_file->read_proc = &locomx_read_proc;
398 new_file->write_proc = &locomx_write_proc;
399 new_file->nlink = 1;
400
401 if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644,
402 ch->procdir)) == NULL) {
403 goto cleanup_filename_io;
404 }
405 new_file->data = (void *)new_file;
406 new_file->read_proc = &locomx_read_proc;
407 new_file->write_proc = &locomx_write_proc;
408 new_file->nlink = 1;
409
410 /* No clock yet */
411 /*
412 if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644,
413 ch->procdir)) == NULL) {
414 return -EIO;
415 }
416 new_file->data = (void *)new_file;
417 new_file->read_proc = &locomx_read_proc;
418 new_file->write_proc = &locomx_write_proc;
419 new_file->nlink = 1;
420 */
421
422 ch->HW_access_board = NULL;
423 ch->HW_release_board = NULL;
424 ch->HW_txe = LOCOMX_txe;
425 ch->HW_open = LOCOMX_open;
426 ch->HW_close = LOCOMX_close;
427 ch->HW_send_packet = LOCOMX_send_packet;
428 ch->HW_statistics = LOCOMX_statistics;
429 ch->HW_set_clock = NULL;
430
431 ch->current_stats = &hw->board.chanA.stats;
432 memcpy(ch->current_stats, &ch->stats, sizeof(struct net_device_stats));
433
434 dev->base_addr = LOCOMX_DEFAULT_IO;
435 dev->irq = LOCOMX_DEFAULT_IRQ;
436
437
438 /* O.K. Count one more user on this module */
439 MOD_INC_USE_COUNT;
440 return 0;
441 cleanup_filename_io:
442 remove_proc_entry(FILENAME_IO, ch->procdir);
443 cleanup_HW_privdata:
444 kfree(ch->HW_privdata);
445 return -EIO;
446 }
447
448
449 static int LOCOMX_exit(struct net_device *dev)
450 {
451 struct comx_channel *ch = (struct comx_channel *)dev->priv;
452
453 ch->HW_access_board = NULL;
454 ch->HW_release_board = NULL;
455 ch->HW_txe = NULL;
456 ch->HW_open = NULL;
457 ch->HW_close = NULL;
458 ch->HW_send_packet = NULL;
459 ch->HW_statistics = NULL;
460 ch->HW_set_clock = NULL;
461 memcpy(&ch->stats, ch->current_stats, sizeof(struct net_device_stats));
462 ch->current_stats = &ch->stats;
463
464 kfree(ch->HW_privdata);
465
466 remove_proc_entry(FILENAME_IO, ch->procdir);
467 remove_proc_entry(FILENAME_IRQ, ch->procdir);
468 // remove_proc_entry(FILENAME_CLOCK, ch->procdir);
469
470 MOD_DEC_USE_COUNT;
471 return 0;
472 }
473
474 static struct comx_hardware locomx_hw = {
475 "locomx",
476 VERSION,
477 LOCOMX_init,
478 LOCOMX_exit,
479 LOCOMX_dump,
480 NULL
481 };
482
483 #ifdef MODULE
484 #define comx_hw_locomx_init init_module
485 #endif
486
487 int __init comx_hw_locomx_init(void)
488 {
489 comx_register_hardware(&locomx_hw);
490 return 0;
491 }
492
493 #ifdef MODULE
494 void cleanup_module(void)
495 {
496 comx_unregister_hardware("locomx");
497 return;
498 }
499 #endif
500