This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / 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/interrupt.h>
40 #include <linux/module.h>
41 #include <linux/types.h>
42 #include <linux/netdevice.h>
43 #include <linux/proc_fs.h>
44 #include <linux/ioport.h>
45 #include <linux/init.h>
46
47 #include <asm/types.h>
48 #include <asm/uaccess.h>
49 #include <asm/io.h>
50 #include <asm/dma.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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 = netdev_priv(dev);
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 (!request_region(dev->base_addr, hw->io_extent, dev->name)) {
158                 return -EAGAIN;
159         }
160
161         hw->board.chanA.ctrlio=dev->base_addr + 5;
162         hw->board.chanA.dataio=dev->base_addr + 7;
163         
164         hw->board.irq=dev->irq;
165         hw->board.chanA.netdevice=dev;
166         hw->board.chanA.dev=&hw->board;
167         hw->board.name=dev->name;
168         hw->board.chanA.txdma=TX_DMA;
169         hw->board.chanA.rxdma=RX_DMA;
170         hw->board.chanA.irqs=&z8530_nop;
171         hw->board.chanB.irqs=&z8530_nop;
172
173         if(request_irq(dev->irq, z8530_interrupt, SA_INTERRUPT, 
174             dev->name, &hw->board)) {
175                 printk(KERN_ERR "%s: unable to obtain irq %d\n", dev->name, 
176                         dev->irq);
177                 ret=-EAGAIN;
178                 goto irq_fail;
179         }
180         if(request_dma(TX_DMA,"LoCOMX (TX)")) {
181                 printk(KERN_ERR "%s: unable to obtain TX DMA (DMA channel %d)\n", 
182                         dev->name, TX_DMA);
183                 ret=-EAGAIN;
184                 goto dma1_fail;
185         }
186
187         if(request_dma(RX_DMA,"LoCOMX (RX)")) {
188                 printk(KERN_ERR "%s: unable to obtain RX DMA (DMA channel %d)\n", 
189                         dev->name, RX_DMA);
190                 ret=-EAGAIN;
191                 goto dma2_fail;
192         }
193         
194         save_flags(flags); 
195         cli();
196
197         if(z8530_init(&hw->board)!=0)
198         {
199                 printk(KERN_ERR "%s: Z8530 device not found.\n",dev->name);
200                 ret=-ENODEV;
201                 goto z8530_fail;
202         }
203
204         hw->board.chanA.dcdcheck=CTS;
205
206         z8530_channel_load(&hw->board.chanA, z8530_hdlc_kilostream_85230);
207         z8530_channel_load(&hw->board.chanA, z8530_locomx);
208         z8530_channel_load(&hw->board.chanB, z8530_dead_port);
209
210         z8530_describe(&hw->board, "I/O", dev->base_addr);
211
212         if((ret=z8530_sync_dma_open(dev, &hw->board.chanA))!=0) {
213                 goto z8530_fail;
214         }
215
216         restore_flags(flags);
217
218
219         hw->board.active=1;
220         hw->board.chanA.rx_function=locomx_rx;
221
222         ch->init_status |= HW_OPEN;
223         if (hw->board.chanA.status & DCD) {
224                 ch->line_status |= LINE_UP;
225         } else {
226                 ch->line_status &= ~LINE_UP;
227         }
228
229         comx_status(dev, ch->line_status);
230
231         init_timer(&hw->status_timer);
232         hw->status_timer.function=locomx_status_timerfun;
233         hw->status_timer.data=(unsigned long)dev;
234         hw->status_timer.expires=jiffies + ch->lineup_delay * HZ;
235         add_timer(&hw->status_timer);
236
237         for (; procfile ; procfile = procfile->next) {
238                 if (strcmp(procfile->name, FILENAME_IO) == 0 ||
239                      strcmp(procfile->name, FILENAME_IRQ) == 0) {
240                         procfile->mode = S_IFREG |  0444;
241                 }
242         }
243         return 0;
244
245 z8530_fail:
246         restore_flags(flags);
247         free_dma(RX_DMA);
248 dma2_fail:
249         free_dma(TX_DMA);
250 dma1_fail:
251         free_irq(dev->irq, &hw->board);
252 irq_fail:
253         release_region(dev->base_addr, hw->io_extent);
254         return ret;
255 }
256
257 static int LOCOMX_close(struct net_device *dev)
258 {
259         struct comx_channel *ch = netdev_priv(dev);
260         struct locomx_data *hw = ch->HW_privdata;
261         struct proc_dir_entry *procfile = ch->procdir->subdir;
262
263         hw->board.chanA.rx_function=z8530_null_rx;
264         netif_stop_queue(dev);
265         z8530_sync_dma_close(dev, &hw->board.chanA);
266
267         z8530_shutdown(&hw->board);
268
269         del_timer(&hw->status_timer);
270         free_dma(RX_DMA);
271         free_dma(TX_DMA);
272         free_irq(dev->irq,&hw->board);
273         release_region(dev->base_addr,8);
274
275         for (; procfile ; procfile = procfile->next) {
276                 if (strcmp(procfile->name, FILENAME_IO) == 0 ||
277                     strcmp(procfile->name, FILENAME_IRQ) == 0) {
278                         procfile->mode = S_IFREG |  0644;
279                 }
280         }
281
282         ch->init_status &= ~HW_OPEN;
283         return 0;
284 }
285
286 static int LOCOMX_statistics(struct net_device *dev,char *page)
287 {
288         int len = 0;
289
290         len += sprintf(page + len, "Hello\n");
291
292         return len;
293 }
294
295 static int LOCOMX_dump(struct net_device *dev) {
296         printk(KERN_INFO "LOCOMX_dump called\n");
297         return(-1);
298 }
299
300 static int locomx_read_proc(char *page, char **start, off_t off, int count,
301         int *eof, void *data)
302 {
303         struct proc_dir_entry *file = (struct proc_dir_entry *)data;
304         struct net_device *dev = file->parent->data;
305         int len = 0;
306
307         if (strcmp(file->name, FILENAME_IO) == 0) {
308                 len = sprintf(page, "0x%x\n", (unsigned int)dev->base_addr);
309         } else if (strcmp(file->name, FILENAME_IRQ) == 0) {
310                 len = sprintf(page, "%d\n", (unsigned int)dev->irq);
311         } else {
312                 printk(KERN_ERR "hw_read_proc: internal error, filename %s\n", 
313                         file->name);
314                 return -EBADF;
315         }
316
317         if (off >= len) {
318                 *eof = 1;
319                 return 0;
320         }
321
322         *start = page + off;
323         if (count >= len - off) {
324                 *eof = 1;
325         }
326         return min_t(int, count, len - off);
327 }
328
329 static int locomx_write_proc(struct file *file, const char *buffer,
330         u_long count, void *data)
331 {
332         struct proc_dir_entry *entry = (struct proc_dir_entry *)data;
333         struct net_device *dev = (struct net_device *)entry->parent->data;
334         int val;
335         char *page;
336
337         if (!(page = (char *)__get_free_page(GFP_KERNEL))) {
338                 return -ENOMEM;
339         }
340
341         if (copy_from_user(page, buffer, count = min_t(unsigned long, count, PAGE_SIZE))) {
342                 free_page((unsigned long)page);
343                 return -EBADF;
344         }
345         if (*(page + count - 1) == '\n') {
346                 *(page + count - 1) = 0;
347         }
348
349         if (strcmp(entry->name, FILENAME_IO) == 0) {
350                 val = simple_strtoul(page, NULL, 0);
351                 if (val != 0x360 && val != 0x368 && val != 0x370 && 
352                    val != 0x378) {
353                         printk(KERN_ERR "LoCOMX: incorrect io address!\n");     
354                 } else {
355                         dev->base_addr = val;
356                 }
357         } else if (strcmp(entry->name, FILENAME_IRQ) == 0) {
358                 val = simple_strtoul(page, NULL, 0);
359                 if (val != 3 && val != 4 && val != 5 && val != 6 && val != 7) {
360                         printk(KERN_ERR "LoCOMX: incorrect irq value!\n");
361                 } else {
362                         dev->irq = val;
363                 }       
364         } else {
365                 printk(KERN_ERR "locomx_write_proc: internal error, filename %s\n", 
366                         entry->name);
367                 free_page((unsigned long)page);
368                 return -EBADF;
369         }
370
371         free_page((unsigned long)page);
372         return count;
373 }
374
375
376
377 static int LOCOMX_init(struct net_device *dev) 
378 {
379         struct comx_channel *ch = netdev_priv(dev);
380         struct locomx_data *hw;
381         struct proc_dir_entry *new_file;
382
383         /* Alloc data for private structure */
384         if ((ch->HW_privdata = kmalloc(sizeof(struct locomx_data), 
385            GFP_KERNEL)) == NULL) {
386                 return -ENOMEM;
387         }
388
389         memset(hw = ch->HW_privdata, 0, sizeof(struct locomx_data));
390         hw->io_extent = LOCOMX_IO_EXTENT;
391
392         /* Register /proc files */
393         if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, 
394             ch->procdir)) == NULL) {
395                 goto cleanup_HW_privdata;
396         }
397         new_file->data = (void *)new_file;
398         new_file->read_proc = &locomx_read_proc;
399         new_file->write_proc = &locomx_write_proc;
400         new_file->nlink = 1;
401
402         if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, 
403             ch->procdir)) == NULL)  {
404                 goto cleanup_filename_io;
405         }
406         new_file->data = (void *)new_file;
407         new_file->read_proc = &locomx_read_proc;
408         new_file->write_proc = &locomx_write_proc;
409         new_file->nlink = 1;
410
411 /*      No clock yet */
412 /*
413         if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, 
414             ch->procdir)) == NULL) {
415                 return -EIO;
416         }
417         new_file->data = (void *)new_file;
418         new_file->read_proc = &locomx_read_proc;
419         new_file->write_proc = &locomx_write_proc;
420         new_file->nlink = 1;
421 */
422
423         ch->HW_access_board = NULL;
424         ch->HW_release_board = NULL;
425         ch->HW_txe = LOCOMX_txe;
426         ch->HW_open = LOCOMX_open;
427         ch->HW_close = LOCOMX_close;
428         ch->HW_send_packet = LOCOMX_send_packet;
429         ch->HW_statistics = LOCOMX_statistics;
430         ch->HW_set_clock = NULL;
431
432         ch->current_stats = &hw->board.chanA.stats;
433         memcpy(ch->current_stats, &ch->stats, sizeof(struct net_device_stats));
434
435         dev->base_addr = LOCOMX_DEFAULT_IO;
436         dev->irq = LOCOMX_DEFAULT_IRQ;
437         
438         
439         /* O.K. Count one more user on this module */
440         MOD_INC_USE_COUNT;
441         return 0;
442 cleanup_filename_io:
443         remove_proc_entry(FILENAME_IO, ch->procdir);
444 cleanup_HW_privdata:
445         kfree(ch->HW_privdata);
446         return -EIO;
447 }
448
449
450 static int LOCOMX_exit(struct net_device *dev)
451 {
452         struct comx_channel *ch = netdev_priv(dev);
453
454         ch->HW_access_board = NULL;
455         ch->HW_release_board = NULL;
456         ch->HW_txe = NULL;
457         ch->HW_open = NULL;
458         ch->HW_close = NULL;
459         ch->HW_send_packet = NULL;
460         ch->HW_statistics = NULL;
461         ch->HW_set_clock = NULL;
462         memcpy(&ch->stats, ch->current_stats, sizeof(struct net_device_stats));
463         ch->current_stats = &ch->stats;
464
465         kfree(ch->HW_privdata);
466
467         remove_proc_entry(FILENAME_IO, ch->procdir);
468         remove_proc_entry(FILENAME_IRQ, ch->procdir);
469 //      remove_proc_entry(FILENAME_CLOCK, ch->procdir);
470
471         MOD_DEC_USE_COUNT;
472         return 0;
473 }
474
475 static struct comx_hardware locomx_hw = {
476         "locomx",
477         VERSION,
478         LOCOMX_init, 
479         LOCOMX_exit,
480         LOCOMX_dump,
481         NULL
482 };
483         
484 static int __init comx_hw_locomx_init(void)
485 {
486         comx_register_hardware(&locomx_hw);
487         return 0;
488 }
489
490 static void __exit comx_hw_locomx_exit(void)
491 {
492         comx_unregister_hardware("locomx");
493 }
494
495 module_init(comx_hw_locomx_init);
496 module_exit(comx_hw_locomx_exit);