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