blob: 79bca611d4294d622e1f35bbd93c5c2d117c9561 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2*
3* (c) 1999 by Computone Corporation
4*
5********************************************************************************
6*
7* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
8* serial I/O controllers.
9*
10* DESCRIPTION: Mainline code for the device driver
11*
12*******************************************************************************/
13// ToDo:
14//
15// Fix the immediate DSS_NOW problem.
16// Work over the channel stats return logic in ip2_ipl_ioctl so they
17// make sense for all 256 possible channels and so the user space
18// utilities will compile and work properly.
19//
20// Done:
21//
22// 1.2.14 /\/\|=mhw=|\/\/
23// Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts.
24// Changed the definition of ip2trace to be more consistent with kernel style
25// Thanks to Andreas Dilger <adilger@turbolabs.com> for these updates
26//
27// 1.2.13 /\/\|=mhw=|\/\/
28// DEVFS: Renamed ttf/{n} to tts/F{n} and cuf/{n} to cua/F{n} to conform
29// to agreed devfs serial device naming convention.
30//
31// 1.2.12 /\/\|=mhw=|\/\/
32// Cleaned up some remove queue cut and paste errors
33//
34// 1.2.11 /\/\|=mhw=|\/\/
35// Clean up potential NULL pointer dereferences
36// Clean up devfs registration
37// Add kernel command line parsing for io and irq
Adrian Bunk9c4b5622006-01-19 18:07:10 +010038// Compile defaults for io and irq are now set in ip2.c not ip2.h!
Linus Torvalds1da177e2005-04-16 15:20:36 -070039// Reworked poll_only hack for explicit parameter setting
40// You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
41// Merged ip2_loadmain and old_ip2_init
42// Converted all instances of interruptible_sleep_on into queue calls
43// Most of these had no race conditions but better to clean up now
44//
45// 1.2.10 /\/\|=mhw=|\/\/
46// Fixed the bottom half interrupt handler and enabled USE_IQI
47// to split the interrupt handler into a formal top-half / bottom-half
48// Fixed timing window on high speed processors that queued messages to
49// the outbound mail fifo faster than the board could handle.
50//
51// 1.2.9
52// Four box EX was barfing on >128k kmalloc, made structure smaller by
53// reducing output buffer size
54//
55// 1.2.8
56// Device file system support (MHW)
57//
58// 1.2.7
59// Fixed
60// Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules
61//
62// 1.2.6
63//Fixes DCD problems
64// DCD was not reported when CLOCAL was set on call to TIOCMGET
65//
66//Enhancements:
67// TIOCMGET requests and waits for status return
68// No DSS interrupts enabled except for DCD when needed
69//
70// For internal use only
71//
72//#define IP2DEBUG_INIT
73//#define IP2DEBUG_OPEN
74//#define IP2DEBUG_WRITE
75//#define IP2DEBUG_READ
76//#define IP2DEBUG_IOCTL
77//#define IP2DEBUG_IPL
78
79//#define IP2DEBUG_TRACE
80//#define DEBUG_FIFO
81
82/************/
83/* Includes */
84/************/
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86#include <linux/ctype.h>
87#include <linux/string.h>
88#include <linux/fcntl.h>
89#include <linux/errno.h>
90#include <linux/module.h>
91#include <linux/signal.h>
92#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070093#include <linux/timer.h>
94#include <linux/interrupt.h>
95#include <linux/pci.h>
96#include <linux/mm.h>
97#include <linux/slab.h>
98#include <linux/major.h>
99#include <linux/wait.h>
100#include <linux/device.h>
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600101#include <linux/smp_lock.h>
David Woodhouse547d8bb2008-06-11 16:57:21 +0100102#include <linux/firmware.h>
103#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105#include <linux/tty.h>
106#include <linux/tty_flip.h>
107#include <linux/termios.h>
108#include <linux/tty_driver.h>
109#include <linux/serial.h>
110#include <linux/ptrace.h>
111#include <linux/ioport.h>
112
113#include <linux/cdk.h>
114#include <linux/comstats.h>
115#include <linux/delay.h>
116#include <linux/bitops.h>
117
118#include <asm/system.h>
119#include <asm/io.h>
120#include <asm/irq.h>
121
122#include <linux/vmalloc.h>
123#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125#include <asm/uaccess.h>
126
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100127#include "ip2types.h"
128#include "ip2trace.h"
129#include "ip2ioctl.h"
130#include "ip2.h"
131#include "i2ellis.h"
132#include "i2lib.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134/*****************
135 * /proc/ip2mem *
136 *****************/
137
138#include <linux/proc_fs.h>
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700139#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700141static const struct file_operations ip2mem_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
143
144/********************/
145/* Type Definitions */
146/********************/
147
148/*************/
149/* Constants */
150/*************/
151
152/* String constants to identify ourselves */
153static char *pcName = "Computone IntelliPort Plus multiport driver";
154static char *pcVersion = "1.2.14";
155
156/* String constants for port names */
157static char *pcDriver_name = "ip2";
158static char *pcIpl = "ip2ipl";
159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160/***********************/
161/* Function Prototypes */
162/***********************/
163
164/* Global module entry functions */
165
166/* Private (static) functions */
167static int ip2_open(PTTY, struct file *);
168static void ip2_close(PTTY, struct file *);
Alan Coxd9e39532006-01-09 20:54:20 -0800169static int ip2_write(PTTY, const unsigned char *, int);
Alan Coxf34d7a52008-04-30 00:54:13 -0700170static int ip2_putchar(PTTY, unsigned char);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static void ip2_flush_chars(PTTY);
172static int ip2_write_room(PTTY);
173static int ip2_chars_in_buf(PTTY);
174static void ip2_flush_buffer(PTTY);
175static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);
Alan Cox606d0992006-12-08 02:38:45 -0800176static void ip2_set_termios(PTTY, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177static void ip2_set_line_discipline(PTTY);
178static void ip2_throttle(PTTY);
179static void ip2_unthrottle(PTTY);
180static void ip2_stop(PTTY);
181static void ip2_start(PTTY);
182static void ip2_hangup(PTTY);
183static int ip2_tiocmget(struct tty_struct *tty, struct file *file);
184static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
185 unsigned int set, unsigned int clear);
186
187static void set_irq(int, int);
David Howellsc4028952006-11-22 14:57:56 +0000188static void ip2_interrupt_bh(struct work_struct *work);
David Howells7d12e782006-10-05 14:55:46 +0100189static irqreturn_t ip2_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void ip2_poll(unsigned long arg);
191static inline void service_all_boards(void);
David Howellsc4028952006-11-22 14:57:56 +0000192static void do_input(struct work_struct *);
193static void do_status(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195static void ip2_wait_until_sent(PTTY,int);
196
Alan Cox606d0992006-12-08 02:38:45 -0800197static void set_params (i2ChanStrPtr, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *);
199static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *);
200
201static ssize_t ip2_ipl_read(struct file *, char __user *, size_t, loff_t *);
202static ssize_t ip2_ipl_write(struct file *, const char __user *, size_t, loff_t *);
Alan Cox47be36a2008-07-25 01:48:13 -0700203static long ip2_ipl_ioctl(struct file *, UINT, ULONG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static int ip2_ipl_open(struct inode *, struct file *);
205
206static int DumpTraceBuffer(char __user *, int);
207static int DumpFifoBuffer( char __user *, int);
208
David Woodhouse547d8bb2008-06-11 16:57:21 +0100209static void ip2_init_board(int, const struct firmware *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210static unsigned short find_eisa_board(int);
211
212/***************/
213/* Static Data */
214/***************/
215
216static struct tty_driver *ip2_tty_driver;
217
218/* Here, then is a table of board pointers which the interrupt routine should
219 * scan through to determine who it must service.
220 */
221static unsigned short i2nBoards; // Number of boards here
222
223static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS];
224
225static i2ChanStrPtr DevTable[IP2_MAX_PORTS];
226//DevTableMem just used to save addresses for kfree
227static void *DevTableMem[IP2_MAX_BOARDS];
228
229/* This is the driver descriptor for the ip2ipl device, which is used to
230 * download the loadware to the boards.
231 */
Arjan van de Ven62322d22006-07-03 00:24:21 -0700232static const struct file_operations ip2_ipl = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 .owner = THIS_MODULE,
234 .read = ip2_ipl_read,
235 .write = ip2_ipl_write,
Alan Cox47be36a2008-07-25 01:48:13 -0700236 .unlocked_ioctl = ip2_ipl_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 .open = ip2_ipl_open,
238};
239
240static unsigned long irq_counter = 0;
241static unsigned long bh_counter = 0;
242
243// Use immediate queue to service interrupts
244#define USE_IQI
245//#define USE_IQ // PCI&2.2 needs work
246
247/* The timer_list entry for our poll routine. If interrupt operation is not
248 * selected, the board is serviced periodically to see if anything needs doing.
249 */
250#define POLL_TIMEOUT (jiffies + 1)
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700251static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252static char TimerOn;
253
254#ifdef IP2DEBUG_TRACE
255/* Trace (debug) buffer data */
256#define TRACEMAX 1000
257static unsigned long tracebuf[TRACEMAX];
258static int tracestuff;
259static int tracestrip;
260static int tracewrap;
261#endif
262
263/**********/
264/* Macros */
265/**********/
266
267#if defined(MODULE) && defined(IP2DEBUG_OPEN)
268#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
269 tty->name,(pCh->flags),ip2_tty_driver->refcount, \
270 tty->count,/*GET_USE_COUNT(module)*/0,s)
271#else
272#define DBG_CNT(s)
273#endif
274
275/********/
276/* Code */
277/********/
278
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100279#include "i2ellis.c" /* Extremely low-level interface services */
280#include "i2cmd.c" /* Standard loadware command definitions */
281#include "i2lib.c" /* High level interface services */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283/* Configuration area for modprobe */
284
285MODULE_AUTHOR("Doug McNash");
286MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
Jiri Slaby47babd42008-10-13 10:34:27 +0100287MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289static int poll_only = 0;
290
291static int Eisa_irq;
292static int Eisa_slot;
293
294static int iindx;
295static char rirqs[IP2_MAX_BOARDS];
296static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
297
Jiri Slaby47babd42008-10-13 10:34:27 +0100298/* Note: Add compiled in defaults to these arrays, not to the structure
299 in ip2.h any longer. That structure WILL get overridden
300 by these values, or command line values, or insmod values!!! =mhw=
301*/
302static int io[IP2_MAX_BOARDS];
303static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
304
305MODULE_AUTHOR("Doug McNash");
306MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
307module_param_array(irq, int, NULL, 0);
308MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
309module_param_array(io, int, NULL, 0);
310MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
311module_param(poll_only, bool, 0);
312MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314/* for sysfs class support */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800315static struct class *ip2_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317// Some functions to keep track of what irq's we have
318
Randy Dunlap673e3212006-06-25 05:48:39 -0700319static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320is_valid_irq(int irq)
321{
322 int *i = Valid_Irqs;
323
324 while ((*i != 0) && (*i != irq)) {
325 i++;
326 }
327 return (*i);
328}
329
Randy Dunlap673e3212006-06-25 05:48:39 -0700330static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331mark_requested_irq( char irq )
332{
333 rirqs[iindx++] = irq;
334}
335
336#ifdef MODULE
Randy Dunlap673e3212006-06-25 05:48:39 -0700337static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338clear_requested_irq( char irq )
339{
340 int i;
341 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
342 if (rirqs[i] == irq) {
343 rirqs[i] = 0;
344 return 1;
345 }
346 }
347 return 0;
348}
349#endif
350
Randy Dunlap673e3212006-06-25 05:48:39 -0700351static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352have_requested_irq( char irq )
353{
354 // array init to zeros so 0 irq will not be requested as a side effect
355 int i;
356 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
357 if (rirqs[i] == irq)
358 return 1;
359 }
360 return 0;
361}
362
363/******************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364/* Function: cleanup_module() */
365/* Parameters: None */
366/* Returns: Nothing */
367/* */
368/* Description: */
369/* This is a required entry point for an installable module. It has to return */
370/* the device and the driver to a passive state. It should not be necessary */
371/* to reset the board fully, especially as the loadware is downloaded */
372/* externally rather than in the driver. We just want to disable the board */
373/* and clear the loadware to a reset state. To allow this there has to be a */
374/* way to detect whether the board has the loadware running at init time to */
375/* handle subsequent installations of the driver. All memory allocated by the */
376/* driver should be returned since it may be unloaded from memory. */
377/******************************************************************************/
378#ifdef MODULE
Jon Schindler83e422b2008-04-30 00:53:53 -0700379void __exit
380ip2_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
382 int err;
383 int i;
384
385#ifdef IP2DEBUG_INIT
386 printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );
387#endif
388 /* Stop poll timer if we had one. */
389 if ( TimerOn ) {
390 del_timer ( &PollTimer );
391 TimerOn = 0;
392 }
393
394 /* Reset the boards we have. */
395 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
396 if ( i2BoardPtrTable[i] ) {
397 iiReset( i2BoardPtrTable[i] );
398 }
399 }
400
401 /* The following is done at most once, if any boards were installed. */
402 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
403 if ( i2BoardPtrTable[i] ) {
404 iiResetDelay( i2BoardPtrTable[i] );
405 /* free io addresses and Tibet */
406 release_region( ip2config.addr[i], 8 );
tonyj@suse.de07c015e2007-08-07 22:28:44 -0700407 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
408 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 }
410 /* Disable and remove interrupt handler. */
411 if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {
412 free_irq ( ip2config.irq[i], (void *)&pcName);
413 clear_requested_irq( ip2config.irq[i]);
414 }
415 }
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800416 class_destroy(ip2_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
418 printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
419 }
420 put_tty_driver(ip2_tty_driver);
Akinobu Mita68fc4fa2007-07-19 01:47:50 -0700421 unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
Alexey Dobriyanc74c1202008-04-29 01:01:44 -0700422 remove_proc_entry("ip2mem", NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
424 // free memory
425 for (i = 0; i < IP2_MAX_BOARDS; i++) {
426 void *pB;
427#ifdef CONFIG_PCI
428 if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
429 pci_disable_device(ip2config.pci_dev[i]);
Alan Cox1aff0ec2006-09-30 23:27:59 -0700430 pci_dev_put(ip2config.pci_dev[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 ip2config.pci_dev[i] = NULL;
432 }
433#endif
434 if ((pB = i2BoardPtrTable[i]) != 0 ) {
435 kfree ( pB );
436 i2BoardPtrTable[i] = NULL;
437 }
438 if ((DevTableMem[i]) != NULL ) {
439 kfree ( DevTableMem[i] );
440 DevTableMem[i] = NULL;
441 }
442 }
443
444 /* Cleanup the iiEllis subsystem. */
445 iiEllisCleanup();
446#ifdef IP2DEBUG_INIT
447 printk (KERN_DEBUG "IP2 Unloaded\n" );
448#endif
449}
Jon Schindler83e422b2008-04-30 00:53:53 -0700450module_exit(ip2_cleanup_module);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451#endif /* MODULE */
452
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700453static const struct tty_operations ip2_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 .open = ip2_open,
455 .close = ip2_close,
456 .write = ip2_write,
457 .put_char = ip2_putchar,
458 .flush_chars = ip2_flush_chars,
459 .write_room = ip2_write_room,
460 .chars_in_buffer = ip2_chars_in_buf,
461 .flush_buffer = ip2_flush_buffer,
462 .ioctl = ip2_ioctl,
463 .throttle = ip2_throttle,
464 .unthrottle = ip2_unthrottle,
465 .set_termios = ip2_set_termios,
466 .set_ldisc = ip2_set_line_discipline,
467 .stop = ip2_stop,
468 .start = ip2_start,
469 .hangup = ip2_hangup,
470 .read_proc = ip2_read_proc,
471 .tiocmget = ip2_tiocmget,
472 .tiocmset = ip2_tiocmset,
473};
474
475/******************************************************************************/
476/* Function: ip2_loadmain() */
477/* Parameters: irq, io from command line of insmod et. al. */
478/* pointer to fip firmware and firmware size for boards */
479/* Returns: Success (0) */
480/* */
481/* Description: */
482/* This was the required entry point for all drivers (now in ip2.c) */
483/* It performs all */
484/* initialisation of the devices and driver structures, and registers itself */
485/* with the relevant kernel modules. */
486/******************************************************************************/
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700487/* IRQF_DISABLED - if set blocks all interrupts else only this line */
488/* IRQF_SHARED - for shared irq PCI or maybe EISA only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489/* SA_RANDOM - can be source for cert. random number generators */
490#define IP2_SA_FLAGS 0
491
David Woodhouse547d8bb2008-06-11 16:57:21 +0100492
493static const struct firmware *ip2_request_firmware(void)
494{
495 struct platform_device *pdev;
496 const struct firmware *fw;
497
498 pdev = platform_device_register_simple("ip2", 0, NULL, 0);
499 if (IS_ERR(pdev)) {
500 printk(KERN_ERR "Failed to register platform device for ip2\n");
501 return NULL;
502 }
503 if (request_firmware(&fw, "intelliport2.bin", &pdev->dev)) {
504 printk(KERN_ERR "Failed to load firmware 'intelliport2.bin'\n");
505 fw = NULL;
506 }
507 platform_device_unregister(pdev);
508 return fw;
509}
510
Jiri Slaby47babd42008-10-13 10:34:27 +0100511#ifndef MODULE
512/******************************************************************************
513 * ip2_setup:
514 * str: kernel command line string
515 *
516 * Can't autoprobe the boards so user must specify configuration on
517 * kernel command line. Sane people build it modular but the others
518 * come here.
519 *
520 * Alternating pairs of io,irq for up to 4 boards.
521 * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
522 *
523 * io=0 => No board
524 * io=1 => PCI
525 * io=2 => EISA
526 * else => ISA I/O address
527 *
528 * irq=0 or invalid for ISA will revert to polling mode
529 *
530 * Any value = -1, do not overwrite compiled in value.
531 *
532 ******************************************************************************/
533static int __init ip2_setup(char *str)
534{
535 int j, ints[10]; /* 4 boards, 2 parameters + 2 */
536 unsigned int i;
537
538 str = get_options(str, ARRAY_SIZE(ints), ints);
539
540 for (i = 0, j = 1; i < 4; i++) {
541 if (j > ints[0])
542 break;
543 if (ints[j] >= 0)
544 io[i] = ints[j];
545 j++;
546 if (j > ints[0])
547 break;
548 if (ints[j] >= 0)
549 irq[i] = ints[j];
550 j++;
551 }
552 return 1;
553}
554__setup("ip2=", ip2_setup);
555#endif /* !MODULE */
556
557static int ip2_loadmain(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
559 int i, j, box;
560 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 static int loaded;
562 i2eBordStrPtr pB = NULL;
563 int rc = -1;
Alan Cox1aff0ec2006-09-30 23:27:59 -0700564 static struct pci_dev *pci_dev_i = NULL;
David Woodhouse547d8bb2008-06-11 16:57:21 +0100565 const struct firmware *fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Jiri Slaby47babd42008-10-13 10:34:27 +0100567 if (poll_only) {
568 /* Hard lock the interrupts to zero */
569 irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
570 }
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
573
574 /* process command line arguments to modprobe or
575 insmod i.e. iop & irqp */
576 /* irqp and iop should ALWAYS be specified now... But we check
577 them individually just to be sure, anyways... */
578 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
Jiri Slaby47babd42008-10-13 10:34:27 +0100579 ip2config.addr[i] = io[i];
580 if (irq[i] >= 0)
581 ip2config.irq[i] = irq[i];
582 else
583 ip2config.irq[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 // This is a little bit of a hack. If poll_only=1 on command
585 // line back in ip2.c OR all IRQs on all specified boards are
586 // explicitly set to 0, then drop to poll only mode and override
587 // PCI or EISA interrupts. This superceeds the old hack of
588 // triggering if all interrupts were zero (like da default).
589 // Still a hack but less prone to random acts of terrorism.
590 //
591 // What we really should do, now that the IRQ default is set
592 // to -1, is to use 0 as a hard coded, do not probe.
593 //
594 // /\/\|=mhw=|\/\/
Jiri Slaby47babd42008-10-13 10:34:27 +0100595 poll_only |= irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 }
597 poll_only = !poll_only;
598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 /* Announce our presence */
600 printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
601
602 // ip2 can be unloaded and reloaded for no good reason
603 // we can't let that happen here or bad things happen
604 // second load hoses board but not system - fixme later
605 if (loaded) {
606 printk( KERN_INFO "Still loaded\n" );
607 return 0;
608 }
609 loaded++;
610
611 ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
612 if (!ip2_tty_driver)
613 return -ENOMEM;
614
615 /* Initialise the iiEllis subsystem. */
616 iiEllisInit();
617
618 /* Initialize arrays. */
619 memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable );
620 memset( DevTable, 0, sizeof DevTable );
621
622 /* Initialise all the boards we can find (up to the maximum). */
623 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
624 switch ( ip2config.addr[i] ) {
625 case 0: /* skip this slot even if card is present */
626 break;
627 default: /* ISA */
628 /* ISA address must be specified */
629 if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) {
630 printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n",
631 i, ip2config.addr[i] );
632 ip2config.addr[i] = 0;
633 } else {
634 ip2config.type[i] = ISA;
635
636 /* Check for valid irq argument, set for polling if invalid */
637 if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) {
638 printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]);
639 ip2config.irq[i] = 0;// 0 is polling and is valid in that sense
640 }
641 }
642 break;
643 case PCI:
644#ifdef CONFIG_PCI
645 {
Andrew Mortonad4a5bb2007-07-31 00:39:41 -0700646 int status;
647
Alan Cox1aff0ec2006-09-30 23:27:59 -0700648 pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
650 if (pci_dev_i != NULL) {
651 unsigned int addr;
652
653 if (pci_enable_device(pci_dev_i)) {
654 printk( KERN_ERR "IP2: can't enable PCI device at %s\n",
655 pci_name(pci_dev_i));
656 break;
657 }
658 ip2config.type[i] = PCI;
Alan Cox1aff0ec2006-09-30 23:27:59 -0700659 ip2config.pci_dev[i] = pci_dev_get(pci_dev_i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 status =
661 pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
662 if ( addr & 1 ) {
663 ip2config.addr[i]=(USHORT)(addr&0xfffe);
664 } else {
665 printk( KERN_ERR "IP2: PCI I/O address error\n");
666 }
667
668// If the PCI BIOS assigned it, lets try and use it. If we
669// can't acquire it or it screws up, deal with it then.
670
671// if (!is_valid_irq(pci_irq)) {
672// printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
673// pci_irq = 0;
674// }
675 ip2config.irq[i] = pci_dev_i->irq;
676 } else { // ann error
677 ip2config.addr[i] = 0;
Jeff Garzik2b0172e2007-10-16 23:30:31 -0700678 printk(KERN_ERR "IP2: PCI board %d not found\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 }
680 }
681#else
682 printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
683 printk( KERN_ERR "IP2: configured in this kernel.\n");
684 printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n");
685#endif /* CONFIG_PCI */
686 break;
687 case EISA:
688 if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) {
689 /* Eisa_irq set as side effect, boo */
690 ip2config.type[i] = EISA;
691 }
692 ip2config.irq[i] = Eisa_irq;
693 break;
694 } /* switch */
695 } /* for */
Alan Cox1aff0ec2006-09-30 23:27:59 -0700696 if (pci_dev_i)
697 pci_dev_put(pci_dev_i);
698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
700 if ( ip2config.addr[i] ) {
Mariusz Kozlowski978550b82007-10-16 23:26:45 -0700701 pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
702 if (pB) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 i2BoardPtrTable[i] = pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer );
705 iiReset( pB );
706 } else {
707 printk(KERN_ERR "IP2: board memory allocation error\n");
708 }
709 }
710 }
711 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
712 if ( ( pB = i2BoardPtrTable[i] ) != NULL ) {
713 iiResetDelay( pB );
714 break;
715 }
716 }
717 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100718 /* We don't want to request the firmware unless we have at
719 least one board */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 if ( i2BoardPtrTable[i] != NULL ) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100721 if (!fw)
722 fw = ip2_request_firmware();
723 if (!fw)
724 break;
725 ip2_init_board(i, fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 }
727 }
David Woodhouse547d8bb2008-06-11 16:57:21 +0100728 if (fw)
729 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730
731 ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 );
732
733 ip2_tty_driver->owner = THIS_MODULE;
734 ip2_tty_driver->name = "ttyF";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 ip2_tty_driver->driver_name = pcDriver_name;
736 ip2_tty_driver->major = IP2_TTY_MAJOR;
737 ip2_tty_driver->minor_start = 0;
738 ip2_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
739 ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL;
740 ip2_tty_driver->init_termios = tty_std_termios;
741 ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -0700742 ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 tty_set_operations(ip2_tty_driver, &ip2_ops);
744
745 ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
746
747 /* Register the tty devices. */
748 if ( ( err = tty_register_driver ( ip2_tty_driver ) ) ) {
749 printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err);
750 put_tty_driver(ip2_tty_driver);
751 return -EINVAL;
752 } else
753 /* Register the IPL driver. */
754 if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
755 printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
756 } else {
757 /* create the sysfs class */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800758 ip2_class = class_create(THIS_MODULE, "ip2");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (IS_ERR(ip2_class)) {
760 err = PTR_ERR(ip2_class);
761 goto out_chrdev;
762 }
763 }
764 /* Register the read_procmem thing */
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700765 if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 printk(KERN_ERR "IP2: failed to register read_procmem\n");
767 } else {
768
769 ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 );
770 /* Register the interrupt handler or poll handler, depending upon the
771 * specified interrupt.
772 */
773
774 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
775 if ( 0 == ip2config.addr[i] ) {
776 continue;
777 }
778
779 if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
Greg Kroah-Hartman47aa5792008-05-21 12:52:33 -0700780 device_create_drvdata(ip2_class, NULL,
781 MKDEV(IP2_IPL_MAJOR, 4 * i),
782 NULL, "ipl%d", i);
783 device_create_drvdata(ip2_class, NULL,
784 MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
785 NULL, "stat%d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 for ( box = 0; box < ABS_MAX_BOXES; ++box )
788 {
789 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
790 {
791 if ( pB->i2eChannelMap[box] & (1 << j) )
792 {
793 tty_register_device(ip2_tty_driver,
794 j + ABS_BIGGEST_BOX *
795 (box+i*ABS_MAX_BOXES), NULL);
796 }
797 }
798 }
799 }
800
801 if (poll_only) {
802// Poll only forces driver to only use polling and
803// to ignore the probed PCI or EISA interrupts.
804 ip2config.irq[i] = CIR_POLL;
805 }
806 if ( ip2config.irq[i] == CIR_POLL ) {
807retry:
808 if (!TimerOn) {
809 PollTimer.expires = POLL_TIMEOUT;
810 add_timer ( &PollTimer );
811 TimerOn = 1;
812 printk( KERN_INFO "IP2: polling\n");
813 }
814 } else {
815 if (have_requested_irq(ip2config.irq[i]))
816 continue;
817 rc = request_irq( ip2config.irq[i], ip2_interrupt,
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700818 IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
Jeff Garzik6bd3bd62007-10-19 15:38:40 -0400819 pcName, i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 if (rc) {
821 printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
822 ip2config.irq[i] = CIR_POLL;
823 printk( KERN_INFO "IP2: Polling %ld/sec.\n",
824 (POLL_TIMEOUT - jiffies));
825 goto retry;
826 }
827 mark_requested_irq(ip2config.irq[i]);
828 /* Initialise the interrupt handler bottom half (aka slih). */
829 }
830 }
831 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
832 if ( i2BoardPtrTable[i] ) {
833 set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
834 }
835 }
836 }
837 ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
838 goto out;
839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840out_chrdev:
841 unregister_chrdev(IP2_IPL_MAJOR, "ip2");
842out:
843 return err;
844}
Jiri Slaby47babd42008-10-13 10:34:27 +0100845module_init(ip2_loadmain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847/******************************************************************************/
848/* Function: ip2_init_board() */
849/* Parameters: Index of board in configuration structure */
850/* Returns: Success (0) */
851/* */
852/* Description: */
853/* This function initializes the specified board. The loadware is copied to */
854/* the board, the channel structures are initialized, and the board details */
855/* are reported on the console. */
856/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700857static void
David Woodhouse547d8bb2008-06-11 16:57:21 +0100858ip2_init_board(int boardnum, const struct firmware *fw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859{
860 int i;
861 int nports = 0, nboxes = 0;
862 i2ChanStrPtr pCh;
863 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
864
865 if ( !iiInitialize ( pB ) ) {
866 printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
867 pB->i2eBase, pB->i2eError );
868 goto err_initialize;
869 }
870 printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
871 ip2config.addr[boardnum], ip2config.irq[boardnum] );
872
873 if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
874 printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
875 goto err_initialize;
876 }
877
David Woodhouse547d8bb2008-06-11 16:57:21 +0100878 if ( iiDownloadAll ( pB, (loadHdrStrPtr)fw->data, 1, fw->size )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 != II_DOWN_GOOD ) {
880 printk ( KERN_ERR "IP2: failed to download loadware\n" );
881 goto err_release_region;
882 } else {
883 printk ( KERN_INFO "IP2: fv=%d.%d.%d lv=%d.%d.%d\n",
884 pB->i2ePom.e.porVersion,
885 pB->i2ePom.e.porRevision,
886 pB->i2ePom.e.porSubRev, pB->i2eLVersion,
887 pB->i2eLRevision, pB->i2eLSub );
888 }
889
890 switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
891
892 default:
893 printk( KERN_ERR "IP2: Unknown board type, ID = %x\n",
894 pB->i2ePom.e.porID );
895 nports = 0;
896 goto err_release_region;
897 break;
898
899 case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
900 printk ( KERN_INFO "IP2: ISA-4\n" );
901 nports = 4;
902 break;
903
904 case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
905 printk ( KERN_INFO "IP2: ISA-8 std\n" );
906 nports = 8;
907 break;
908
909 case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
910 printk ( KERN_INFO "IP2: ISA-8 RJ11\n" );
911 nports = 8;
912 break;
913
914 case POR_ID_FIIEX: /* IntelliPort IIEX */
915 {
916 int portnum = IP2_PORTS_PER_BOARD * boardnum;
917 int box;
918
919 for( box = 0; box < ABS_MAX_BOXES; ++box ) {
920 if ( pB->i2eChannelMap[box] != 0 ) {
921 ++nboxes;
922 }
923 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
924 if ( pB->i2eChannelMap[box] & 1<< i ) {
925 ++nports;
926 }
927 }
928 }
929 DevTableMem[boardnum] = pCh =
930 kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
931 if ( !pCh ) {
932 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
933 goto err_release_region;
934 }
935 if ( !i2InitChannels( pB, nports, pCh ) ) {
936 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
937 kfree ( pCh );
938 goto err_release_region;
939 }
940 pB->i2eChannelPtr = &DevTable[portnum];
941 pB->i2eChannelCnt = ABS_MOST_PORTS;
942
943 for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
944 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
945 if ( pB->i2eChannelMap[box] & (1 << i) ) {
946 DevTable[portnum + i] = pCh;
947 pCh->port_index = portnum + i;
948 pCh++;
949 }
950 }
951 }
952 printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit\n",
953 nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
954 }
955 goto ex_exit;
956 }
957 DevTableMem[boardnum] = pCh =
958 kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
959 if ( !pCh ) {
960 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
961 goto err_release_region;
962 }
963 pB->i2eChannelPtr = pCh;
964 pB->i2eChannelCnt = nports;
965 if ( !i2InitChannels( pB, nports, pCh ) ) {
966 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
967 kfree ( pCh );
968 goto err_release_region;
969 }
970 pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
971
972 for( i = 0; i < pB->i2eChannelCnt; ++i ) {
973 DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
974 pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
975 pCh++;
976 }
977ex_exit:
David Howellsc4028952006-11-22 14:57:56 +0000978 INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 return;
980
981err_release_region:
982 release_region(ip2config.addr[boardnum], 8);
983err_initialize:
984 kfree ( pB );
985 i2BoardPtrTable[boardnum] = NULL;
986 return;
987}
988
989/******************************************************************************/
990/* Function: find_eisa_board ( int start_slot ) */
991/* Parameters: First slot to check */
992/* Returns: Address of EISA IntelliPort II controller */
993/* */
994/* Description: */
995/* This function searches for an EISA IntelliPort controller, starting */
996/* from the specified slot number. If the motherboard is not identified as an */
997/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
998/* it returns the base address of the controller. */
999/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -07001000static unsigned short
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001find_eisa_board( int start_slot )
1002{
1003 int i, j;
1004 unsigned int idm = 0;
1005 unsigned int idp = 0;
1006 unsigned int base = 0;
1007 unsigned int value;
1008 int setup_address;
1009 int setup_irq;
1010 int ismine = 0;
1011
1012 /*
1013 * First a check for an EISA motherboard, which we do by comparing the
1014 * EISA ID registers for the system board and the first couple of slots.
1015 * No slot ID should match the system board ID, but on an ISA or PCI
1016 * machine the odds are that an empty bus will return similar values for
1017 * each slot.
1018 */
1019 i = 0x0c80;
1020 value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
1021 for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
1022 j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
1023 if ( value == j )
1024 return 0;
1025 }
1026
1027 /*
1028 * OK, so we are inclined to believe that this is an EISA machine. Find
1029 * an IntelliPort controller.
1030 */
1031 for( i = start_slot; i < 16; i++ ) {
1032 base = i << 12;
1033 idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
1034 idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
1035 ismine = 0;
1036 if ( idm == 0x0e8e ) {
1037 if ( idp == 0x0281 || idp == 0x0218 ) {
1038 ismine = 1;
1039 } else if ( idp == 0x0282 || idp == 0x0283 ) {
1040 ismine = 3; /* Can do edge-trigger */
1041 }
1042 if ( ismine ) {
1043 Eisa_slot = i;
1044 break;
1045 }
1046 }
1047 }
1048 if ( !ismine )
1049 return 0;
1050
1051 /* It's some sort of EISA card, but at what address is it configured? */
1052
1053 setup_address = base + 0xc88;
1054 value = inb(base + 0xc86);
1055 setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
1056
1057 if ( (ismine & 2) && !(value & 0x10) ) {
1058 ismine = 1; /* Could be edging, but not */
1059 }
1060
1061 if ( Eisa_irq == 0 ) {
1062 Eisa_irq = setup_irq;
1063 } else if ( Eisa_irq != setup_irq ) {
1064 printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
1065 }
1066
1067#ifdef IP2DEBUG_INIT
1068printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
1069 base >> 12, idm, idp, setup_address);
1070 if ( Eisa_irq ) {
1071 printk(KERN_DEBUG ", Interrupt %d %s\n",
1072 setup_irq, (ismine & 2) ? "(edge)" : "(level)");
1073 } else {
1074 printk(KERN_DEBUG ", (polled)\n");
1075 }
1076#endif
1077 return setup_address;
1078}
1079
1080/******************************************************************************/
1081/* Function: set_irq() */
1082/* Parameters: index to board in board table */
1083/* IRQ to use */
1084/* Returns: Success (0) */
1085/* */
1086/* Description: */
1087/******************************************************************************/
1088static void
1089set_irq( int boardnum, int boardIrq )
1090{
1091 unsigned char tempCommand[16];
1092 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
1093 unsigned long flags;
1094
1095 /*
1096 * Notify the boards they may generate interrupts. This is done by
1097 * sending an in-line command to channel 0 on each board. This is why
1098 * the channels have to be defined already. For each board, if the
1099 * interrupt has never been defined, we must do so NOW, directly, since
1100 * board will not send flow control or even give an interrupt until this
1101 * is done. If polling we must send 0 as the interrupt parameter.
1102 */
1103
1104 // We will get an interrupt here at the end of this function
1105
1106 iiDisableMailIrq(pB);
1107
1108 /* We build up the entire packet header. */
1109 CHANNEL_OF(tempCommand) = 0;
1110 PTYPE_OF(tempCommand) = PTYPE_INLINE;
1111 CMD_COUNT_OF(tempCommand) = 2;
1112 (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
1113 (CMD_OF(tempCommand))[1] = boardIrq;
1114 /*
1115 * Write to FIFO; don't bother to adjust fifo capacity for this, since
1116 * board will respond almost immediately after SendMail hit.
1117 */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001118 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001120 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 pB->i2eUsingIrq = boardIrq;
1122 pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
1123
1124 /* Need to update number of boards before you enable mailbox int */
1125 ++i2nBoards;
1126
1127 CHANNEL_OF(tempCommand) = 0;
1128 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1129 CMD_COUNT_OF(tempCommand) = 6;
1130 (CMD_OF(tempCommand))[0] = 88; // SILO
1131 (CMD_OF(tempCommand))[1] = 64; // chars
1132 (CMD_OF(tempCommand))[2] = 32; // ms
1133
1134 (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK
1135 (CMD_OF(tempCommand))[4] = 64; // chars
1136
1137 (CMD_OF(tempCommand))[5] = 87; // HW_TEST
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001138 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 iiWriteBuf(pB, tempCommand, 8);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001140 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
1142 CHANNEL_OF(tempCommand) = 0;
1143 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1144 CMD_COUNT_OF(tempCommand) = 1;
1145 (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */
1146 iiWriteBuf(pB, tempCommand, 3);
1147
1148#ifdef XXX
1149 // enable heartbeat for test porpoises
1150 CHANNEL_OF(tempCommand) = 0;
1151 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1152 CMD_COUNT_OF(tempCommand) = 2;
1153 (CMD_OF(tempCommand))[0] = 44; /* get ping */
1154 (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001155 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001157 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158#endif
1159
1160 iiEnableMailIrq(pB);
1161 iiSendPendingMail(pB);
1162}
1163
1164/******************************************************************************/
1165/* Interrupt Handler Section */
1166/******************************************************************************/
1167
1168static inline void
1169service_all_boards(void)
1170{
1171 int i;
1172 i2eBordStrPtr pB;
1173
1174 /* Service every board on the list */
1175 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
1176 pB = i2BoardPtrTable[i];
1177 if ( pB ) {
1178 i2ServiceBoard( pB );
1179 }
1180 }
1181}
1182
1183
1184/******************************************************************************/
David Howellsc4028952006-11-22 14:57:56 +00001185/* Function: ip2_interrupt_bh(work) */
1186/* Parameters: work - pointer to the board structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187/* Returns: Nothing */
1188/* */
1189/* Description: */
1190/* Service the board in a bottom half interrupt handler and then */
1191/* reenable the board's interrupts if it has an IRQ number */
1192/* */
1193/******************************************************************************/
1194static void
David Howellsc4028952006-11-22 14:57:56 +00001195ip2_interrupt_bh(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196{
David Howellsc4028952006-11-22 14:57:56 +00001197 i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198// pB better well be set or we have a problem! We can only get
1199// here from the IMMEDIATE queue. Here, we process the boards.
1200// Checking pB doesn't cost much and it saves us from the sanity checkers.
1201
1202 bh_counter++;
1203
1204 if ( pB ) {
1205 i2ServiceBoard( pB );
1206 if( pB->i2eUsingIrq ) {
1207// Re-enable his interrupts
1208 iiEnableMailIrq(pB);
1209 }
1210 }
1211}
1212
1213
1214/******************************************************************************/
David Howells7d12e782006-10-05 14:55:46 +01001215/* Function: ip2_interrupt(int irq, void *dev_id) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216/* Parameters: irq - interrupt number */
1217/* pointer to optional device ID structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218/* Returns: Nothing */
1219/* */
1220/* Description: */
1221/* */
1222/* Our task here is simply to identify each board which needs servicing. */
1223/* If we are queuing then, queue it to be serviced, and disable its irq */
1224/* mask otherwise process the board directly. */
1225/* */
1226/* We could queue by IRQ but that just complicates things on both ends */
1227/* with very little gain in performance (how many instructions does */
1228/* it take to iterate on the immediate queue). */
1229/* */
1230/* */
1231/******************************************************************************/
Jeff Garzikf3518e42007-10-19 15:24:59 -04001232static void
1233ip2_irq_work(i2eBordStrPtr pB)
1234{
1235#ifdef USE_IQI
1236 if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
1237// Disable his interrupt (will be enabled when serviced)
1238// This is mostly to protect from reentrancy.
1239 iiDisableMailIrq(pB);
1240
1241// Park the board on the immediate queue for processing.
1242 schedule_work(&pB->tqueue_interrupt);
1243
1244// Make sure the immediate queue is flagged to fire.
1245 }
1246#else
1247
1248// We are using immediate servicing here. This sucks and can
1249// cause all sorts of havoc with ppp and others. The failsafe
1250// check on iiSendPendingMail could also throw a hairball.
1251
1252 i2ServiceBoard( pB );
1253
1254#endif /* USE_IQI */
1255}
1256
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001257static void
1258ip2_polled_interrupt(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259{
1260 int i;
1261 i2eBordStrPtr pB;
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001262 const int irq = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
1264 ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
1265
1266 /* Service just the boards on the list using this irq */
1267 for( i = 0; i < i2nBoards; ++i ) {
1268 pB = i2BoardPtrTable[i];
1269
1270// Only process those boards which match our IRQ.
1271// IRQ = 0 for polled boards, we won't poll "IRQ" boards
1272
1273 if ( pB && (pB->i2eUsingIrq == irq) ) {
Jeff Garzikf3518e42007-10-19 15:24:59 -04001274 ip2_irq_work(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 }
1276 }
1277
1278 ++irq_counter;
1279
1280 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001281}
1282
1283static irqreturn_t
1284ip2_interrupt(int irq, void *dev_id)
1285{
1286 i2eBordStrPtr pB = dev_id;
1287
1288 ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, pB->i2eUsingIrq );
1289
1290 ip2_irq_work(pB);
1291
1292 ++irq_counter;
1293
1294 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1295 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296}
1297
1298/******************************************************************************/
1299/* Function: ip2_poll(unsigned long arg) */
1300/* Parameters: ? */
1301/* Returns: Nothing */
1302/* */
1303/* Description: */
1304/* This function calls the library routine i2ServiceBoard for each board in */
1305/* the board table. This is used instead of the interrupt routine when polled */
1306/* mode is specified. */
1307/******************************************************************************/
1308static void
1309ip2_poll(unsigned long arg)
1310{
1311 ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
1312
1313 TimerOn = 0; // it's the truth but not checked in service
1314
1315 // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
1316 // It will NOT poll boards handled by hard interrupts.
Joe Perches8dfba4d2008-02-03 17:11:42 +02001317 // The issue of queued BH interrupts is handled in ip2_interrupt().
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001318 ip2_polled_interrupt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320 PollTimer.expires = POLL_TIMEOUT;
1321 add_timer( &PollTimer );
1322 TimerOn = 1;
1323
1324 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1325}
1326
David Howellsc4028952006-11-22 14:57:56 +00001327static void do_input(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328{
David Howellsc4028952006-11-22 14:57:56 +00001329 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 unsigned long flags;
1331
1332 ip2trace(CHANN, ITRC_INPUT, 21, 0 );
1333
1334 // Data input
1335 if ( pCh->pTTY != NULL ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001336 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001338 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 i2Input( pCh );
1340 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001341 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 } else {
1343 ip2trace(CHANN, ITRC_INPUT, 22, 0 );
1344
1345 i2InputFlush( pCh );
1346 }
1347}
1348
1349// code duplicated from n_tty (ldisc)
1350static inline void isig(int sig, struct tty_struct *tty, int flush)
1351{
Alan Coxa352def2008-07-16 21:53:12 +01001352 /* FIXME: This is completely bogus */
Eric W. Biedermanab521dc2007-02-12 00:53:00 -08001353 if (tty->pgrp)
1354 kill_pgrp(tty->pgrp, sig, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 if (flush || !L_NOFLSH(tty)) {
Alan Coxa352def2008-07-16 21:53:12 +01001356 if ( tty->ldisc.ops->flush_buffer )
1357 tty->ldisc.ops->flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 i2InputFlush( tty->driver_data );
1359 }
1360}
1361
David Howellsc4028952006-11-22 14:57:56 +00001362static void do_status(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363{
David Howellsc4028952006-11-22 14:57:56 +00001364 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 int status;
1366
1367 status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
1368
1369 ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
1370
1371 if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
1372 if ( (status & I2_BRK) ) {
1373 // code duplicated from n_tty (ldisc)
1374 if (I_IGNBRK(pCh->pTTY))
1375 goto skip_this;
1376 if (I_BRKINT(pCh->pTTY)) {
1377 isig(SIGINT, pCh->pTTY, 1);
1378 goto skip_this;
1379 }
1380 wake_up_interruptible(&pCh->pTTY->read_wait);
1381 }
1382#ifdef NEVER_HAPPENS_AS_SETUP_XXX
1383 // and can't work because we don't know the_char
1384 // as the_char is reported on a separate path
1385 // The intelligent board does this stuff as setup
1386 {
1387 char brkf = TTY_NORMAL;
1388 unsigned char brkc = '\0';
1389 unsigned char tmp;
1390 if ( (status & I2_BRK) ) {
1391 brkf = TTY_BREAK;
1392 brkc = '\0';
1393 }
1394 else if (status & I2_PAR) {
1395 brkf = TTY_PARITY;
1396 brkc = the_char;
1397 } else if (status & I2_FRA) {
1398 brkf = TTY_FRAME;
1399 brkc = the_char;
1400 } else if (status & I2_OVR) {
1401 brkf = TTY_OVERRUN;
1402 brkc = the_char;
1403 }
1404 tmp = pCh->pTTY->real_raw;
1405 pCh->pTTY->real_raw = 0;
Alan Coxa352def2008-07-16 21:53:12 +01001406 pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 pCh->pTTY->real_raw = tmp;
1408 }
1409#endif /* NEVER_HAPPENS_AS_SETUP_XXX */
1410 }
1411skip_this:
1412
1413 if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
1414 wake_up_interruptible(&pCh->delta_msr_wait);
1415
1416 if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
1417 if ( status & I2_DCD ) {
1418 if ( pCh->wopen ) {
1419 wake_up_interruptible ( &pCh->open_wait );
1420 }
1421 } else {
1422 if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
1423 tty_hangup( pCh->pTTY );
1424 }
1425 }
1426 }
1427 }
1428
1429 ip2trace (CHANN, ITRC_STATUS, 26, 0 );
1430}
1431
1432/******************************************************************************/
1433/* Device Open/Close/Ioctl Entry Point Section */
1434/******************************************************************************/
1435
1436/******************************************************************************/
1437/* Function: open_sanity_check() */
1438/* Parameters: Pointer to tty structure */
1439/* Pointer to file structure */
1440/* Returns: Success or failure */
1441/* */
1442/* Description: */
1443/* Verifies the structure magic numbers and cross links. */
1444/******************************************************************************/
1445#ifdef IP2DEBUG_OPEN
1446static void
1447open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
1448{
1449 if ( pBrd->i2eValid != I2E_MAGIC ) {
1450 printk(KERN_ERR "IP2: invalid board structure\n" );
1451 } else if ( pBrd != pCh->pMyBord ) {
1452 printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
1453 pCh->pMyBord );
1454 } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
1455 printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
1456 } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
1457 } else {
1458 printk(KERN_INFO "IP2: all pointers check out!\n" );
1459 }
1460}
1461#endif
1462
1463
1464/******************************************************************************/
1465/* Function: ip2_open() */
1466/* Parameters: Pointer to tty structure */
1467/* Pointer to file structure */
1468/* Returns: Success or failure */
1469/* */
1470/* Description: (MANDATORY) */
1471/* A successful device open has to run a gauntlet of checks before it */
1472/* completes. After some sanity checking and pointer setup, the function */
1473/* blocks until all conditions are satisfied. It then initialises the port to */
1474/* the default characteristics and returns. */
1475/******************************************************************************/
1476static int
1477ip2_open( PTTY tty, struct file *pFile )
1478{
1479 wait_queue_t wait;
1480 int rc = 0;
1481 int do_clocal = 0;
1482 i2ChanStrPtr pCh = DevTable[tty->index];
1483
1484 ip2trace (tty->index, ITRC_OPEN, ITRC_ENTER, 0 );
1485
1486 if ( pCh == NULL ) {
1487 return -ENODEV;
1488 }
1489 /* Setup pointer links in device and tty structures */
1490 pCh->pTTY = tty;
1491 tty->driver_data = pCh;
1492
1493#ifdef IP2DEBUG_OPEN
1494 printk(KERN_DEBUG \
1495 "IP2:open(tty=%p,pFile=%p):dev=%s,ch=%d,idx=%d\n",
1496 tty, pFile, tty->name, pCh->infl.hd.i2sChannel, pCh->port_index);
1497 open_sanity_check ( pCh, pCh->pMyBord );
1498#endif
1499
1500 i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP);
1501 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1502 serviceOutgoingFifo( pCh->pMyBord );
1503
1504 /* Block here until the port is ready (per serial and istallion) */
1505 /*
1506 * 1. If the port is in the middle of closing wait for the completion
1507 * and then return the appropriate error.
1508 */
1509 init_waitqueue_entry(&wait, current);
1510 add_wait_queue(&pCh->close_wait, &wait);
1511 set_current_state( TASK_INTERRUPTIBLE );
1512
1513 if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
1514 if ( pCh->flags & ASYNC_CLOSING ) {
1515 schedule();
1516 }
1517 if ( tty_hung_up_p(pFile) ) {
1518 set_current_state( TASK_RUNNING );
1519 remove_wait_queue(&pCh->close_wait, &wait);
1520 return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
1521 }
1522 }
1523 set_current_state( TASK_RUNNING );
1524 remove_wait_queue(&pCh->close_wait, &wait);
1525
1526 /*
1527 * 3. Handle a non-blocking open of a normal port.
1528 */
1529 if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
1530 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1531 goto noblock;
1532 }
1533 /*
1534 * 4. Now loop waiting for the port to be free and carrier present
1535 * (if required).
1536 */
1537 if ( tty->termios->c_cflag & CLOCAL )
1538 do_clocal = 1;
1539
1540#ifdef IP2DEBUG_OPEN
1541 printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
1542#endif
1543
1544 ++pCh->wopen;
1545
1546 init_waitqueue_entry(&wait, current);
1547 add_wait_queue(&pCh->open_wait, &wait);
1548
1549 for(;;) {
1550 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1551 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1552 set_current_state( TASK_INTERRUPTIBLE );
1553 serviceOutgoingFifo( pCh->pMyBord );
1554 if ( tty_hung_up_p(pFile) ) {
1555 set_current_state( TASK_RUNNING );
1556 remove_wait_queue(&pCh->open_wait, &wait);
1557 return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
1558 }
1559 if (!(pCh->flags & ASYNC_CLOSING) &&
1560 (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
1561 rc = 0;
1562 break;
1563 }
1564
1565#ifdef IP2DEBUG_OPEN
1566 printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
1567 (pCh->flags & ASYNC_CLOSING)?"True":"False");
1568 printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
1569#endif
1570 ip2trace (CHANN, ITRC_OPEN, 3, 2, 0,
1571 (pCh->flags & ASYNC_CLOSING) );
1572 /* check for signal */
1573 if (signal_pending(current)) {
1574 rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
1575 break;
1576 }
1577 schedule();
1578 }
1579 set_current_state( TASK_RUNNING );
1580 remove_wait_queue(&pCh->open_wait, &wait);
1581
1582 --pCh->wopen; //why count?
1583
1584 ip2trace (CHANN, ITRC_OPEN, 4, 0 );
1585
1586 if (rc != 0 ) {
1587 return rc;
1588 }
1589 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1590
1591noblock:
1592
1593 /* first open - Assign termios structure to port */
1594 if ( tty->count == 1 ) {
1595 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1596 /* Now we must send the termios settings to the loadware */
1597 set_params( pCh, NULL );
1598 }
1599
1600 /*
1601 * Now set any i2lib options. These may go away if the i2lib code ends
1602 * up rolled into the mainline.
1603 */
1604 pCh->channelOptions |= CO_NBLOCK_WRITE;
1605
1606#ifdef IP2DEBUG_OPEN
1607 printk (KERN_DEBUG "IP2: open completed\n" );
1608#endif
1609 serviceOutgoingFifo( pCh->pMyBord );
1610
1611 ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
1612
1613 return 0;
1614}
1615
1616/******************************************************************************/
1617/* Function: ip2_close() */
1618/* Parameters: Pointer to tty structure */
1619/* Pointer to file structure */
1620/* Returns: Nothing */
1621/* */
1622/* Description: */
1623/* */
1624/* */
1625/******************************************************************************/
1626static void
1627ip2_close( PTTY tty, struct file *pFile )
1628{
1629 i2ChanStrPtr pCh = tty->driver_data;
1630
1631 if ( !pCh ) {
1632 return;
1633 }
1634
1635 ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
1636
1637#ifdef IP2DEBUG_OPEN
1638 printk(KERN_DEBUG "IP2:close %s:\n",tty->name);
1639#endif
1640
1641 if ( tty_hung_up_p ( pFile ) ) {
1642
1643 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
1644
1645 return;
1646 }
1647 if ( tty->count > 1 ) { /* not the last close */
1648
1649 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
1650
1651 return;
1652 }
1653 pCh->flags |= ASYNC_CLOSING; // last close actually
1654
1655 tty->closing = 1;
1656
1657 if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
1658 /*
1659 * Before we drop DTR, make sure the transmitter has completely drained.
1660 * This uses an timeout, after which the close
1661 * completes.
1662 */
1663 ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
1664 }
1665 /*
1666 * At this point we stop accepting input. Here we flush the channel
1667 * input buffer which will allow the board to send up more data. Any
1668 * additional input is tossed at interrupt/poll time.
1669 */
1670 i2InputFlush( pCh );
1671
1672 /* disable DSS reporting */
1673 i2QueueCommands(PTYPE_INLINE, pCh, 100, 4,
1674 CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1675 if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
1676 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
1677 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1678 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1679 }
1680
1681 serviceOutgoingFifo ( pCh->pMyBord );
1682
Alan Coxf34d7a52008-04-30 00:54:13 -07001683 tty_ldisc_flush(tty);
Alan Coxa6fc8192008-04-30 00:54:18 -07001684 tty_driver_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 tty->closing = 0;
1686
1687 pCh->pTTY = NULL;
1688
1689 if (pCh->wopen) {
1690 if (pCh->ClosingDelay) {
1691 msleep_interruptible(jiffies_to_msecs(pCh->ClosingDelay));
1692 }
1693 wake_up_interruptible(&pCh->open_wait);
1694 }
1695
1696 pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1697 wake_up_interruptible(&pCh->close_wait);
1698
1699#ifdef IP2DEBUG_OPEN
1700 DBG_CNT("ip2_close: after wakeups--");
1701#endif
1702
1703
1704 ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
1705
1706 return;
1707}
1708
1709/******************************************************************************/
1710/* Function: ip2_hangup() */
1711/* Parameters: Pointer to tty structure */
1712/* Returns: Nothing */
1713/* */
1714/* Description: */
1715/* */
1716/* */
1717/******************************************************************************/
1718static void
1719ip2_hangup ( PTTY tty )
1720{
1721 i2ChanStrPtr pCh = tty->driver_data;
1722
1723 if( !pCh ) {
1724 return;
1725 }
1726
1727 ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
1728
1729 ip2_flush_buffer(tty);
1730
1731 /* disable DSS reporting */
1732
1733 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
1734 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1735 if ( (tty->termios->c_cflag & HUPCL) ) {
1736 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
1737 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1738 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1739 }
1740 i2QueueCommands(PTYPE_INLINE, pCh, 1, 3,
1741 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1742 serviceOutgoingFifo ( pCh->pMyBord );
1743
1744 wake_up_interruptible ( &pCh->delta_msr_wait );
1745
1746 pCh->flags &= ~ASYNC_NORMAL_ACTIVE;
1747 pCh->pTTY = NULL;
1748 wake_up_interruptible ( &pCh->open_wait );
1749
1750 ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
1751}
1752
1753/******************************************************************************/
1754/******************************************************************************/
1755/* Device Output Section */
1756/******************************************************************************/
1757/******************************************************************************/
1758
1759/******************************************************************************/
1760/* Function: ip2_write() */
1761/* Parameters: Pointer to tty structure */
1762/* Flag denoting data is in user (1) or kernel (0) space */
1763/* Pointer to data */
1764/* Number of bytes to write */
1765/* Returns: Number of bytes actually written */
1766/* */
1767/* Description: (MANDATORY) */
1768/* */
1769/* */
1770/******************************************************************************/
1771static int
Alan Coxd9e39532006-01-09 20:54:20 -08001772ip2_write( PTTY tty, const unsigned char *pData, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773{
1774 i2ChanStrPtr pCh = tty->driver_data;
1775 int bytesSent = 0;
1776 unsigned long flags;
1777
1778 ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
1779
1780 /* Flush out any buffered data left over from ip2_putchar() calls. */
1781 ip2_flush_chars( tty );
1782
1783 /* This is the actual move bit. Make sure it does what we need!!!!! */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001784 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Al Virof061c582006-10-11 17:45:47 +01001785 bytesSent = i2Output( pCh, pData, count);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001786 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
1788 ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
1789
1790 return bytesSent > 0 ? bytesSent : 0;
1791}
1792
1793/******************************************************************************/
1794/* Function: ip2_putchar() */
1795/* Parameters: Pointer to tty structure */
1796/* Character to write */
1797/* Returns: Nothing */
1798/* */
1799/* Description: */
1800/* */
1801/* */
1802/******************************************************************************/
Alan Coxf34d7a52008-04-30 00:54:13 -07001803static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804ip2_putchar( PTTY tty, unsigned char ch )
1805{
1806 i2ChanStrPtr pCh = tty->driver_data;
1807 unsigned long flags;
1808
1809// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
1810
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001811 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
1813 if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001814 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 ip2_flush_chars( tty );
1816 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001817 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Alan Coxf34d7a52008-04-30 00:54:13 -07001818 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
1820// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
1821}
1822
1823/******************************************************************************/
1824/* Function: ip2_flush_chars() */
1825/* Parameters: Pointer to tty structure */
1826/* Returns: Nothing */
1827/* */
1828/* Description: */
1829/* */
1830/******************************************************************************/
1831static void
1832ip2_flush_chars( PTTY tty )
1833{
1834 int strip;
1835 i2ChanStrPtr pCh = tty->driver_data;
1836 unsigned long flags;
1837
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001838 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 if ( pCh->Pbuf_stuff ) {
1840
1841// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
1842
1843 //
1844 // We may need to restart i2Output if it does not fullfill this request
1845 //
Al Virof061c582006-10-11 17:45:47 +01001846 strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 if ( strip != pCh->Pbuf_stuff ) {
1848 memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
1849 }
1850 pCh->Pbuf_stuff -= strip;
1851 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001852 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853}
1854
1855/******************************************************************************/
1856/* Function: ip2_write_room() */
1857/* Parameters: Pointer to tty structure */
1858/* Returns: Number of bytes that the driver can accept */
1859/* */
1860/* Description: */
1861/* */
1862/******************************************************************************/
1863static int
1864ip2_write_room ( PTTY tty )
1865{
1866 int bytesFree;
1867 i2ChanStrPtr pCh = tty->driver_data;
1868 unsigned long flags;
1869
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001870 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001872 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
1874 ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
1875
1876 return ((bytesFree > 0) ? bytesFree : 0);
1877}
1878
1879/******************************************************************************/
1880/* Function: ip2_chars_in_buf() */
1881/* Parameters: Pointer to tty structure */
1882/* Returns: Number of bytes queued for transmission */
1883/* */
1884/* Description: */
1885/* */
1886/* */
1887/******************************************************************************/
1888static int
1889ip2_chars_in_buf ( PTTY tty )
1890{
1891 i2ChanStrPtr pCh = tty->driver_data;
1892 int rc;
1893 unsigned long flags;
1894
1895 ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
1896
1897#ifdef IP2DEBUG_WRITE
1898 printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
1899 pCh->Obuf_char_count + pCh->Pbuf_stuff,
1900 pCh->Obuf_char_count, pCh->Pbuf_stuff );
1901#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001902 read_lock_irqsave(&pCh->Obuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 rc = pCh->Obuf_char_count;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001904 read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
1905 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 rc += pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001907 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 return rc;
1909}
1910
1911/******************************************************************************/
1912/* Function: ip2_flush_buffer() */
1913/* Parameters: Pointer to tty structure */
1914/* Returns: Nothing */
1915/* */
1916/* Description: */
1917/* */
1918/* */
1919/******************************************************************************/
1920static void
1921ip2_flush_buffer( PTTY tty )
1922{
1923 i2ChanStrPtr pCh = tty->driver_data;
1924 unsigned long flags;
1925
1926 ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
1927
1928#ifdef IP2DEBUG_WRITE
1929 printk (KERN_DEBUG "IP2: flush buffer\n" );
1930#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001931 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 pCh->Pbuf_stuff = 0;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001933 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 i2FlushOutput( pCh );
1935 ip2_owake(tty);
1936
1937 ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
1938
1939}
1940
1941/******************************************************************************/
1942/* Function: ip2_wait_until_sent() */
1943/* Parameters: Pointer to tty structure */
1944/* Timeout for wait. */
1945/* Returns: Nothing */
1946/* */
1947/* Description: */
1948/* This function is used in place of the normal tty_wait_until_sent, which */
1949/* only waits for the driver buffers to be empty (or rather, those buffers */
1950/* reported by chars_in_buffer) which doesn't work for IP2 due to the */
1951/* indeterminate number of bytes buffered on the board. */
1952/******************************************************************************/
1953static void
1954ip2_wait_until_sent ( PTTY tty, int timeout )
1955{
1956 int i = jiffies;
1957 i2ChanStrPtr pCh = tty->driver_data;
1958
1959 tty_wait_until_sent(tty, timeout );
1960 if ( (i = timeout - (jiffies -i)) > 0)
1961 i2DrainOutput( pCh, i );
1962}
1963
1964/******************************************************************************/
1965/******************************************************************************/
1966/* Device Input Section */
1967/******************************************************************************/
1968/******************************************************************************/
1969
1970/******************************************************************************/
1971/* Function: ip2_throttle() */
1972/* Parameters: Pointer to tty structure */
1973/* Returns: Nothing */
1974/* */
1975/* Description: */
1976/* */
1977/* */
1978/******************************************************************************/
1979static void
1980ip2_throttle ( PTTY tty )
1981{
1982 i2ChanStrPtr pCh = tty->driver_data;
1983
1984#ifdef IP2DEBUG_READ
1985 printk (KERN_DEBUG "IP2: throttle\n" );
1986#endif
1987 /*
1988 * Signal the poll/interrupt handlers not to forward incoming data to
1989 * the line discipline. This will cause the buffers to fill up in the
1990 * library and thus cause the library routines to send the flow control
1991 * stuff.
1992 */
1993 pCh->throttled = 1;
1994}
1995
1996/******************************************************************************/
1997/* Function: ip2_unthrottle() */
1998/* Parameters: Pointer to tty structure */
1999/* Returns: Nothing */
2000/* */
2001/* Description: */
2002/* */
2003/* */
2004/******************************************************************************/
2005static void
2006ip2_unthrottle ( PTTY tty )
2007{
2008 i2ChanStrPtr pCh = tty->driver_data;
2009 unsigned long flags;
2010
2011#ifdef IP2DEBUG_READ
2012 printk (KERN_DEBUG "IP2: unthrottle\n" );
2013#endif
2014
2015 /* Pass incoming data up to the line discipline again. */
2016 pCh->throttled = 0;
2017 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
2018 serviceOutgoingFifo( pCh->pMyBord );
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002019 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002021 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022#ifdef IP2DEBUG_READ
2023 printk (KERN_DEBUG "i2Input called from unthrottle\n" );
2024#endif
2025 i2Input( pCh );
2026 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002027 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028}
2029
2030static void
2031ip2_start ( PTTY tty )
2032{
2033 i2ChanStrPtr pCh = DevTable[tty->index];
2034
2035 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
2036 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
2037 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
2038#ifdef IP2DEBUG_WRITE
2039 printk (KERN_DEBUG "IP2: start tx\n" );
2040#endif
2041}
2042
2043static void
2044ip2_stop ( PTTY tty )
2045{
2046 i2ChanStrPtr pCh = DevTable[tty->index];
2047
2048 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
2049#ifdef IP2DEBUG_WRITE
2050 printk (KERN_DEBUG "IP2: stop tx\n" );
2051#endif
2052}
2053
2054/******************************************************************************/
2055/* Device Ioctl Section */
2056/******************************************************************************/
2057
2058static int ip2_tiocmget(struct tty_struct *tty, struct file *file)
2059{
2060 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002061#ifdef ENABLE_DSSNOW
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 wait_queue_t wait;
Alan Coxd9e39532006-01-09 20:54:20 -08002063#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064
2065 if (pCh == NULL)
2066 return -ENODEV;
2067
2068/*
2069 FIXME - the following code is causing a NULL pointer dereference in
2070 2.3.51 in an interrupt handler. It's suppose to prompt the board
2071 to return the DSS signal status immediately. Why doesn't it do
2072 the same thing in 2.2.14?
2073*/
2074
2075/* This thing is still busted in the 1.2.12 driver on 2.4.x
2076 and even hoses the serial console so the oops can be trapped.
2077 /\/\|=mhw=|\/\/ */
2078
2079#ifdef ENABLE_DSSNOW
2080 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
2081
2082 init_waitqueue_entry(&wait, current);
2083 add_wait_queue(&pCh->dss_now_wait, &wait);
2084 set_current_state( TASK_INTERRUPTIBLE );
2085
2086 serviceOutgoingFifo( pCh->pMyBord );
2087
2088 schedule();
2089
2090 set_current_state( TASK_RUNNING );
2091 remove_wait_queue(&pCh->dss_now_wait, &wait);
2092
2093 if (signal_pending(current)) {
2094 return -EINTR;
2095 }
2096#endif
2097 return ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
2098 | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
2099 | ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0)
2100 | ((pCh->dataSetIn & I2_RI) ? TIOCM_RNG : 0)
2101 | ((pCh->dataSetIn & I2_DSR) ? TIOCM_DSR : 0)
2102 | ((pCh->dataSetIn & I2_CTS) ? TIOCM_CTS : 0);
2103}
2104
2105static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
2106 unsigned int set, unsigned int clear)
2107{
2108 i2ChanStrPtr pCh = DevTable[tty->index];
2109
2110 if (pCh == NULL)
2111 return -ENODEV;
2112
2113 if (set & TIOCM_RTS) {
2114 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2115 pCh->dataSetOut |= I2_RTS;
2116 }
2117 if (set & TIOCM_DTR) {
2118 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2119 pCh->dataSetOut |= I2_DTR;
2120 }
2121
2122 if (clear & TIOCM_RTS) {
2123 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2124 pCh->dataSetOut &= ~I2_RTS;
2125 }
2126 if (clear & TIOCM_DTR) {
2127 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2128 pCh->dataSetOut &= ~I2_DTR;
2129 }
2130 serviceOutgoingFifo( pCh->pMyBord );
2131 return 0;
2132}
2133
2134/******************************************************************************/
2135/* Function: ip2_ioctl() */
2136/* Parameters: Pointer to tty structure */
2137/* Pointer to file structure */
2138/* Command */
2139/* Argument */
2140/* Returns: Success or failure */
2141/* */
2142/* Description: */
2143/* */
2144/* */
2145/******************************************************************************/
2146static int
2147ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
2148{
2149 wait_queue_t wait;
2150 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002151 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 struct async_icount cprev, cnow; /* kernel counter temps */
2153 struct serial_icounter_struct __user *p_cuser;
2154 int rc = 0;
2155 unsigned long flags;
2156 void __user *argp = (void __user *)arg;
2157
Alan Coxd9e39532006-01-09 20:54:20 -08002158 if ( pCh == NULL )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 return -ENODEV;
Alan Coxd9e39532006-01-09 20:54:20 -08002160
2161 pB = pCh->pMyBord;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
2163 ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
2164
2165#ifdef IP2DEBUG_IOCTL
2166 printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
2167#endif
2168
2169 switch(cmd) {
2170 case TIOCGSERIAL:
2171
2172 ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
2173
2174 rc = get_serial_info(pCh, argp);
2175 if (rc)
2176 return rc;
2177 break;
2178
2179 case TIOCSSERIAL:
2180
2181 ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
2182
2183 rc = set_serial_info(pCh, argp);
2184 if (rc)
2185 return rc;
2186 break;
2187
2188 case TCXONC:
2189 rc = tty_check_change(tty);
2190 if (rc)
2191 return rc;
2192 switch (arg) {
2193 case TCOOFF:
2194 //return -ENOIOCTLCMD;
2195 break;
2196 case TCOON:
2197 //return -ENOIOCTLCMD;
2198 break;
2199 case TCIOFF:
2200 if (STOP_CHAR(tty) != __DISABLED_CHAR) {
2201 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2202 CMD_XMIT_NOW(STOP_CHAR(tty)));
2203 }
2204 break;
2205 case TCION:
2206 if (START_CHAR(tty) != __DISABLED_CHAR) {
2207 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2208 CMD_XMIT_NOW(START_CHAR(tty)));
2209 }
2210 break;
2211 default:
2212 return -EINVAL;
2213 }
2214 return 0;
2215
2216 case TCSBRK: /* SVID version: non-zero arg --> no break */
2217 rc = tty_check_change(tty);
2218
2219 ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
2220
2221 if (!rc) {
2222 ip2_wait_until_sent(tty,0);
2223 if (!arg) {
2224 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
2225 serviceOutgoingFifo( pCh->pMyBord );
2226 }
2227 }
2228 break;
2229
2230 case TCSBRKP: /* support for POSIX tcsendbreak() */
2231 rc = tty_check_change(tty);
2232
2233 ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
2234
2235 if (!rc) {
2236 ip2_wait_until_sent(tty,0);
2237 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2238 CMD_SEND_BRK(arg ? arg*100 : 250));
2239 serviceOutgoingFifo ( pCh->pMyBord );
2240 }
2241 break;
2242
2243 case TIOCGSOFTCAR:
2244
2245 ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
2246
2247 rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
2248 if (rc)
2249 return rc;
2250 break;
2251
2252 case TIOCSSOFTCAR:
2253
2254 ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
2255
2256 rc = get_user(arg,(unsigned long __user *) argp);
2257 if (rc)
2258 return rc;
2259 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
2260 | (arg ? CLOCAL : 0));
2261
2262 break;
2263
2264 /*
2265 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
2266 * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
2267 * for masking). Caller should use TIOCGICOUNT to see which one it was
2268 */
2269 case TIOCMIWAIT:
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002270 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 cprev = pCh->icount; /* note the counters on entry */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002272 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
2274 CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
2275 init_waitqueue_entry(&wait, current);
2276 add_wait_queue(&pCh->delta_msr_wait, &wait);
2277 set_current_state( TASK_INTERRUPTIBLE );
2278
2279 serviceOutgoingFifo( pCh->pMyBord );
2280 for(;;) {
2281 ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
2282
2283 schedule();
2284
2285 ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
2286
2287 /* see if a signal did it */
2288 if (signal_pending(current)) {
2289 rc = -ERESTARTSYS;
2290 break;
2291 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002292 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 cnow = pCh->icount; /* atomic copy */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002294 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2296 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2297 rc = -EIO; /* no change => rc */
2298 break;
2299 }
2300 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2301 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2302 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2303 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2304 rc = 0;
2305 break;
2306 }
2307 cprev = cnow;
2308 }
2309 set_current_state( TASK_RUNNING );
2310 remove_wait_queue(&pCh->delta_msr_wait, &wait);
2311
2312 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3,
2313 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
2314 if ( ! (pCh->flags & ASYNC_CHECK_CD)) {
2315 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP);
2316 }
2317 serviceOutgoingFifo( pCh->pMyBord );
2318 return rc;
2319 break;
2320
2321 /*
2322 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2323 * Return: write counters to the user passed counter struct
2324 * NB: both 1->0 and 0->1 transitions are counted except for RI where
2325 * only 0->1 is counted. The controller is quite capable of counting
2326 * both, but this done to preserve compatibility with the standard
2327 * serial driver.
2328 */
2329 case TIOCGICOUNT:
2330 ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
2331
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002332 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 cnow = pCh->icount;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002334 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 p_cuser = argp;
2336 rc = put_user(cnow.cts, &p_cuser->cts);
2337 rc = put_user(cnow.dsr, &p_cuser->dsr);
2338 rc = put_user(cnow.rng, &p_cuser->rng);
2339 rc = put_user(cnow.dcd, &p_cuser->dcd);
2340 rc = put_user(cnow.rx, &p_cuser->rx);
2341 rc = put_user(cnow.tx, &p_cuser->tx);
2342 rc = put_user(cnow.frame, &p_cuser->frame);
2343 rc = put_user(cnow.overrun, &p_cuser->overrun);
2344 rc = put_user(cnow.parity, &p_cuser->parity);
2345 rc = put_user(cnow.brk, &p_cuser->brk);
2346 rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
2347 break;
2348
2349 /*
2350 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
2351 * will be passed to the line discipline for it to handle.
2352 */
2353 case TIOCSERCONFIG:
2354 case TIOCSERGWILD:
2355 case TIOCSERGETLSR:
2356 case TIOCSERSWILD:
2357 case TIOCSERGSTRUCT:
2358 case TIOCSERGETMULTI:
2359 case TIOCSERSETMULTI:
2360
2361 default:
2362 ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
2363
2364 rc = -ENOIOCTLCMD;
2365 break;
2366 }
2367
2368 ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
2369
2370 return rc;
2371}
2372
2373/******************************************************************************/
2374/* Function: GetSerialInfo() */
2375/* Parameters: Pointer to channel structure */
2376/* Pointer to old termios structure */
2377/* Returns: Nothing */
2378/* */
2379/* Description: */
2380/* This is to support the setserial command, and requires processing of the */
2381/* standard Linux serial structure. */
2382/******************************************************************************/
2383static int
2384get_serial_info ( i2ChanStrPtr pCh, struct serial_struct __user *retinfo )
2385{
2386 struct serial_struct tmp;
2387
2388 memset ( &tmp, 0, sizeof(tmp) );
2389 tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
2390 if (BID_HAS_654(tmp.type)) {
2391 tmp.type = PORT_16650;
2392 } else {
2393 tmp.type = PORT_CIRRUS;
2394 }
2395 tmp.line = pCh->port_index;
2396 tmp.port = pCh->pMyBord->i2eBase;
2397 tmp.irq = ip2config.irq[pCh->port_index/64];
2398 tmp.flags = pCh->flags;
2399 tmp.baud_base = pCh->BaudBase;
2400 tmp.close_delay = pCh->ClosingDelay;
2401 tmp.closing_wait = pCh->ClosingWaitTime;
2402 tmp.custom_divisor = pCh->BaudDivisor;
2403 return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
2404}
2405
2406/******************************************************************************/
2407/* Function: SetSerialInfo() */
2408/* Parameters: Pointer to channel structure */
2409/* Pointer to old termios structure */
2410/* Returns: Nothing */
2411/* */
2412/* Description: */
2413/* This function provides support for setserial, which uses the TIOCSSERIAL */
2414/* ioctl. Not all setserial parameters are relevant. If the user attempts to */
2415/* change the IRQ, address or type of the port the ioctl fails. */
2416/******************************************************************************/
2417static int
2418set_serial_info( i2ChanStrPtr pCh, struct serial_struct __user *new_info )
2419{
2420 struct serial_struct ns;
2421 int old_flags, old_baud_divisor;
2422
2423 if (copy_from_user(&ns, new_info, sizeof (ns)))
2424 return -EFAULT;
2425
2426 /*
2427 * We don't allow setserial to change IRQ, board address, type or baud
2428 * base. Also line nunber as such is meaningless but we use it for our
2429 * array index so it is fixed also.
2430 */
2431 if ( (ns.irq != ip2config.irq[pCh->port_index])
2432 || ((int) ns.port != ((int) (pCh->pMyBord->i2eBase)))
2433 || (ns.baud_base != pCh->BaudBase)
2434 || (ns.line != pCh->port_index) ) {
2435 return -EINVAL;
2436 }
2437
2438 old_flags = pCh->flags;
2439 old_baud_divisor = pCh->BaudDivisor;
2440
2441 if ( !capable(CAP_SYS_ADMIN) ) {
2442 if ( ( ns.close_delay != pCh->ClosingDelay ) ||
2443 ( (ns.flags & ~ASYNC_USR_MASK) !=
2444 (pCh->flags & ~ASYNC_USR_MASK) ) ) {
2445 return -EPERM;
2446 }
2447
2448 pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
2449 (ns.flags & ASYNC_USR_MASK);
2450 pCh->BaudDivisor = ns.custom_divisor;
2451 } else {
2452 pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
2453 (ns.flags & ASYNC_FLAGS);
2454 pCh->BaudDivisor = ns.custom_divisor;
2455 pCh->ClosingDelay = ns.close_delay * HZ/100;
2456 pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
2457 }
2458
2459 if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
2460 || (old_baud_divisor != pCh->BaudDivisor) ) {
2461 // Invalidate speed and reset parameters
2462 set_params( pCh, NULL );
2463 }
2464
2465 return 0;
2466}
2467
2468/******************************************************************************/
2469/* Function: ip2_set_termios() */
2470/* Parameters: Pointer to tty structure */
2471/* Pointer to old termios structure */
2472/* Returns: Nothing */
2473/* */
2474/* Description: */
2475/* */
2476/* */
2477/******************************************************************************/
2478static void
Alan Cox606d0992006-12-08 02:38:45 -08002479ip2_set_termios( PTTY tty, struct ktermios *old_termios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480{
2481 i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
2482
2483#ifdef IP2DEBUG_IOCTL
2484 printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
2485#endif
2486
2487 set_params( pCh, old_termios );
2488}
2489
2490/******************************************************************************/
2491/* Function: ip2_set_line_discipline() */
2492/* Parameters: Pointer to tty structure */
2493/* Returns: Nothing */
2494/* */
2495/* Description: Does nothing */
2496/* */
2497/* */
2498/******************************************************************************/
2499static void
2500ip2_set_line_discipline ( PTTY tty )
2501{
2502#ifdef IP2DEBUG_IOCTL
2503 printk (KERN_DEBUG "IP2: set line discipline\n" );
2504#endif
2505
2506 ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
2507
2508}
2509
2510/******************************************************************************/
2511/* Function: SetLine Characteristics() */
2512/* Parameters: Pointer to channel structure */
2513/* Returns: Nothing */
2514/* */
2515/* Description: */
2516/* This routine is called to update the channel structure with the new line */
2517/* characteristics, and send the appropriate commands to the board when they */
2518/* change. */
2519/******************************************************************************/
2520static void
Alan Cox606d0992006-12-08 02:38:45 -08002521set_params( i2ChanStrPtr pCh, struct ktermios *o_tios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522{
2523 tcflag_t cflag, iflag, lflag;
2524 char stop_char, start_char;
Alan Cox606d0992006-12-08 02:38:45 -08002525 struct ktermios dummy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
2527 lflag = pCh->pTTY->termios->c_lflag;
2528 cflag = pCh->pTTY->termios->c_cflag;
2529 iflag = pCh->pTTY->termios->c_iflag;
2530
2531 if (o_tios == NULL) {
2532 dummy.c_lflag = ~lflag;
2533 dummy.c_cflag = ~cflag;
2534 dummy.c_iflag = ~iflag;
2535 o_tios = &dummy;
2536 }
2537
2538 {
2539 switch ( cflag & CBAUD ) {
2540 case B0:
2541 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
2542 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
2543 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
2544 pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
2545 goto service_it;
2546 break;
2547 case B38400:
2548 /*
2549 * This is the speed that is overloaded with all the other high
2550 * speeds, depending upon the flag settings.
2551 */
2552 if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
2553 pCh->speed = CBR_57600;
2554 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
2555 pCh->speed = CBR_115200;
2556 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
2557 pCh->speed = CBR_C1;
2558 } else {
2559 pCh->speed = CBR_38400;
2560 }
2561 break;
2562 case B50: pCh->speed = CBR_50; break;
2563 case B75: pCh->speed = CBR_75; break;
2564 case B110: pCh->speed = CBR_110; break;
2565 case B134: pCh->speed = CBR_134; break;
2566 case B150: pCh->speed = CBR_150; break;
2567 case B200: pCh->speed = CBR_200; break;
2568 case B300: pCh->speed = CBR_300; break;
2569 case B600: pCh->speed = CBR_600; break;
2570 case B1200: pCh->speed = CBR_1200; break;
2571 case B1800: pCh->speed = CBR_1800; break;
2572 case B2400: pCh->speed = CBR_2400; break;
2573 case B4800: pCh->speed = CBR_4800; break;
2574 case B9600: pCh->speed = CBR_9600; break;
2575 case B19200: pCh->speed = CBR_19200; break;
2576 case B57600: pCh->speed = CBR_57600; break;
2577 case B115200: pCh->speed = CBR_115200; break;
2578 case B153600: pCh->speed = CBR_153600; break;
2579 case B230400: pCh->speed = CBR_230400; break;
2580 case B307200: pCh->speed = CBR_307200; break;
2581 case B460800: pCh->speed = CBR_460800; break;
2582 case B921600: pCh->speed = CBR_921600; break;
2583 default: pCh->speed = CBR_9600; break;
2584 }
2585 if ( pCh->speed == CBR_C1 ) {
2586 // Process the custom speed parameters.
2587 int bps = pCh->BaudBase / pCh->BaudDivisor;
2588 if ( bps == 921600 ) {
2589 pCh->speed = CBR_921600;
2590 } else {
2591 bps = bps/10;
2592 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
2593 }
2594 }
2595 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
2596
2597 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
2598 pCh->dataSetOut |= (I2_DTR | I2_RTS);
2599 }
2600 if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag))
2601 {
2602 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2603 CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
2604 }
2605 if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag))
2606 {
2607 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2608 CMD_SETPAR(
2609 (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
2610 )
2611 );
2612 }
2613 /* byte size and parity */
2614 if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag))
2615 {
2616 int datasize;
2617 switch ( cflag & CSIZE ) {
2618 case CS5: datasize = CSZ_5; break;
2619 case CS6: datasize = CSZ_6; break;
2620 case CS7: datasize = CSZ_7; break;
2621 case CS8: datasize = CSZ_8; break;
2622 default: datasize = CSZ_5; break; /* as per serial.c */
2623 }
2624 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
2625 }
2626 /* Process CTS flow control flag setting */
2627 if ( (cflag & CRTSCTS) ) {
2628 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2629 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
2630 } else {
2631 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2632 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
2633 }
2634 //
2635 // Process XON/XOFF flow control flags settings
2636 //
2637 stop_char = STOP_CHAR(pCh->pTTY);
2638 start_char = START_CHAR(pCh->pTTY);
2639
2640 //////////// can't be \000
2641 if (stop_char == __DISABLED_CHAR )
2642 {
2643 stop_char = ~__DISABLED_CHAR;
2644 }
2645 if (start_char == __DISABLED_CHAR )
2646 {
2647 start_char = ~__DISABLED_CHAR;
2648 }
2649 /////////////////////////////////
2650
2651 if ( o_tios->c_cc[VSTART] != start_char )
2652 {
2653 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
2654 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
2655 }
2656 if ( o_tios->c_cc[VSTOP] != stop_char )
2657 {
2658 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
2659 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
2660 }
2661 if (stop_char == __DISABLED_CHAR )
2662 {
2663 stop_char = ~__DISABLED_CHAR; //TEST123
2664 goto no_xoff;
2665 }
2666 if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF)))
2667 {
2668 if ( iflag & IXOFF ) { // Enable XOFF output flow control
2669 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
2670 } else { // Disable XOFF output flow control
2671no_xoff:
2672 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
2673 }
2674 }
2675 if (start_char == __DISABLED_CHAR )
2676 {
2677 goto no_xon;
2678 }
2679 if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY)))
2680 {
2681 if ( iflag & IXON ) {
2682 if ( iflag & IXANY ) { // Enable XON/XANY output flow control
2683 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
2684 } else { // Enable XON output flow control
2685 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
2686 }
2687 } else { // Disable XON output flow control
2688no_xon:
2689 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
2690 }
2691 }
2692 if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) )
2693 {
2694 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2695 CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
2696 }
2697 if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) )
2698 {
2699 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2700 CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
2701 }
2702
2703 if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR))
2704 ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) )
2705 {
2706 char brkrpt = 0;
2707 char parrpt = 0;
2708
2709 if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
2710 /* Ignore breaks altogether */
2711 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
2712 } else {
2713 if ( iflag & BRKINT ) {
2714 if ( iflag & PARMRK ) {
2715 brkrpt = 0x0a; // exception an inline triple
2716 } else {
2717 brkrpt = 0x1a; // exception and NULL
2718 }
2719 brkrpt |= 0x04; // flush input
2720 } else {
2721 if ( iflag & PARMRK ) {
2722 brkrpt = 0x0b; //POSIX triple \0377 \0 \0
2723 } else {
2724 brkrpt = 0x01; // Null only
2725 }
2726 }
2727 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
2728 }
2729
2730 if (iflag & IGNPAR) {
2731 parrpt = 0x20;
2732 /* would be 2 for not cirrus bug */
2733 /* would be 0x20 cept for cirrus bug */
2734 } else {
2735 if ( iflag & PARMRK ) {
2736 /*
2737 * Replace error characters with 3-byte sequence (\0377,\0,char)
2738 */
2739 parrpt = 0x04 ;
2740 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
2741 } else {
2742 parrpt = 0x03;
2743 }
2744 }
2745 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
2746 }
2747 if (cflag & CLOCAL) {
2748 // Status reporting fails for DCD if this is off
2749 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
2750 pCh->flags &= ~ASYNC_CHECK_CD;
2751 } else {
2752 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
2753 pCh->flags |= ASYNC_CHECK_CD;
2754 }
2755
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756service_it:
2757 i2DrainOutput( pCh, 100 );
2758}
2759
2760/******************************************************************************/
2761/* IPL Device Section */
2762/******************************************************************************/
2763
2764/******************************************************************************/
2765/* Function: ip2_ipl_read() */
2766/* Parameters: Pointer to device inode */
2767/* Pointer to file structure */
2768/* Pointer to data */
2769/* Number of bytes to read */
2770/* Returns: Success or failure */
2771/* */
2772/* Description: Ugly */
2773/* */
2774/* */
2775/******************************************************************************/
2776
2777static
2778ssize_t
2779ip2_ipl_read(struct file *pFile, char __user *pData, size_t count, loff_t *off )
2780{
Josef Sipeka7113a92006-12-08 02:36:55 -08002781 unsigned int minor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 int rc = 0;
2783
2784#ifdef IP2DEBUG_IPL
2785 printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
2786#endif
2787
2788 switch( minor ) {
2789 case 0: // IPL device
2790 rc = -EINVAL;
2791 break;
2792 case 1: // Status dump
2793 rc = -EINVAL;
2794 break;
2795 case 2: // Ping device
2796 rc = -EINVAL;
2797 break;
2798 case 3: // Trace device
2799 rc = DumpTraceBuffer ( pData, count );
2800 break;
2801 case 4: // Trace device
2802 rc = DumpFifoBuffer ( pData, count );
2803 break;
2804 default:
2805 rc = -ENODEV;
2806 break;
2807 }
2808 return rc;
2809}
2810
2811static int
2812DumpFifoBuffer ( char __user *pData, int count )
2813{
2814#ifdef DEBUG_FIFO
2815 int rc;
2816 rc = copy_to_user(pData, DBGBuf, count);
2817
2818 printk(KERN_DEBUG "Last index %d\n", I );
2819
2820 return count;
2821#endif /* DEBUG_FIFO */
2822 return 0;
2823}
2824
2825static int
2826DumpTraceBuffer ( char __user *pData, int count )
2827{
2828#ifdef IP2DEBUG_TRACE
2829 int rc;
2830 int dumpcount;
2831 int chunk;
2832 int *pIndex = (int __user *)pData;
2833
2834 if ( count < (sizeof(int) * 6) ) {
2835 return -EIO;
2836 }
2837 rc = put_user(tracewrap, pIndex );
2838 rc = put_user(TRACEMAX, ++pIndex );
2839 rc = put_user(tracestrip, ++pIndex );
2840 rc = put_user(tracestuff, ++pIndex );
2841 pData += sizeof(int) * 6;
2842 count -= sizeof(int) * 6;
2843
2844 dumpcount = tracestuff - tracestrip;
2845 if ( dumpcount < 0 ) {
2846 dumpcount += TRACEMAX;
2847 }
2848 if ( dumpcount > count ) {
2849 dumpcount = count;
2850 }
2851 chunk = TRACEMAX - tracestrip;
2852 if ( dumpcount > chunk ) {
2853 rc = copy_to_user(pData, &tracebuf[tracestrip],
2854 chunk * sizeof(tracebuf[0]) );
2855 pData += chunk * sizeof(tracebuf[0]);
2856 tracestrip = 0;
2857 chunk = dumpcount - chunk;
2858 } else {
2859 chunk = dumpcount;
2860 }
2861 rc = copy_to_user(pData, &tracebuf[tracestrip],
2862 chunk * sizeof(tracebuf[0]) );
2863 tracestrip += chunk;
2864 tracewrap = 0;
2865
2866 rc = put_user(tracestrip, ++pIndex );
2867 rc = put_user(tracestuff, ++pIndex );
2868
2869 return dumpcount;
2870#else
2871 return 0;
2872#endif
2873}
2874
2875/******************************************************************************/
2876/* Function: ip2_ipl_write() */
2877/* Parameters: */
2878/* Pointer to file structure */
2879/* Pointer to data */
2880/* Number of bytes to write */
2881/* Returns: Success or failure */
2882/* */
2883/* Description: */
2884/* */
2885/* */
2886/******************************************************************************/
2887static ssize_t
2888ip2_ipl_write(struct file *pFile, const char __user *pData, size_t count, loff_t *off)
2889{
2890#ifdef IP2DEBUG_IPL
2891 printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
2892#endif
2893 return 0;
2894}
2895
2896/******************************************************************************/
2897/* Function: ip2_ipl_ioctl() */
2898/* Parameters: Pointer to device inode */
2899/* Pointer to file structure */
2900/* Command */
2901/* Argument */
2902/* Returns: Success or failure */
2903/* */
2904/* Description: */
2905/* */
2906/* */
2907/******************************************************************************/
Alan Cox47be36a2008-07-25 01:48:13 -07002908static long
2909ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910{
Alan Cox47be36a2008-07-25 01:48:13 -07002911 unsigned int iplminor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 int rc = 0;
2913 void __user *argp = (void __user *)arg;
2914 ULONG __user *pIndex = argp;
2915 i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
2916 i2ChanStrPtr pCh;
2917
2918#ifdef IP2DEBUG_IPL
2919 printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
2920#endif
2921
Alan Cox47be36a2008-07-25 01:48:13 -07002922 lock_kernel();
2923
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 switch ( iplminor ) {
2925 case 0: // IPL device
2926 rc = -EINVAL;
2927 break;
2928 case 1: // Status dump
2929 case 5:
2930 case 9:
2931 case 13:
2932 switch ( cmd ) {
2933 case 64: /* Driver - ip2stat */
2934 rc = put_user(ip2_tty_driver->refcount, pIndex++ );
2935 rc = put_user(irq_counter, pIndex++ );
2936 rc = put_user(bh_counter, pIndex++ );
2937 break;
2938
2939 case 65: /* Board - ip2stat */
2940 if ( pB ) {
2941 rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002942 rc = put_user(inb(pB->i2eStatus),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 (ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
2944 } else {
2945 rc = -ENODEV;
2946 }
2947 break;
2948
2949 default:
2950 if (cmd < IP2_MAX_PORTS) {
2951 pCh = DevTable[cmd];
2952 if ( pCh )
2953 {
2954 rc = copy_to_user(argp, pCh, sizeof(i2ChanStr));
2955 } else {
2956 rc = -ENODEV;
2957 }
2958 } else {
2959 rc = -EINVAL;
2960 }
2961 }
2962 break;
2963
2964 case 2: // Ping device
2965 rc = -EINVAL;
2966 break;
2967 case 3: // Trace device
Andrew Mortondef93912006-02-03 03:04:47 -08002968 /*
2969 * akpm: This used to write a whole bunch of function addresses
2970 * to userspace, which generated lots of put_user() warnings.
2971 * I killed it all. Just return "success" and don't do
2972 * anything.
2973 */
2974 if (cmd == 1)
2975 rc = 0;
2976 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 break;
2979
2980 default:
2981 rc = -ENODEV;
2982 break;
2983 }
Alan Cox47be36a2008-07-25 01:48:13 -07002984 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 return rc;
2986}
2987
2988/******************************************************************************/
2989/* Function: ip2_ipl_open() */
2990/* Parameters: Pointer to device inode */
2991/* Pointer to file structure */
2992/* Returns: Success or failure */
2993/* */
2994/* Description: */
2995/* */
2996/* */
2997/******************************************************************************/
2998static int
2999ip2_ipl_open( struct inode *pInode, struct file *pFile )
3000{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001
3002#ifdef IP2DEBUG_IPL
3003 printk (KERN_DEBUG "IP2IPL: open\n" );
3004#endif
Jonathan Corbetf2b98572008-05-18 15:32:43 -06003005 cycle_kernel_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 return 0;
3007}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
3009static int
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003010proc_ip2mem_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011{
3012 i2eBordStrPtr pB;
3013 i2ChanStrPtr pCh;
3014 PTTY tty;
3015 int i;
3016
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
3018#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
3019#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
3020
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003021 seq_printf(m,"\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022
3023 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3024 pB = i2BoardPtrTable[i];
3025 if ( pB ) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003026 seq_printf(m,"board %d:\n",i);
3027 seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
3029 }
3030 }
3031
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003032 seq_printf(m,"#: tty flags, port flags, cflags, iflags\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 for (i=0; i < IP2_MAX_PORTS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 pCh = DevTable[i];
3035 if (pCh) {
3036 tty = pCh->pTTY;
3037 if (tty && tty->count) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003038 seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 tty->termios->c_cflag,tty->termios->c_iflag);
3040
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003041 seq_printf(m,FMTLIN2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003043 seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 }
3045 }
3046 }
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003047 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048}
3049
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003050static int proc_ip2mem_open(struct inode *inode, struct file *file)
3051{
3052 return single_open(file, proc_ip2mem_show, NULL);
3053}
3054
3055static const struct file_operations ip2mem_proc_fops = {
3056 .owner = THIS_MODULE,
3057 .open = proc_ip2mem_open,
3058 .read = seq_read,
3059 .llseek = seq_lseek,
3060 .release = single_release,
3061};
3062
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063/*
3064 * This is the handler for /proc/tty/driver/ip2
3065 *
3066 * This stretch of code has been largely plagerized from at least three
3067 * different sources including ip2mkdev.c and a couple of other drivers.
3068 * The bugs are all mine. :-) =mhw=
3069 */
3070static int ip2_read_proc(char *page, char **start, off_t off,
3071 int count, int *eof, void *data)
3072{
3073 int i, j, box;
3074 int len = 0;
3075 int boxes = 0;
3076 int ports = 0;
3077 int tports = 0;
3078 off_t begin = 0;
3079 i2eBordStrPtr pB;
3080
3081 len += sprintf(page, "ip2info: 1.0 driver: %s\n", pcVersion );
3082 len += sprintf(page+len, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
3083 IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
3084 IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
3085
3086 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3087 /* This need to be reset for a board by board count... */
3088 boxes = 0;
3089 pB = i2BoardPtrTable[i];
3090 if( pB ) {
3091 switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED )
3092 {
3093 case POR_ID_FIIEX:
3094 len += sprintf( page+len, "Board %d: EX ports=", i );
3095 for( box = 0; box < ABS_MAX_BOXES; ++box )
3096 {
3097 ports = 0;
3098
3099 if( pB->i2eChannelMap[box] != 0 ) ++boxes;
3100 for( j = 0; j < ABS_BIGGEST_BOX; ++j )
3101 {
3102 if( pB->i2eChannelMap[box] & 1<< j ) {
3103 ++ports;
3104 }
3105 }
3106 len += sprintf( page+len, "%d,", ports );
3107 tports += ports;
3108 }
3109
3110 --len; /* Backup over that last comma */
3111
3112 len += sprintf( page+len, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8 );
3113 break;
3114
3115 case POR_ID_II_4:
3116 len += sprintf(page+len, "Board %d: ISA-4 ports=4 boxes=1", i );
3117 tports = ports = 4;
3118 break;
3119
3120 case POR_ID_II_8:
3121 len += sprintf(page+len, "Board %d: ISA-8-std ports=8 boxes=1", i );
3122 tports = ports = 8;
3123 break;
3124
3125 case POR_ID_II_8R:
3126 len += sprintf(page+len, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i );
3127 tports = ports = 8;
3128 break;
3129
3130 default:
3131 len += sprintf(page+len, "Board %d: unknown", i );
3132 /* Don't try and probe for minor numbers */
3133 tports = ports = 0;
3134 }
3135
3136 } else {
3137 /* Don't try and probe for minor numbers */
3138 len += sprintf(page+len, "Board %d: vacant", i );
3139 tports = ports = 0;
3140 }
3141
3142 if( tports ) {
3143 len += sprintf(page+len, " minors=" );
3144
3145 for ( box = 0; box < ABS_MAX_BOXES; ++box )
3146 {
3147 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
3148 {
3149 if ( pB->i2eChannelMap[box] & (1 << j) )
3150 {
3151 len += sprintf (page+len,"%d,",
3152 j + ABS_BIGGEST_BOX *
3153 (box+i*ABS_MAX_BOXES));
3154 }
3155 }
3156 }
3157
3158 page[ len - 1 ] = '\n'; /* Overwrite that last comma */
3159 } else {
3160 len += sprintf (page+len,"\n" );
3161 }
3162
3163 if (len+begin > off+count)
3164 break;
3165 if (len+begin < off) {
3166 begin += len;
3167 len = 0;
3168 }
3169 }
3170
3171 if (i >= IP2_MAX_BOARDS)
3172 *eof = 1;
3173 if (off >= len+begin)
3174 return 0;
3175
3176 *start = page + (off-begin);
3177 return ((count < begin+len-off) ? count : begin+len-off);
3178 }
3179
3180/******************************************************************************/
3181/* Function: ip2trace() */
3182/* Parameters: Value to add to trace buffer */
3183/* Returns: Nothing */
3184/* */
3185/* Description: */
3186/* */
3187/* */
3188/******************************************************************************/
3189#ifdef IP2DEBUG_TRACE
3190void
3191ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
3192{
3193 long flags;
3194 unsigned long *pCode = &codes;
3195 union ip2breadcrumb bc;
3196 i2ChanStrPtr pCh;
3197
3198
3199 tracebuf[tracestuff++] = jiffies;
3200 if ( tracestuff == TRACEMAX ) {
3201 tracestuff = 0;
3202 }
3203 if ( tracestuff == tracestrip ) {
3204 if ( ++tracestrip == TRACEMAX ) {
3205 tracestrip = 0;
3206 }
3207 ++tracewrap;
3208 }
3209
3210 bc.hdr.port = 0xff & pn;
3211 bc.hdr.cat = cat;
3212 bc.hdr.codes = (unsigned char)( codes & 0xff );
3213 bc.hdr.label = label;
3214 tracebuf[tracestuff++] = bc.value;
3215
3216 for (;;) {
3217 if ( tracestuff == TRACEMAX ) {
3218 tracestuff = 0;
3219 }
3220 if ( tracestuff == tracestrip ) {
3221 if ( ++tracestrip == TRACEMAX ) {
3222 tracestrip = 0;
3223 }
3224 ++tracewrap;
3225 }
3226
3227 if ( !codes-- )
3228 break;
3229
3230 tracebuf[tracestuff++] = *++pCode;
3231 }
3232}
3233#endif
3234
3235
3236MODULE_LICENSE("GPL");
Chuck Shorteb0e71c2006-07-10 04:43:59 -07003237
3238static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
3239 { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
3240 { }
3241};
3242
3243MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);