blob: 517271c762e6b620b1323da302c5cd837985c626 [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;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700142static const struct file_operations ip2_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144/********************/
145/* Type Definitions */
146/********************/
147
148/*************/
149/* Constants */
150/*************/
151
152/* String constants to identify ourselves */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100153static const char pcName[] = "Computone IntelliPort Plus multiport driver";
154static const char pcVersion[] = "1.2.14";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156/* String constants for port names */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100157static const char pcDriver_name[] = "ip2";
158static const char pcIpl[] = "ip2ipl";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
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
Jiri Slabycf176bc2008-10-13 10:34:36 +0100240static unsigned long irq_counter;
241static unsigned long bh_counter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
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 -0700252
253#ifdef IP2DEBUG_TRACE
254/* Trace (debug) buffer data */
255#define TRACEMAX 1000
256static unsigned long tracebuf[TRACEMAX];
257static int tracestuff;
258static int tracestrip;
259static int tracewrap;
260#endif
261
262/**********/
263/* Macros */
264/**********/
265
266#if defined(MODULE) && defined(IP2DEBUG_OPEN)
Alan Cox7d7b93c2008-10-13 10:42:09 +0100267#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
268 tty->name,(pCh->flags), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 tty->count,/*GET_USE_COUNT(module)*/0,s)
270#else
271#define DBG_CNT(s)
272#endif
273
274/********/
275/* Code */
276/********/
277
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100278#include "i2ellis.c" /* Extremely low-level interface services */
279#include "i2cmd.c" /* Standard loadware command definitions */
280#include "i2lib.c" /* High level interface services */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282/* Configuration area for modprobe */
283
284MODULE_AUTHOR("Doug McNash");
285MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
Jiri Slaby47babd42008-10-13 10:34:27 +0100286MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Jiri Slabycf176bc2008-10-13 10:34:36 +0100288static int poll_only;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290static int Eisa_irq;
291static int Eisa_slot;
292
293static int iindx;
294static char rirqs[IP2_MAX_BOARDS];
295static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
296
Jiri Slaby47babd42008-10-13 10:34:27 +0100297/* Note: Add compiled in defaults to these arrays, not to the structure
298 in ip2.h any longer. That structure WILL get overridden
299 by these values, or command line values, or insmod values!!! =mhw=
300*/
301static int io[IP2_MAX_BOARDS];
302static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
303
304MODULE_AUTHOR("Doug McNash");
305MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
306module_param_array(irq, int, NULL, 0);
307MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
308module_param_array(io, int, NULL, 0);
309MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
310module_param(poll_only, bool, 0);
311MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313/* for sysfs class support */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800314static struct class *ip2_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100316/* Some functions to keep track of what irqs we have */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100318static int __init is_valid_irq(int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
320 int *i = Valid_Irqs;
321
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100322 while (*i != 0 && *i != irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 i++;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100324
325 return *i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100328static void __init mark_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 rirqs[iindx++] = irq;
331}
332
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100333static int __exit clear_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
335 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100336 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 if (rirqs[i] == irq) {
338 rirqs[i] = 0;
339 return 1;
340 }
341 }
342 return 0;
343}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100345static int have_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100347 /* array init to zeros so 0 irq will not be requested as a side
348 * effect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100350 for (i = 0; i < IP2_MAX_BOARDS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if (rirqs[i] == irq)
352 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return 0;
354}
355
356/******************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357/* Function: cleanup_module() */
358/* Parameters: None */
359/* Returns: Nothing */
360/* */
361/* Description: */
362/* This is a required entry point for an installable module. It has to return */
363/* the device and the driver to a passive state. It should not be necessary */
364/* to reset the board fully, especially as the loadware is downloaded */
365/* externally rather than in the driver. We just want to disable the board */
366/* and clear the loadware to a reset state. To allow this there has to be a */
367/* way to detect whether the board has the loadware running at init time to */
368/* handle subsequent installations of the driver. All memory allocated by the */
369/* driver should be returned since it may be unloaded from memory. */
370/******************************************************************************/
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100371static void __exit ip2_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 int err;
374 int i;
375
Akinobu Mita9d020a2e2008-10-13 10:35:05 +0100376 del_timer_sync(&PollTimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 /* Reset the boards we have. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100379 for (i = 0; i < IP2_MAX_BOARDS; i++)
380 if (i2BoardPtrTable[i])
381 iiReset(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 /* The following is done at most once, if any boards were installed. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100384 for (i = 0; i < IP2_MAX_BOARDS; i++) {
385 if (i2BoardPtrTable[i]) {
386 iiResetDelay(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 /* free io addresses and Tibet */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100388 release_region(ip2config.addr[i], 8);
tonyj@suse.de07c015e2007-08-07 22:28:44 -0700389 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100390 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
391 4 * i + 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
393 /* Disable and remove interrupt handler. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100394 if (ip2config.irq[i] > 0 &&
395 have_requested_irq(ip2config.irq[i])) {
396 free_irq(ip2config.irq[i], (void *)&pcName);
397 clear_requested_irq(ip2config.irq[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 }
399 }
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800400 class_destroy(ip2_class);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100401 err = tty_unregister_driver(ip2_tty_driver);
402 if (err)
403 printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
404 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 put_tty_driver(ip2_tty_driver);
Akinobu Mita68fc4fa2007-07-19 01:47:50 -0700406 unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
Alexey Dobriyanc74c1202008-04-29 01:01:44 -0700407 remove_proc_entry("ip2mem", NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100409 /* free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 for (i = 0; i < IP2_MAX_BOARDS; i++) {
411 void *pB;
412#ifdef CONFIG_PCI
413 if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
414 pci_disable_device(ip2config.pci_dev[i]);
Alan Cox1aff0ec2006-09-30 23:27:59 -0700415 pci_dev_put(ip2config.pci_dev[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 ip2config.pci_dev[i] = NULL;
417 }
418#endif
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100419 pB = i2BoardPtrTable[i];
420 if (pB != NULL) {
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100421 kfree(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 i2BoardPtrTable[i] = NULL;
423 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100424 if (DevTableMem[i] != NULL) {
425 kfree(DevTableMem[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 DevTableMem[i] = NULL;
427 }
428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429}
Jon Schindler83e422b2008-04-30 00:53:53 -0700430module_exit(ip2_cleanup_module);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700432static const struct tty_operations ip2_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 .open = ip2_open,
434 .close = ip2_close,
435 .write = ip2_write,
436 .put_char = ip2_putchar,
437 .flush_chars = ip2_flush_chars,
438 .write_room = ip2_write_room,
439 .chars_in_buffer = ip2_chars_in_buf,
440 .flush_buffer = ip2_flush_buffer,
441 .ioctl = ip2_ioctl,
442 .throttle = ip2_throttle,
443 .unthrottle = ip2_unthrottle,
444 .set_termios = ip2_set_termios,
445 .set_ldisc = ip2_set_line_discipline,
446 .stop = ip2_stop,
447 .start = ip2_start,
448 .hangup = ip2_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 .tiocmget = ip2_tiocmget,
450 .tiocmset = ip2_tiocmset,
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700451 .proc_fops = &ip2_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452};
453
454/******************************************************************************/
455/* Function: ip2_loadmain() */
456/* Parameters: irq, io from command line of insmod et. al. */
457/* pointer to fip firmware and firmware size for boards */
458/* Returns: Success (0) */
459/* */
460/* Description: */
461/* This was the required entry point for all drivers (now in ip2.c) */
462/* It performs all */
463/* initialisation of the devices and driver structures, and registers itself */
464/* with the relevant kernel modules. */
465/******************************************************************************/
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700466/* IRQF_DISABLED - if set blocks all interrupts else only this line */
467/* IRQF_SHARED - for shared irq PCI or maybe EISA only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468/* SA_RANDOM - can be source for cert. random number generators */
469#define IP2_SA_FLAGS 0
470
David Woodhouse547d8bb2008-06-11 16:57:21 +0100471
472static const struct firmware *ip2_request_firmware(void)
473{
474 struct platform_device *pdev;
475 const struct firmware *fw;
476
477 pdev = platform_device_register_simple("ip2", 0, NULL, 0);
478 if (IS_ERR(pdev)) {
479 printk(KERN_ERR "Failed to register platform device for ip2\n");
480 return NULL;
481 }
482 if (request_firmware(&fw, "intelliport2.bin", &pdev->dev)) {
483 printk(KERN_ERR "Failed to load firmware 'intelliport2.bin'\n");
484 fw = NULL;
485 }
486 platform_device_unregister(pdev);
487 return fw;
488}
489
Jiri Slaby47babd42008-10-13 10:34:27 +0100490#ifndef MODULE
491/******************************************************************************
492 * ip2_setup:
493 * str: kernel command line string
494 *
495 * Can't autoprobe the boards so user must specify configuration on
496 * kernel command line. Sane people build it modular but the others
497 * come here.
498 *
499 * Alternating pairs of io,irq for up to 4 boards.
500 * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
501 *
502 * io=0 => No board
503 * io=1 => PCI
504 * io=2 => EISA
505 * else => ISA I/O address
506 *
507 * irq=0 or invalid for ISA will revert to polling mode
508 *
509 * Any value = -1, do not overwrite compiled in value.
510 *
511 ******************************************************************************/
512static int __init ip2_setup(char *str)
513{
514 int j, ints[10]; /* 4 boards, 2 parameters + 2 */
515 unsigned int i;
516
517 str = get_options(str, ARRAY_SIZE(ints), ints);
518
519 for (i = 0, j = 1; i < 4; i++) {
520 if (j > ints[0])
521 break;
522 if (ints[j] >= 0)
523 io[i] = ints[j];
524 j++;
525 if (j > ints[0])
526 break;
527 if (ints[j] >= 0)
528 irq[i] = ints[j];
529 j++;
530 }
531 return 1;
532}
533__setup("ip2=", ip2_setup);
534#endif /* !MODULE */
535
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100536static int __init ip2_loadmain(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
538 int i, j, box;
539 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 i2eBordStrPtr pB = NULL;
541 int rc = -1;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100542 struct pci_dev *pdev = NULL;
David Woodhouse547d8bb2008-06-11 16:57:21 +0100543 const struct firmware *fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Jiri Slaby47babd42008-10-13 10:34:27 +0100545 if (poll_only) {
546 /* Hard lock the interrupts to zero */
547 irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
548 }
549
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100550 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
552 /* process command line arguments to modprobe or
553 insmod i.e. iop & irqp */
554 /* irqp and iop should ALWAYS be specified now... But we check
555 them individually just to be sure, anyways... */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100556 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Jiri Slaby47babd42008-10-13 10:34:27 +0100557 ip2config.addr[i] = io[i];
558 if (irq[i] >= 0)
559 ip2config.irq[i] = irq[i];
560 else
561 ip2config.irq[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100562 /* This is a little bit of a hack. If poll_only=1 on command
563 line back in ip2.c OR all IRQs on all specified boards are
564 explicitly set to 0, then drop to poll only mode and override
565 PCI or EISA interrupts. This superceeds the old hack of
566 triggering if all interrupts were zero (like da default).
567 Still a hack but less prone to random acts of terrorism.
568
569 What we really should do, now that the IRQ default is set
570 to -1, is to use 0 as a hard coded, do not probe.
571
572 /\/\|=mhw=|\/\/
573 */
Jiri Slaby47babd42008-10-13 10:34:27 +0100574 poll_only |= irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 }
576 poll_only = !poll_only;
577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 /* Announce our presence */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100579 printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581 ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
582 if (!ip2_tty_driver)
583 return -ENOMEM;
584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 /* Initialise all the boards we can find (up to the maximum). */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100586 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
587 switch (ip2config.addr[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 case 0: /* skip this slot even if card is present */
589 break;
590 default: /* ISA */
591 /* ISA address must be specified */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100592 if (ip2config.addr[i] < 0x100 ||
593 ip2config.addr[i] > 0x3f8) {
594 printk(KERN_ERR "IP2: Bad ISA board %d "
595 "address %x\n", i,
596 ip2config.addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 ip2config.addr[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100598 break;
599 }
600 ip2config.type[i] = ISA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100602 /* Check for valid irq argument, set for polling if
603 * invalid */
604 if (ip2config.irq[i] &&
605 !is_valid_irq(ip2config.irq[i])) {
606 printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
607 ip2config.irq[i]);
608 /* 0 is polling and is valid in that sense */
609 ip2config.irq[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 }
611 break;
612 case PCI:
613#ifdef CONFIG_PCI
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100614 {
615 u32 addr;
616 int status;
Andrew Mortonad4a5bb2007-07-31 00:39:41 -0700617
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100618 pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
619 PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
620 if (pdev == NULL) {
621 ip2config.addr[i] = 0;
622 printk(KERN_ERR "IP2: PCI board %d not "
623 "found\n", i);
624 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100626
627 if (pci_enable_device(pdev)) {
628 dev_err(&pdev->dev, "can't enable device\n");
629 break;
630 }
631 ip2config.type[i] = PCI;
632 ip2config.pci_dev[i] = pci_dev_get(pdev);
633 status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
634 &addr);
635 if (addr & 1)
636 ip2config.addr[i] = (USHORT)(addr & 0xfffe);
637 else
638 dev_err(&pdev->dev, "I/O address error\n");
639
640 ip2config.irq[i] = pdev->irq;
641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642#else
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100643 printk(KERN_ERR "IP2: PCI card specified but PCI "
644 "support not enabled.\n");
645 printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
646 "defined!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647#endif /* CONFIG_PCI */
648 break;
649 case EISA:
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100650 ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
651 if (ip2config.addr[i] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 /* Eisa_irq set as side effect, boo */
653 ip2config.type[i] = EISA;
654 }
655 ip2config.irq[i] = Eisa_irq;
656 break;
657 } /* switch */
658 } /* for */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100659 pci_dev_put(pdev);
Alan Cox1aff0ec2006-09-30 23:27:59 -0700660
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100661 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
662 if (ip2config.addr[i]) {
Mariusz Kozlowski978550b82007-10-16 23:26:45 -0700663 pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
664 if (pB) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 i2BoardPtrTable[i] = pB;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100666 iiSetAddress(pB, ip2config.addr[i],
667 ii2DelayTimer);
668 iiReset(pB);
669 } else
670 printk(KERN_ERR "IP2: board memory allocation "
671 "error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 }
673 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100674 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
675 pB = i2BoardPtrTable[i];
676 if (pB != NULL) {
677 iiResetDelay(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 break;
679 }
680 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100681 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100682 /* We don't want to request the firmware unless we have at
683 least one board */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100684 if (i2BoardPtrTable[i] != NULL) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100685 if (!fw)
686 fw = ip2_request_firmware();
687 if (!fw)
688 break;
689 ip2_init_board(i, fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 }
691 }
David Woodhouse547d8bb2008-06-11 16:57:21 +0100692 if (fw)
693 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100695 ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
697 ip2_tty_driver->owner = THIS_MODULE;
698 ip2_tty_driver->name = "ttyF";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 ip2_tty_driver->driver_name = pcDriver_name;
700 ip2_tty_driver->major = IP2_TTY_MAJOR;
701 ip2_tty_driver->minor_start = 0;
702 ip2_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
703 ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL;
704 ip2_tty_driver->init_termios = tty_std_termios;
705 ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100706 ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW |
707 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 tty_set_operations(ip2_tty_driver, &ip2_ops);
709
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100710 ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100712 err = tty_register_driver(ip2_tty_driver);
713 if (err) {
714 printk(KERN_ERR "IP2: failed to register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 put_tty_driver(ip2_tty_driver);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100716 return err; /* leaking resources */
717 }
718
719 err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
720 if (err) {
721 printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
722 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 } else {
724 /* create the sysfs class */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800725 ip2_class = class_create(THIS_MODULE, "ip2");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (IS_ERR(ip2_class)) {
727 err = PTR_ERR(ip2_class);
728 goto out_chrdev;
729 }
730 }
731 /* Register the read_procmem thing */
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700732 if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 printk(KERN_ERR "IP2: failed to register read_procmem\n");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100734 return -EIO; /* leaking resources */
735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100737 ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
738 /* Register the interrupt handler or poll handler, depending upon the
739 * specified interrupt.
740 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100742 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
743 if (ip2config.addr[i] == 0)
744 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100746 pB = i2BoardPtrTable[i];
747 if (pB != NULL) {
Greg Kroah-Hartman03457cd2008-07-21 20:03:34 -0700748 device_create(ip2_class, NULL,
749 MKDEV(IP2_IPL_MAJOR, 4 * i),
750 NULL, "ipl%d", i);
751 device_create(ip2_class, NULL,
752 MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
753 NULL, "stat%d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100755 for (box = 0; box < ABS_MAX_BOXES; box++)
756 for (j = 0; j < ABS_BIGGEST_BOX; j++)
757 if (pB->i2eChannelMap[box] & (1 << j))
758 tty_register_device(
759 ip2_tty_driver,
760 j + ABS_BIGGEST_BOX *
761 (box+i*ABS_MAX_BOXES),
762 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100764
765 if (poll_only) {
766 /* Poll only forces driver to only use polling and
767 to ignore the probed PCI or EISA interrupts. */
768 ip2config.irq[i] = CIR_POLL;
769 }
770 if (ip2config.irq[i] == CIR_POLL) {
771retry:
Akinobu Mita9d020a2e2008-10-13 10:35:05 +0100772 if (!timer_pending(&PollTimer)) {
773 mod_timer(&PollTimer, POLL_TIMEOUT);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100774 printk(KERN_INFO "IP2: polling\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100776 } else {
777 if (have_requested_irq(ip2config.irq[i]))
778 continue;
779 rc = request_irq(ip2config.irq[i], ip2_interrupt,
780 IP2_SA_FLAGS |
781 (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
782 pcName, i2BoardPtrTable[i]);
783 if (rc) {
784 printk(KERN_ERR "IP2: request_irq failed: "
785 "error %d\n", rc);
786 ip2config.irq[i] = CIR_POLL;
787 printk(KERN_INFO "IP2: Polling %ld/sec.\n",
788 (POLL_TIMEOUT - jiffies));
789 goto retry;
790 }
791 mark_requested_irq(ip2config.irq[i]);
792 /* Initialise the interrupt handler bottom half
793 * (aka slih). */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 }
795 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100796
797 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
798 if (i2BoardPtrTable[i]) {
799 /* set and enable board interrupt */
800 set_irq(i, ip2config.irq[i]);
801 }
802 }
803
804 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
805
806 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808out_chrdev:
809 unregister_chrdev(IP2_IPL_MAJOR, "ip2");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100810 /* unregister and put tty here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 return err;
812}
Jiri Slaby47babd42008-10-13 10:34:27 +0100813module_init(ip2_loadmain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815/******************************************************************************/
816/* Function: ip2_init_board() */
817/* Parameters: Index of board in configuration structure */
818/* Returns: Success (0) */
819/* */
820/* Description: */
821/* This function initializes the specified board. The loadware is copied to */
822/* the board, the channel structures are initialized, and the board details */
823/* are reported on the console. */
824/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700825static void
David Woodhouse547d8bb2008-06-11 16:57:21 +0100826ip2_init_board(int boardnum, const struct firmware *fw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 int i;
829 int nports = 0, nboxes = 0;
830 i2ChanStrPtr pCh;
831 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
832
833 if ( !iiInitialize ( pB ) ) {
834 printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
835 pB->i2eBase, pB->i2eError );
836 goto err_initialize;
837 }
838 printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
839 ip2config.addr[boardnum], ip2config.irq[boardnum] );
840
841 if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
842 printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
843 goto err_initialize;
844 }
845
David Woodhouse547d8bb2008-06-11 16:57:21 +0100846 if ( iiDownloadAll ( pB, (loadHdrStrPtr)fw->data, 1, fw->size )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 != II_DOWN_GOOD ) {
848 printk ( KERN_ERR "IP2: failed to download loadware\n" );
849 goto err_release_region;
850 } else {
851 printk ( KERN_INFO "IP2: fv=%d.%d.%d lv=%d.%d.%d\n",
852 pB->i2ePom.e.porVersion,
853 pB->i2ePom.e.porRevision,
854 pB->i2ePom.e.porSubRev, pB->i2eLVersion,
855 pB->i2eLRevision, pB->i2eLSub );
856 }
857
858 switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
859
860 default:
861 printk( KERN_ERR "IP2: Unknown board type, ID = %x\n",
862 pB->i2ePom.e.porID );
863 nports = 0;
864 goto err_release_region;
865 break;
866
867 case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
868 printk ( KERN_INFO "IP2: ISA-4\n" );
869 nports = 4;
870 break;
871
872 case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
873 printk ( KERN_INFO "IP2: ISA-8 std\n" );
874 nports = 8;
875 break;
876
877 case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
878 printk ( KERN_INFO "IP2: ISA-8 RJ11\n" );
879 nports = 8;
880 break;
881
882 case POR_ID_FIIEX: /* IntelliPort IIEX */
883 {
884 int portnum = IP2_PORTS_PER_BOARD * boardnum;
885 int box;
886
887 for( box = 0; box < ABS_MAX_BOXES; ++box ) {
888 if ( pB->i2eChannelMap[box] != 0 ) {
889 ++nboxes;
890 }
891 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
892 if ( pB->i2eChannelMap[box] & 1<< i ) {
893 ++nports;
894 }
895 }
896 }
897 DevTableMem[boardnum] = pCh =
898 kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
899 if ( !pCh ) {
900 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
901 goto err_release_region;
902 }
903 if ( !i2InitChannels( pB, nports, pCh ) ) {
904 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
905 kfree ( pCh );
906 goto err_release_region;
907 }
908 pB->i2eChannelPtr = &DevTable[portnum];
909 pB->i2eChannelCnt = ABS_MOST_PORTS;
910
911 for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
912 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
913 if ( pB->i2eChannelMap[box] & (1 << i) ) {
914 DevTable[portnum + i] = pCh;
915 pCh->port_index = portnum + i;
916 pCh++;
917 }
918 }
919 }
920 printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit\n",
921 nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
922 }
923 goto ex_exit;
924 }
925 DevTableMem[boardnum] = pCh =
926 kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
927 if ( !pCh ) {
928 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
929 goto err_release_region;
930 }
931 pB->i2eChannelPtr = pCh;
932 pB->i2eChannelCnt = nports;
933 if ( !i2InitChannels( pB, nports, pCh ) ) {
934 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
935 kfree ( pCh );
936 goto err_release_region;
937 }
938 pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
939
940 for( i = 0; i < pB->i2eChannelCnt; ++i ) {
941 DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
942 pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
943 pCh++;
944 }
945ex_exit:
David Howellsc4028952006-11-22 14:57:56 +0000946 INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 return;
948
949err_release_region:
950 release_region(ip2config.addr[boardnum], 8);
951err_initialize:
952 kfree ( pB );
953 i2BoardPtrTable[boardnum] = NULL;
954 return;
955}
956
957/******************************************************************************/
958/* Function: find_eisa_board ( int start_slot ) */
959/* Parameters: First slot to check */
960/* Returns: Address of EISA IntelliPort II controller */
961/* */
962/* Description: */
963/* This function searches for an EISA IntelliPort controller, starting */
964/* from the specified slot number. If the motherboard is not identified as an */
965/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
966/* it returns the base address of the controller. */
967/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700968static unsigned short
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969find_eisa_board( int start_slot )
970{
971 int i, j;
972 unsigned int idm = 0;
973 unsigned int idp = 0;
974 unsigned int base = 0;
975 unsigned int value;
976 int setup_address;
977 int setup_irq;
978 int ismine = 0;
979
980 /*
981 * First a check for an EISA motherboard, which we do by comparing the
982 * EISA ID registers for the system board and the first couple of slots.
983 * No slot ID should match the system board ID, but on an ISA or PCI
984 * machine the odds are that an empty bus will return similar values for
985 * each slot.
986 */
987 i = 0x0c80;
988 value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
989 for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
990 j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
991 if ( value == j )
992 return 0;
993 }
994
995 /*
996 * OK, so we are inclined to believe that this is an EISA machine. Find
997 * an IntelliPort controller.
998 */
999 for( i = start_slot; i < 16; i++ ) {
1000 base = i << 12;
1001 idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
1002 idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
1003 ismine = 0;
1004 if ( idm == 0x0e8e ) {
1005 if ( idp == 0x0281 || idp == 0x0218 ) {
1006 ismine = 1;
1007 } else if ( idp == 0x0282 || idp == 0x0283 ) {
1008 ismine = 3; /* Can do edge-trigger */
1009 }
1010 if ( ismine ) {
1011 Eisa_slot = i;
1012 break;
1013 }
1014 }
1015 }
1016 if ( !ismine )
1017 return 0;
1018
1019 /* It's some sort of EISA card, but at what address is it configured? */
1020
1021 setup_address = base + 0xc88;
1022 value = inb(base + 0xc86);
1023 setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
1024
1025 if ( (ismine & 2) && !(value & 0x10) ) {
1026 ismine = 1; /* Could be edging, but not */
1027 }
1028
1029 if ( Eisa_irq == 0 ) {
1030 Eisa_irq = setup_irq;
1031 } else if ( Eisa_irq != setup_irq ) {
1032 printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
1033 }
1034
1035#ifdef IP2DEBUG_INIT
1036printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
1037 base >> 12, idm, idp, setup_address);
1038 if ( Eisa_irq ) {
1039 printk(KERN_DEBUG ", Interrupt %d %s\n",
1040 setup_irq, (ismine & 2) ? "(edge)" : "(level)");
1041 } else {
1042 printk(KERN_DEBUG ", (polled)\n");
1043 }
1044#endif
1045 return setup_address;
1046}
1047
1048/******************************************************************************/
1049/* Function: set_irq() */
1050/* Parameters: index to board in board table */
1051/* IRQ to use */
1052/* Returns: Success (0) */
1053/* */
1054/* Description: */
1055/******************************************************************************/
1056static void
1057set_irq( int boardnum, int boardIrq )
1058{
1059 unsigned char tempCommand[16];
1060 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
1061 unsigned long flags;
1062
1063 /*
1064 * Notify the boards they may generate interrupts. This is done by
1065 * sending an in-line command to channel 0 on each board. This is why
1066 * the channels have to be defined already. For each board, if the
1067 * interrupt has never been defined, we must do so NOW, directly, since
1068 * board will not send flow control or even give an interrupt until this
1069 * is done. If polling we must send 0 as the interrupt parameter.
1070 */
1071
1072 // We will get an interrupt here at the end of this function
1073
1074 iiDisableMailIrq(pB);
1075
1076 /* We build up the entire packet header. */
1077 CHANNEL_OF(tempCommand) = 0;
1078 PTYPE_OF(tempCommand) = PTYPE_INLINE;
1079 CMD_COUNT_OF(tempCommand) = 2;
1080 (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
1081 (CMD_OF(tempCommand))[1] = boardIrq;
1082 /*
1083 * Write to FIFO; don't bother to adjust fifo capacity for this, since
1084 * board will respond almost immediately after SendMail hit.
1085 */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001086 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001088 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 pB->i2eUsingIrq = boardIrq;
1090 pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
1091
1092 /* Need to update number of boards before you enable mailbox int */
1093 ++i2nBoards;
1094
1095 CHANNEL_OF(tempCommand) = 0;
1096 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1097 CMD_COUNT_OF(tempCommand) = 6;
1098 (CMD_OF(tempCommand))[0] = 88; // SILO
1099 (CMD_OF(tempCommand))[1] = 64; // chars
1100 (CMD_OF(tempCommand))[2] = 32; // ms
1101
1102 (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK
1103 (CMD_OF(tempCommand))[4] = 64; // chars
1104
1105 (CMD_OF(tempCommand))[5] = 87; // HW_TEST
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001106 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 iiWriteBuf(pB, tempCommand, 8);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001108 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
1110 CHANNEL_OF(tempCommand) = 0;
1111 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1112 CMD_COUNT_OF(tempCommand) = 1;
1113 (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */
1114 iiWriteBuf(pB, tempCommand, 3);
1115
1116#ifdef XXX
1117 // enable heartbeat for test porpoises
1118 CHANNEL_OF(tempCommand) = 0;
1119 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1120 CMD_COUNT_OF(tempCommand) = 2;
1121 (CMD_OF(tempCommand))[0] = 44; /* get ping */
1122 (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001123 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001125 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126#endif
1127
1128 iiEnableMailIrq(pB);
1129 iiSendPendingMail(pB);
1130}
1131
1132/******************************************************************************/
1133/* Interrupt Handler Section */
1134/******************************************************************************/
1135
1136static inline void
1137service_all_boards(void)
1138{
1139 int i;
1140 i2eBordStrPtr pB;
1141
1142 /* Service every board on the list */
1143 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
1144 pB = i2BoardPtrTable[i];
1145 if ( pB ) {
1146 i2ServiceBoard( pB );
1147 }
1148 }
1149}
1150
1151
1152/******************************************************************************/
David Howellsc4028952006-11-22 14:57:56 +00001153/* Function: ip2_interrupt_bh(work) */
1154/* Parameters: work - pointer to the board structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155/* Returns: Nothing */
1156/* */
1157/* Description: */
1158/* Service the board in a bottom half interrupt handler and then */
1159/* reenable the board's interrupts if it has an IRQ number */
1160/* */
1161/******************************************************************************/
1162static void
David Howellsc4028952006-11-22 14:57:56 +00001163ip2_interrupt_bh(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164{
David Howellsc4028952006-11-22 14:57:56 +00001165 i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166// pB better well be set or we have a problem! We can only get
1167// here from the IMMEDIATE queue. Here, we process the boards.
1168// Checking pB doesn't cost much and it saves us from the sanity checkers.
1169
1170 bh_counter++;
1171
1172 if ( pB ) {
1173 i2ServiceBoard( pB );
1174 if( pB->i2eUsingIrq ) {
1175// Re-enable his interrupts
1176 iiEnableMailIrq(pB);
1177 }
1178 }
1179}
1180
1181
1182/******************************************************************************/
David Howells7d12e782006-10-05 14:55:46 +01001183/* Function: ip2_interrupt(int irq, void *dev_id) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184/* Parameters: irq - interrupt number */
1185/* pointer to optional device ID structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186/* Returns: Nothing */
1187/* */
1188/* Description: */
1189/* */
1190/* Our task here is simply to identify each board which needs servicing. */
1191/* If we are queuing then, queue it to be serviced, and disable its irq */
1192/* mask otherwise process the board directly. */
1193/* */
1194/* We could queue by IRQ but that just complicates things on both ends */
1195/* with very little gain in performance (how many instructions does */
1196/* it take to iterate on the immediate queue). */
1197/* */
1198/* */
1199/******************************************************************************/
Jeff Garzikf3518e42007-10-19 15:24:59 -04001200static void
1201ip2_irq_work(i2eBordStrPtr pB)
1202{
1203#ifdef USE_IQI
1204 if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
1205// Disable his interrupt (will be enabled when serviced)
1206// This is mostly to protect from reentrancy.
1207 iiDisableMailIrq(pB);
1208
1209// Park the board on the immediate queue for processing.
1210 schedule_work(&pB->tqueue_interrupt);
1211
1212// Make sure the immediate queue is flagged to fire.
1213 }
1214#else
1215
1216// We are using immediate servicing here. This sucks and can
1217// cause all sorts of havoc with ppp and others. The failsafe
1218// check on iiSendPendingMail could also throw a hairball.
1219
1220 i2ServiceBoard( pB );
1221
1222#endif /* USE_IQI */
1223}
1224
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001225static void
1226ip2_polled_interrupt(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227{
1228 int i;
1229 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001231 ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 /* Service just the boards on the list using this irq */
1234 for( i = 0; i < i2nBoards; ++i ) {
1235 pB = i2BoardPtrTable[i];
1236
1237// Only process those boards which match our IRQ.
1238// IRQ = 0 for polled boards, we won't poll "IRQ" boards
1239
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001240 if (pB && pB->i2eUsingIrq == 0)
Jeff Garzikf3518e42007-10-19 15:24:59 -04001241 ip2_irq_work(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
1243
1244 ++irq_counter;
1245
1246 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001247}
1248
1249static irqreturn_t
1250ip2_interrupt(int irq, void *dev_id)
1251{
1252 i2eBordStrPtr pB = dev_id;
1253
1254 ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, pB->i2eUsingIrq );
1255
1256 ip2_irq_work(pB);
1257
1258 ++irq_counter;
1259
1260 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1261 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262}
1263
1264/******************************************************************************/
1265/* Function: ip2_poll(unsigned long arg) */
1266/* Parameters: ? */
1267/* Returns: Nothing */
1268/* */
1269/* Description: */
1270/* This function calls the library routine i2ServiceBoard for each board in */
1271/* the board table. This is used instead of the interrupt routine when polled */
1272/* mode is specified. */
1273/******************************************************************************/
1274static void
1275ip2_poll(unsigned long arg)
1276{
1277 ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
1278
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
1280 // It will NOT poll boards handled by hard interrupts.
Joe Perches8dfba4d2008-02-03 17:11:42 +02001281 // The issue of queued BH interrupts is handled in ip2_interrupt().
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001282 ip2_polled_interrupt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
Akinobu Mita9d020a2e2008-10-13 10:35:05 +01001284 mod_timer(&PollTimer, POLL_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
1286 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1287}
1288
David Howellsc4028952006-11-22 14:57:56 +00001289static void do_input(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290{
David Howellsc4028952006-11-22 14:57:56 +00001291 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 unsigned long flags;
1293
1294 ip2trace(CHANN, ITRC_INPUT, 21, 0 );
1295
1296 // Data input
1297 if ( pCh->pTTY != NULL ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001298 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001300 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 i2Input( pCh );
1302 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001303 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 } else {
1305 ip2trace(CHANN, ITRC_INPUT, 22, 0 );
1306
1307 i2InputFlush( pCh );
1308 }
1309}
1310
1311// code duplicated from n_tty (ldisc)
1312static inline void isig(int sig, struct tty_struct *tty, int flush)
1313{
Alan Coxa352def2008-07-16 21:53:12 +01001314 /* FIXME: This is completely bogus */
Eric W. Biedermanab521dc2007-02-12 00:53:00 -08001315 if (tty->pgrp)
1316 kill_pgrp(tty->pgrp, sig, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (flush || !L_NOFLSH(tty)) {
Alan Coxc65c9bc2009-06-11 12:50:12 +01001318 if ( tty->ldisc->ops->flush_buffer )
1319 tty->ldisc->ops->flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 i2InputFlush( tty->driver_data );
1321 }
1322}
1323
David Howellsc4028952006-11-22 14:57:56 +00001324static void do_status(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325{
David Howellsc4028952006-11-22 14:57:56 +00001326 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 int status;
1328
1329 status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
1330
1331 ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
1332
1333 if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
1334 if ( (status & I2_BRK) ) {
1335 // code duplicated from n_tty (ldisc)
1336 if (I_IGNBRK(pCh->pTTY))
1337 goto skip_this;
1338 if (I_BRKINT(pCh->pTTY)) {
1339 isig(SIGINT, pCh->pTTY, 1);
1340 goto skip_this;
1341 }
1342 wake_up_interruptible(&pCh->pTTY->read_wait);
1343 }
1344#ifdef NEVER_HAPPENS_AS_SETUP_XXX
1345 // and can't work because we don't know the_char
1346 // as the_char is reported on a separate path
1347 // The intelligent board does this stuff as setup
1348 {
1349 char brkf = TTY_NORMAL;
1350 unsigned char brkc = '\0';
1351 unsigned char tmp;
1352 if ( (status & I2_BRK) ) {
1353 brkf = TTY_BREAK;
1354 brkc = '\0';
1355 }
1356 else if (status & I2_PAR) {
1357 brkf = TTY_PARITY;
1358 brkc = the_char;
1359 } else if (status & I2_FRA) {
1360 brkf = TTY_FRAME;
1361 brkc = the_char;
1362 } else if (status & I2_OVR) {
1363 brkf = TTY_OVERRUN;
1364 brkc = the_char;
1365 }
1366 tmp = pCh->pTTY->real_raw;
1367 pCh->pTTY->real_raw = 0;
Alan Coxa352def2008-07-16 21:53:12 +01001368 pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 pCh->pTTY->real_raw = tmp;
1370 }
1371#endif /* NEVER_HAPPENS_AS_SETUP_XXX */
1372 }
1373skip_this:
1374
1375 if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
1376 wake_up_interruptible(&pCh->delta_msr_wait);
1377
1378 if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
1379 if ( status & I2_DCD ) {
1380 if ( pCh->wopen ) {
1381 wake_up_interruptible ( &pCh->open_wait );
1382 }
1383 } else {
1384 if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
1385 tty_hangup( pCh->pTTY );
1386 }
1387 }
1388 }
1389 }
1390
1391 ip2trace (CHANN, ITRC_STATUS, 26, 0 );
1392}
1393
1394/******************************************************************************/
1395/* Device Open/Close/Ioctl Entry Point Section */
1396/******************************************************************************/
1397
1398/******************************************************************************/
1399/* Function: open_sanity_check() */
1400/* Parameters: Pointer to tty structure */
1401/* Pointer to file structure */
1402/* Returns: Success or failure */
1403/* */
1404/* Description: */
1405/* Verifies the structure magic numbers and cross links. */
1406/******************************************************************************/
1407#ifdef IP2DEBUG_OPEN
1408static void
1409open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
1410{
1411 if ( pBrd->i2eValid != I2E_MAGIC ) {
1412 printk(KERN_ERR "IP2: invalid board structure\n" );
1413 } else if ( pBrd != pCh->pMyBord ) {
1414 printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
1415 pCh->pMyBord );
1416 } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
1417 printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
1418 } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
1419 } else {
1420 printk(KERN_INFO "IP2: all pointers check out!\n" );
1421 }
1422}
1423#endif
1424
1425
1426/******************************************************************************/
1427/* Function: ip2_open() */
1428/* Parameters: Pointer to tty structure */
1429/* Pointer to file structure */
1430/* Returns: Success or failure */
1431/* */
1432/* Description: (MANDATORY) */
1433/* A successful device open has to run a gauntlet of checks before it */
1434/* completes. After some sanity checking and pointer setup, the function */
1435/* blocks until all conditions are satisfied. It then initialises the port to */
1436/* the default characteristics and returns. */
1437/******************************************************************************/
1438static int
1439ip2_open( PTTY tty, struct file *pFile )
1440{
1441 wait_queue_t wait;
1442 int rc = 0;
1443 int do_clocal = 0;
1444 i2ChanStrPtr pCh = DevTable[tty->index];
1445
1446 ip2trace (tty->index, ITRC_OPEN, ITRC_ENTER, 0 );
1447
1448 if ( pCh == NULL ) {
1449 return -ENODEV;
1450 }
1451 /* Setup pointer links in device and tty structures */
1452 pCh->pTTY = tty;
1453 tty->driver_data = pCh;
1454
1455#ifdef IP2DEBUG_OPEN
1456 printk(KERN_DEBUG \
1457 "IP2:open(tty=%p,pFile=%p):dev=%s,ch=%d,idx=%d\n",
1458 tty, pFile, tty->name, pCh->infl.hd.i2sChannel, pCh->port_index);
1459 open_sanity_check ( pCh, pCh->pMyBord );
1460#endif
1461
1462 i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP);
1463 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1464 serviceOutgoingFifo( pCh->pMyBord );
1465
1466 /* Block here until the port is ready (per serial and istallion) */
1467 /*
1468 * 1. If the port is in the middle of closing wait for the completion
1469 * and then return the appropriate error.
1470 */
1471 init_waitqueue_entry(&wait, current);
1472 add_wait_queue(&pCh->close_wait, &wait);
1473 set_current_state( TASK_INTERRUPTIBLE );
1474
1475 if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
1476 if ( pCh->flags & ASYNC_CLOSING ) {
1477 schedule();
1478 }
1479 if ( tty_hung_up_p(pFile) ) {
1480 set_current_state( TASK_RUNNING );
1481 remove_wait_queue(&pCh->close_wait, &wait);
1482 return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
1483 }
1484 }
1485 set_current_state( TASK_RUNNING );
1486 remove_wait_queue(&pCh->close_wait, &wait);
1487
1488 /*
1489 * 3. Handle a non-blocking open of a normal port.
1490 */
1491 if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
1492 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1493 goto noblock;
1494 }
1495 /*
1496 * 4. Now loop waiting for the port to be free and carrier present
1497 * (if required).
1498 */
1499 if ( tty->termios->c_cflag & CLOCAL )
1500 do_clocal = 1;
1501
1502#ifdef IP2DEBUG_OPEN
1503 printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
1504#endif
1505
1506 ++pCh->wopen;
1507
1508 init_waitqueue_entry(&wait, current);
1509 add_wait_queue(&pCh->open_wait, &wait);
1510
1511 for(;;) {
1512 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1513 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1514 set_current_state( TASK_INTERRUPTIBLE );
1515 serviceOutgoingFifo( pCh->pMyBord );
1516 if ( tty_hung_up_p(pFile) ) {
1517 set_current_state( TASK_RUNNING );
1518 remove_wait_queue(&pCh->open_wait, &wait);
1519 return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
1520 }
1521 if (!(pCh->flags & ASYNC_CLOSING) &&
1522 (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
1523 rc = 0;
1524 break;
1525 }
1526
1527#ifdef IP2DEBUG_OPEN
1528 printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
1529 (pCh->flags & ASYNC_CLOSING)?"True":"False");
1530 printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
1531#endif
1532 ip2trace (CHANN, ITRC_OPEN, 3, 2, 0,
1533 (pCh->flags & ASYNC_CLOSING) );
1534 /* check for signal */
1535 if (signal_pending(current)) {
1536 rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
1537 break;
1538 }
1539 schedule();
1540 }
1541 set_current_state( TASK_RUNNING );
1542 remove_wait_queue(&pCh->open_wait, &wait);
1543
1544 --pCh->wopen; //why count?
1545
1546 ip2trace (CHANN, ITRC_OPEN, 4, 0 );
1547
1548 if (rc != 0 ) {
1549 return rc;
1550 }
1551 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1552
1553noblock:
1554
1555 /* first open - Assign termios structure to port */
1556 if ( tty->count == 1 ) {
1557 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1558 /* Now we must send the termios settings to the loadware */
1559 set_params( pCh, NULL );
1560 }
1561
1562 /*
1563 * Now set any i2lib options. These may go away if the i2lib code ends
1564 * up rolled into the mainline.
1565 */
1566 pCh->channelOptions |= CO_NBLOCK_WRITE;
1567
1568#ifdef IP2DEBUG_OPEN
1569 printk (KERN_DEBUG "IP2: open completed\n" );
1570#endif
1571 serviceOutgoingFifo( pCh->pMyBord );
1572
1573 ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
1574
1575 return 0;
1576}
1577
1578/******************************************************************************/
1579/* Function: ip2_close() */
1580/* Parameters: Pointer to tty structure */
1581/* Pointer to file structure */
1582/* Returns: Nothing */
1583/* */
1584/* Description: */
1585/* */
1586/* */
1587/******************************************************************************/
1588static void
1589ip2_close( PTTY tty, struct file *pFile )
1590{
1591 i2ChanStrPtr pCh = tty->driver_data;
1592
1593 if ( !pCh ) {
1594 return;
1595 }
1596
1597 ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
1598
1599#ifdef IP2DEBUG_OPEN
1600 printk(KERN_DEBUG "IP2:close %s:\n",tty->name);
1601#endif
1602
1603 if ( tty_hung_up_p ( pFile ) ) {
1604
1605 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
1606
1607 return;
1608 }
1609 if ( tty->count > 1 ) { /* not the last close */
1610
1611 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
1612
1613 return;
1614 }
1615 pCh->flags |= ASYNC_CLOSING; // last close actually
1616
1617 tty->closing = 1;
1618
1619 if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
1620 /*
1621 * Before we drop DTR, make sure the transmitter has completely drained.
1622 * This uses an timeout, after which the close
1623 * completes.
1624 */
1625 ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
1626 }
1627 /*
1628 * At this point we stop accepting input. Here we flush the channel
1629 * input buffer which will allow the board to send up more data. Any
1630 * additional input is tossed at interrupt/poll time.
1631 */
1632 i2InputFlush( pCh );
1633
1634 /* disable DSS reporting */
1635 i2QueueCommands(PTYPE_INLINE, pCh, 100, 4,
1636 CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1637 if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
1638 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
1639 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1640 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1641 }
1642
1643 serviceOutgoingFifo ( pCh->pMyBord );
1644
Alan Coxf34d7a52008-04-30 00:54:13 -07001645 tty_ldisc_flush(tty);
Alan Coxa6fc8192008-04-30 00:54:18 -07001646 tty_driver_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 tty->closing = 0;
1648
1649 pCh->pTTY = NULL;
1650
1651 if (pCh->wopen) {
1652 if (pCh->ClosingDelay) {
1653 msleep_interruptible(jiffies_to_msecs(pCh->ClosingDelay));
1654 }
1655 wake_up_interruptible(&pCh->open_wait);
1656 }
1657
1658 pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1659 wake_up_interruptible(&pCh->close_wait);
1660
1661#ifdef IP2DEBUG_OPEN
1662 DBG_CNT("ip2_close: after wakeups--");
1663#endif
1664
1665
1666 ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
1667
1668 return;
1669}
1670
1671/******************************************************************************/
1672/* Function: ip2_hangup() */
1673/* Parameters: Pointer to tty structure */
1674/* Returns: Nothing */
1675/* */
1676/* Description: */
1677/* */
1678/* */
1679/******************************************************************************/
1680static void
1681ip2_hangup ( PTTY tty )
1682{
1683 i2ChanStrPtr pCh = tty->driver_data;
1684
1685 if( !pCh ) {
1686 return;
1687 }
1688
1689 ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
1690
1691 ip2_flush_buffer(tty);
1692
1693 /* disable DSS reporting */
1694
1695 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
1696 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1697 if ( (tty->termios->c_cflag & HUPCL) ) {
1698 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
1699 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1700 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1701 }
1702 i2QueueCommands(PTYPE_INLINE, pCh, 1, 3,
1703 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1704 serviceOutgoingFifo ( pCh->pMyBord );
1705
1706 wake_up_interruptible ( &pCh->delta_msr_wait );
1707
1708 pCh->flags &= ~ASYNC_NORMAL_ACTIVE;
1709 pCh->pTTY = NULL;
1710 wake_up_interruptible ( &pCh->open_wait );
1711
1712 ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
1713}
1714
1715/******************************************************************************/
1716/******************************************************************************/
1717/* Device Output Section */
1718/******************************************************************************/
1719/******************************************************************************/
1720
1721/******************************************************************************/
1722/* Function: ip2_write() */
1723/* Parameters: Pointer to tty structure */
1724/* Flag denoting data is in user (1) or kernel (0) space */
1725/* Pointer to data */
1726/* Number of bytes to write */
1727/* Returns: Number of bytes actually written */
1728/* */
1729/* Description: (MANDATORY) */
1730/* */
1731/* */
1732/******************************************************************************/
1733static int
Alan Coxd9e39532006-01-09 20:54:20 -08001734ip2_write( PTTY tty, const unsigned char *pData, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735{
1736 i2ChanStrPtr pCh = tty->driver_data;
1737 int bytesSent = 0;
1738 unsigned long flags;
1739
1740 ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
1741
1742 /* Flush out any buffered data left over from ip2_putchar() calls. */
1743 ip2_flush_chars( tty );
1744
1745 /* This is the actual move bit. Make sure it does what we need!!!!! */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001746 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Al Virof061c582006-10-11 17:45:47 +01001747 bytesSent = i2Output( pCh, pData, count);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001748 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
1750 ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
1751
1752 return bytesSent > 0 ? bytesSent : 0;
1753}
1754
1755/******************************************************************************/
1756/* Function: ip2_putchar() */
1757/* Parameters: Pointer to tty structure */
1758/* Character to write */
1759/* Returns: Nothing */
1760/* */
1761/* Description: */
1762/* */
1763/* */
1764/******************************************************************************/
Alan Coxf34d7a52008-04-30 00:54:13 -07001765static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766ip2_putchar( PTTY tty, unsigned char ch )
1767{
1768 i2ChanStrPtr pCh = tty->driver_data;
1769 unsigned long flags;
1770
1771// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
1772
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001773 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
1775 if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001776 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 ip2_flush_chars( tty );
1778 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001779 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Alan Coxf34d7a52008-04-30 00:54:13 -07001780 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
1782// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
1783}
1784
1785/******************************************************************************/
1786/* Function: ip2_flush_chars() */
1787/* Parameters: Pointer to tty structure */
1788/* Returns: Nothing */
1789/* */
1790/* Description: */
1791/* */
1792/******************************************************************************/
1793static void
1794ip2_flush_chars( PTTY tty )
1795{
1796 int strip;
1797 i2ChanStrPtr pCh = tty->driver_data;
1798 unsigned long flags;
1799
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001800 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 if ( pCh->Pbuf_stuff ) {
1802
1803// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
1804
1805 //
1806 // We may need to restart i2Output if it does not fullfill this request
1807 //
Al Virof061c582006-10-11 17:45:47 +01001808 strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 if ( strip != pCh->Pbuf_stuff ) {
1810 memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
1811 }
1812 pCh->Pbuf_stuff -= strip;
1813 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001814 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815}
1816
1817/******************************************************************************/
1818/* Function: ip2_write_room() */
1819/* Parameters: Pointer to tty structure */
1820/* Returns: Number of bytes that the driver can accept */
1821/* */
1822/* Description: */
1823/* */
1824/******************************************************************************/
1825static int
1826ip2_write_room ( PTTY tty )
1827{
1828 int bytesFree;
1829 i2ChanStrPtr pCh = tty->driver_data;
1830 unsigned long flags;
1831
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001832 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001834 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835
1836 ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
1837
1838 return ((bytesFree > 0) ? bytesFree : 0);
1839}
1840
1841/******************************************************************************/
1842/* Function: ip2_chars_in_buf() */
1843/* Parameters: Pointer to tty structure */
1844/* Returns: Number of bytes queued for transmission */
1845/* */
1846/* Description: */
1847/* */
1848/* */
1849/******************************************************************************/
1850static int
1851ip2_chars_in_buf ( PTTY tty )
1852{
1853 i2ChanStrPtr pCh = tty->driver_data;
1854 int rc;
1855 unsigned long flags;
1856
1857 ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
1858
1859#ifdef IP2DEBUG_WRITE
1860 printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
1861 pCh->Obuf_char_count + pCh->Pbuf_stuff,
1862 pCh->Obuf_char_count, pCh->Pbuf_stuff );
1863#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001864 read_lock_irqsave(&pCh->Obuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 rc = pCh->Obuf_char_count;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001866 read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
1867 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 rc += pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001869 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 return rc;
1871}
1872
1873/******************************************************************************/
1874/* Function: ip2_flush_buffer() */
1875/* Parameters: Pointer to tty structure */
1876/* Returns: Nothing */
1877/* */
1878/* Description: */
1879/* */
1880/* */
1881/******************************************************************************/
1882static void
1883ip2_flush_buffer( PTTY tty )
1884{
1885 i2ChanStrPtr pCh = tty->driver_data;
1886 unsigned long flags;
1887
1888 ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
1889
1890#ifdef IP2DEBUG_WRITE
1891 printk (KERN_DEBUG "IP2: flush buffer\n" );
1892#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001893 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 pCh->Pbuf_stuff = 0;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001895 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 i2FlushOutput( pCh );
1897 ip2_owake(tty);
1898
1899 ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
1900
1901}
1902
1903/******************************************************************************/
1904/* Function: ip2_wait_until_sent() */
1905/* Parameters: Pointer to tty structure */
1906/* Timeout for wait. */
1907/* Returns: Nothing */
1908/* */
1909/* Description: */
1910/* This function is used in place of the normal tty_wait_until_sent, which */
1911/* only waits for the driver buffers to be empty (or rather, those buffers */
1912/* reported by chars_in_buffer) which doesn't work for IP2 due to the */
1913/* indeterminate number of bytes buffered on the board. */
1914/******************************************************************************/
1915static void
1916ip2_wait_until_sent ( PTTY tty, int timeout )
1917{
1918 int i = jiffies;
1919 i2ChanStrPtr pCh = tty->driver_data;
1920
1921 tty_wait_until_sent(tty, timeout );
1922 if ( (i = timeout - (jiffies -i)) > 0)
1923 i2DrainOutput( pCh, i );
1924}
1925
1926/******************************************************************************/
1927/******************************************************************************/
1928/* Device Input Section */
1929/******************************************************************************/
1930/******************************************************************************/
1931
1932/******************************************************************************/
1933/* Function: ip2_throttle() */
1934/* Parameters: Pointer to tty structure */
1935/* Returns: Nothing */
1936/* */
1937/* Description: */
1938/* */
1939/* */
1940/******************************************************************************/
1941static void
1942ip2_throttle ( PTTY tty )
1943{
1944 i2ChanStrPtr pCh = tty->driver_data;
1945
1946#ifdef IP2DEBUG_READ
1947 printk (KERN_DEBUG "IP2: throttle\n" );
1948#endif
1949 /*
1950 * Signal the poll/interrupt handlers not to forward incoming data to
1951 * the line discipline. This will cause the buffers to fill up in the
1952 * library and thus cause the library routines to send the flow control
1953 * stuff.
1954 */
1955 pCh->throttled = 1;
1956}
1957
1958/******************************************************************************/
1959/* Function: ip2_unthrottle() */
1960/* Parameters: Pointer to tty structure */
1961/* Returns: Nothing */
1962/* */
1963/* Description: */
1964/* */
1965/* */
1966/******************************************************************************/
1967static void
1968ip2_unthrottle ( PTTY tty )
1969{
1970 i2ChanStrPtr pCh = tty->driver_data;
1971 unsigned long flags;
1972
1973#ifdef IP2DEBUG_READ
1974 printk (KERN_DEBUG "IP2: unthrottle\n" );
1975#endif
1976
1977 /* Pass incoming data up to the line discipline again. */
1978 pCh->throttled = 0;
1979 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
1980 serviceOutgoingFifo( pCh->pMyBord );
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001981 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001983 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984#ifdef IP2DEBUG_READ
1985 printk (KERN_DEBUG "i2Input called from unthrottle\n" );
1986#endif
1987 i2Input( pCh );
1988 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001989 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990}
1991
1992static void
1993ip2_start ( PTTY tty )
1994{
1995 i2ChanStrPtr pCh = DevTable[tty->index];
1996
1997 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
1998 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
1999 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
2000#ifdef IP2DEBUG_WRITE
2001 printk (KERN_DEBUG "IP2: start tx\n" );
2002#endif
2003}
2004
2005static void
2006ip2_stop ( PTTY tty )
2007{
2008 i2ChanStrPtr pCh = DevTable[tty->index];
2009
2010 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
2011#ifdef IP2DEBUG_WRITE
2012 printk (KERN_DEBUG "IP2: stop tx\n" );
2013#endif
2014}
2015
2016/******************************************************************************/
2017/* Device Ioctl Section */
2018/******************************************************************************/
2019
2020static int ip2_tiocmget(struct tty_struct *tty, struct file *file)
2021{
2022 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002023#ifdef ENABLE_DSSNOW
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 wait_queue_t wait;
Alan Coxd9e39532006-01-09 20:54:20 -08002025#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
2027 if (pCh == NULL)
2028 return -ENODEV;
2029
2030/*
2031 FIXME - the following code is causing a NULL pointer dereference in
2032 2.3.51 in an interrupt handler. It's suppose to prompt the board
2033 to return the DSS signal status immediately. Why doesn't it do
2034 the same thing in 2.2.14?
2035*/
2036
2037/* This thing is still busted in the 1.2.12 driver on 2.4.x
2038 and even hoses the serial console so the oops can be trapped.
2039 /\/\|=mhw=|\/\/ */
2040
2041#ifdef ENABLE_DSSNOW
2042 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
2043
2044 init_waitqueue_entry(&wait, current);
2045 add_wait_queue(&pCh->dss_now_wait, &wait);
2046 set_current_state( TASK_INTERRUPTIBLE );
2047
2048 serviceOutgoingFifo( pCh->pMyBord );
2049
2050 schedule();
2051
2052 set_current_state( TASK_RUNNING );
2053 remove_wait_queue(&pCh->dss_now_wait, &wait);
2054
2055 if (signal_pending(current)) {
2056 return -EINTR;
2057 }
2058#endif
2059 return ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
2060 | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
2061 | ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0)
2062 | ((pCh->dataSetIn & I2_RI) ? TIOCM_RNG : 0)
2063 | ((pCh->dataSetIn & I2_DSR) ? TIOCM_DSR : 0)
2064 | ((pCh->dataSetIn & I2_CTS) ? TIOCM_CTS : 0);
2065}
2066
2067static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
2068 unsigned int set, unsigned int clear)
2069{
2070 i2ChanStrPtr pCh = DevTable[tty->index];
2071
2072 if (pCh == NULL)
2073 return -ENODEV;
2074
2075 if (set & TIOCM_RTS) {
2076 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2077 pCh->dataSetOut |= I2_RTS;
2078 }
2079 if (set & TIOCM_DTR) {
2080 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2081 pCh->dataSetOut |= I2_DTR;
2082 }
2083
2084 if (clear & TIOCM_RTS) {
2085 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2086 pCh->dataSetOut &= ~I2_RTS;
2087 }
2088 if (clear & TIOCM_DTR) {
2089 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2090 pCh->dataSetOut &= ~I2_DTR;
2091 }
2092 serviceOutgoingFifo( pCh->pMyBord );
2093 return 0;
2094}
2095
2096/******************************************************************************/
2097/* Function: ip2_ioctl() */
2098/* Parameters: Pointer to tty structure */
2099/* Pointer to file structure */
2100/* Command */
2101/* Argument */
2102/* Returns: Success or failure */
2103/* */
2104/* Description: */
2105/* */
2106/* */
2107/******************************************************************************/
2108static int
2109ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
2110{
2111 wait_queue_t wait;
2112 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002113 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 struct async_icount cprev, cnow; /* kernel counter temps */
2115 struct serial_icounter_struct __user *p_cuser;
2116 int rc = 0;
2117 unsigned long flags;
2118 void __user *argp = (void __user *)arg;
2119
Alan Coxd9e39532006-01-09 20:54:20 -08002120 if ( pCh == NULL )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 return -ENODEV;
Alan Coxd9e39532006-01-09 20:54:20 -08002122
2123 pB = pCh->pMyBord;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
2125 ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
2126
2127#ifdef IP2DEBUG_IOCTL
2128 printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
2129#endif
2130
2131 switch(cmd) {
2132 case TIOCGSERIAL:
2133
2134 ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
2135
2136 rc = get_serial_info(pCh, argp);
2137 if (rc)
2138 return rc;
2139 break;
2140
2141 case TIOCSSERIAL:
2142
2143 ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
2144
2145 rc = set_serial_info(pCh, argp);
2146 if (rc)
2147 return rc;
2148 break;
2149
2150 case TCXONC:
2151 rc = tty_check_change(tty);
2152 if (rc)
2153 return rc;
2154 switch (arg) {
2155 case TCOOFF:
2156 //return -ENOIOCTLCMD;
2157 break;
2158 case TCOON:
2159 //return -ENOIOCTLCMD;
2160 break;
2161 case TCIOFF:
2162 if (STOP_CHAR(tty) != __DISABLED_CHAR) {
2163 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2164 CMD_XMIT_NOW(STOP_CHAR(tty)));
2165 }
2166 break;
2167 case TCION:
2168 if (START_CHAR(tty) != __DISABLED_CHAR) {
2169 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2170 CMD_XMIT_NOW(START_CHAR(tty)));
2171 }
2172 break;
2173 default:
2174 return -EINVAL;
2175 }
2176 return 0;
2177
2178 case TCSBRK: /* SVID version: non-zero arg --> no break */
2179 rc = tty_check_change(tty);
2180
2181 ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
2182
2183 if (!rc) {
2184 ip2_wait_until_sent(tty,0);
2185 if (!arg) {
2186 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
2187 serviceOutgoingFifo( pCh->pMyBord );
2188 }
2189 }
2190 break;
2191
2192 case TCSBRKP: /* support for POSIX tcsendbreak() */
2193 rc = tty_check_change(tty);
2194
2195 ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
2196
2197 if (!rc) {
2198 ip2_wait_until_sent(tty,0);
2199 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2200 CMD_SEND_BRK(arg ? arg*100 : 250));
2201 serviceOutgoingFifo ( pCh->pMyBord );
2202 }
2203 break;
2204
2205 case TIOCGSOFTCAR:
2206
2207 ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
2208
2209 rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
2210 if (rc)
2211 return rc;
2212 break;
2213
2214 case TIOCSSOFTCAR:
2215
2216 ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
2217
2218 rc = get_user(arg,(unsigned long __user *) argp);
2219 if (rc)
2220 return rc;
2221 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
2222 | (arg ? CLOCAL : 0));
2223
2224 break;
2225
2226 /*
2227 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
2228 * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
2229 * for masking). Caller should use TIOCGICOUNT to see which one it was
2230 */
2231 case TIOCMIWAIT:
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002232 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 cprev = pCh->icount; /* note the counters on entry */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002234 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
2236 CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
2237 init_waitqueue_entry(&wait, current);
2238 add_wait_queue(&pCh->delta_msr_wait, &wait);
2239 set_current_state( TASK_INTERRUPTIBLE );
2240
2241 serviceOutgoingFifo( pCh->pMyBord );
2242 for(;;) {
2243 ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
2244
2245 schedule();
2246
2247 ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
2248
2249 /* see if a signal did it */
2250 if (signal_pending(current)) {
2251 rc = -ERESTARTSYS;
2252 break;
2253 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002254 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 cnow = pCh->icount; /* atomic copy */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002256 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2258 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2259 rc = -EIO; /* no change => rc */
2260 break;
2261 }
2262 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2263 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2264 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2265 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2266 rc = 0;
2267 break;
2268 }
2269 cprev = cnow;
2270 }
2271 set_current_state( TASK_RUNNING );
2272 remove_wait_queue(&pCh->delta_msr_wait, &wait);
2273
2274 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3,
2275 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
2276 if ( ! (pCh->flags & ASYNC_CHECK_CD)) {
2277 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP);
2278 }
2279 serviceOutgoingFifo( pCh->pMyBord );
2280 return rc;
2281 break;
2282
2283 /*
2284 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2285 * Return: write counters to the user passed counter struct
2286 * NB: both 1->0 and 0->1 transitions are counted except for RI where
2287 * only 0->1 is counted. The controller is quite capable of counting
2288 * both, but this done to preserve compatibility with the standard
2289 * serial driver.
2290 */
2291 case TIOCGICOUNT:
2292 ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
2293
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002294 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 cnow = pCh->icount;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002296 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 p_cuser = argp;
2298 rc = put_user(cnow.cts, &p_cuser->cts);
2299 rc = put_user(cnow.dsr, &p_cuser->dsr);
2300 rc = put_user(cnow.rng, &p_cuser->rng);
2301 rc = put_user(cnow.dcd, &p_cuser->dcd);
2302 rc = put_user(cnow.rx, &p_cuser->rx);
2303 rc = put_user(cnow.tx, &p_cuser->tx);
2304 rc = put_user(cnow.frame, &p_cuser->frame);
2305 rc = put_user(cnow.overrun, &p_cuser->overrun);
2306 rc = put_user(cnow.parity, &p_cuser->parity);
2307 rc = put_user(cnow.brk, &p_cuser->brk);
2308 rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
2309 break;
2310
2311 /*
2312 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
2313 * will be passed to the line discipline for it to handle.
2314 */
2315 case TIOCSERCONFIG:
2316 case TIOCSERGWILD:
2317 case TIOCSERGETLSR:
2318 case TIOCSERSWILD:
2319 case TIOCSERGSTRUCT:
2320 case TIOCSERGETMULTI:
2321 case TIOCSERSETMULTI:
2322
2323 default:
2324 ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
2325
2326 rc = -ENOIOCTLCMD;
2327 break;
2328 }
2329
2330 ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
2331
2332 return rc;
2333}
2334
2335/******************************************************************************/
2336/* Function: GetSerialInfo() */
2337/* Parameters: Pointer to channel structure */
2338/* Pointer to old termios structure */
2339/* Returns: Nothing */
2340/* */
2341/* Description: */
2342/* This is to support the setserial command, and requires processing of the */
2343/* standard Linux serial structure. */
2344/******************************************************************************/
2345static int
2346get_serial_info ( i2ChanStrPtr pCh, struct serial_struct __user *retinfo )
2347{
2348 struct serial_struct tmp;
2349
2350 memset ( &tmp, 0, sizeof(tmp) );
2351 tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
2352 if (BID_HAS_654(tmp.type)) {
2353 tmp.type = PORT_16650;
2354 } else {
2355 tmp.type = PORT_CIRRUS;
2356 }
2357 tmp.line = pCh->port_index;
2358 tmp.port = pCh->pMyBord->i2eBase;
2359 tmp.irq = ip2config.irq[pCh->port_index/64];
2360 tmp.flags = pCh->flags;
2361 tmp.baud_base = pCh->BaudBase;
2362 tmp.close_delay = pCh->ClosingDelay;
2363 tmp.closing_wait = pCh->ClosingWaitTime;
2364 tmp.custom_divisor = pCh->BaudDivisor;
2365 return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
2366}
2367
2368/******************************************************************************/
2369/* Function: SetSerialInfo() */
2370/* Parameters: Pointer to channel structure */
2371/* Pointer to old termios structure */
2372/* Returns: Nothing */
2373/* */
2374/* Description: */
2375/* This function provides support for setserial, which uses the TIOCSSERIAL */
2376/* ioctl. Not all setserial parameters are relevant. If the user attempts to */
2377/* change the IRQ, address or type of the port the ioctl fails. */
2378/******************************************************************************/
2379static int
2380set_serial_info( i2ChanStrPtr pCh, struct serial_struct __user *new_info )
2381{
2382 struct serial_struct ns;
2383 int old_flags, old_baud_divisor;
2384
2385 if (copy_from_user(&ns, new_info, sizeof (ns)))
2386 return -EFAULT;
2387
2388 /*
2389 * We don't allow setserial to change IRQ, board address, type or baud
2390 * base. Also line nunber as such is meaningless but we use it for our
2391 * array index so it is fixed also.
2392 */
2393 if ( (ns.irq != ip2config.irq[pCh->port_index])
2394 || ((int) ns.port != ((int) (pCh->pMyBord->i2eBase)))
2395 || (ns.baud_base != pCh->BaudBase)
2396 || (ns.line != pCh->port_index) ) {
2397 return -EINVAL;
2398 }
2399
2400 old_flags = pCh->flags;
2401 old_baud_divisor = pCh->BaudDivisor;
2402
2403 if ( !capable(CAP_SYS_ADMIN) ) {
2404 if ( ( ns.close_delay != pCh->ClosingDelay ) ||
2405 ( (ns.flags & ~ASYNC_USR_MASK) !=
2406 (pCh->flags & ~ASYNC_USR_MASK) ) ) {
2407 return -EPERM;
2408 }
2409
2410 pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
2411 (ns.flags & ASYNC_USR_MASK);
2412 pCh->BaudDivisor = ns.custom_divisor;
2413 } else {
2414 pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
2415 (ns.flags & ASYNC_FLAGS);
2416 pCh->BaudDivisor = ns.custom_divisor;
2417 pCh->ClosingDelay = ns.close_delay * HZ/100;
2418 pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
2419 }
2420
2421 if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
2422 || (old_baud_divisor != pCh->BaudDivisor) ) {
2423 // Invalidate speed and reset parameters
2424 set_params( pCh, NULL );
2425 }
2426
2427 return 0;
2428}
2429
2430/******************************************************************************/
2431/* Function: ip2_set_termios() */
2432/* Parameters: Pointer to tty structure */
2433/* Pointer to old termios structure */
2434/* Returns: Nothing */
2435/* */
2436/* Description: */
2437/* */
2438/* */
2439/******************************************************************************/
2440static void
Alan Cox606d0992006-12-08 02:38:45 -08002441ip2_set_termios( PTTY tty, struct ktermios *old_termios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442{
2443 i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
2444
2445#ifdef IP2DEBUG_IOCTL
2446 printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
2447#endif
2448
2449 set_params( pCh, old_termios );
2450}
2451
2452/******************************************************************************/
2453/* Function: ip2_set_line_discipline() */
2454/* Parameters: Pointer to tty structure */
2455/* Returns: Nothing */
2456/* */
2457/* Description: Does nothing */
2458/* */
2459/* */
2460/******************************************************************************/
2461static void
2462ip2_set_line_discipline ( PTTY tty )
2463{
2464#ifdef IP2DEBUG_IOCTL
2465 printk (KERN_DEBUG "IP2: set line discipline\n" );
2466#endif
2467
2468 ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
2469
2470}
2471
2472/******************************************************************************/
2473/* Function: SetLine Characteristics() */
2474/* Parameters: Pointer to channel structure */
2475/* Returns: Nothing */
2476/* */
2477/* Description: */
2478/* This routine is called to update the channel structure with the new line */
2479/* characteristics, and send the appropriate commands to the board when they */
2480/* change. */
2481/******************************************************************************/
2482static void
Alan Cox606d0992006-12-08 02:38:45 -08002483set_params( i2ChanStrPtr pCh, struct ktermios *o_tios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484{
2485 tcflag_t cflag, iflag, lflag;
2486 char stop_char, start_char;
Alan Cox606d0992006-12-08 02:38:45 -08002487 struct ktermios dummy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488
2489 lflag = pCh->pTTY->termios->c_lflag;
2490 cflag = pCh->pTTY->termios->c_cflag;
2491 iflag = pCh->pTTY->termios->c_iflag;
2492
2493 if (o_tios == NULL) {
2494 dummy.c_lflag = ~lflag;
2495 dummy.c_cflag = ~cflag;
2496 dummy.c_iflag = ~iflag;
2497 o_tios = &dummy;
2498 }
2499
2500 {
2501 switch ( cflag & CBAUD ) {
2502 case B0:
2503 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
2504 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
2505 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
2506 pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
2507 goto service_it;
2508 break;
2509 case B38400:
2510 /*
2511 * This is the speed that is overloaded with all the other high
2512 * speeds, depending upon the flag settings.
2513 */
2514 if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
2515 pCh->speed = CBR_57600;
2516 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
2517 pCh->speed = CBR_115200;
2518 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
2519 pCh->speed = CBR_C1;
2520 } else {
2521 pCh->speed = CBR_38400;
2522 }
2523 break;
2524 case B50: pCh->speed = CBR_50; break;
2525 case B75: pCh->speed = CBR_75; break;
2526 case B110: pCh->speed = CBR_110; break;
2527 case B134: pCh->speed = CBR_134; break;
2528 case B150: pCh->speed = CBR_150; break;
2529 case B200: pCh->speed = CBR_200; break;
2530 case B300: pCh->speed = CBR_300; break;
2531 case B600: pCh->speed = CBR_600; break;
2532 case B1200: pCh->speed = CBR_1200; break;
2533 case B1800: pCh->speed = CBR_1800; break;
2534 case B2400: pCh->speed = CBR_2400; break;
2535 case B4800: pCh->speed = CBR_4800; break;
2536 case B9600: pCh->speed = CBR_9600; break;
2537 case B19200: pCh->speed = CBR_19200; break;
2538 case B57600: pCh->speed = CBR_57600; break;
2539 case B115200: pCh->speed = CBR_115200; break;
2540 case B153600: pCh->speed = CBR_153600; break;
2541 case B230400: pCh->speed = CBR_230400; break;
2542 case B307200: pCh->speed = CBR_307200; break;
2543 case B460800: pCh->speed = CBR_460800; break;
2544 case B921600: pCh->speed = CBR_921600; break;
2545 default: pCh->speed = CBR_9600; break;
2546 }
2547 if ( pCh->speed == CBR_C1 ) {
2548 // Process the custom speed parameters.
2549 int bps = pCh->BaudBase / pCh->BaudDivisor;
2550 if ( bps == 921600 ) {
2551 pCh->speed = CBR_921600;
2552 } else {
2553 bps = bps/10;
2554 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
2555 }
2556 }
2557 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
2558
2559 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
2560 pCh->dataSetOut |= (I2_DTR | I2_RTS);
2561 }
2562 if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag))
2563 {
2564 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2565 CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
2566 }
2567 if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag))
2568 {
2569 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2570 CMD_SETPAR(
2571 (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
2572 )
2573 );
2574 }
2575 /* byte size and parity */
2576 if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag))
2577 {
2578 int datasize;
2579 switch ( cflag & CSIZE ) {
2580 case CS5: datasize = CSZ_5; break;
2581 case CS6: datasize = CSZ_6; break;
2582 case CS7: datasize = CSZ_7; break;
2583 case CS8: datasize = CSZ_8; break;
2584 default: datasize = CSZ_5; break; /* as per serial.c */
2585 }
2586 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
2587 }
2588 /* Process CTS flow control flag setting */
2589 if ( (cflag & CRTSCTS) ) {
2590 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2591 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
2592 } else {
2593 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2594 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
2595 }
2596 //
2597 // Process XON/XOFF flow control flags settings
2598 //
2599 stop_char = STOP_CHAR(pCh->pTTY);
2600 start_char = START_CHAR(pCh->pTTY);
2601
2602 //////////// can't be \000
2603 if (stop_char == __DISABLED_CHAR )
2604 {
2605 stop_char = ~__DISABLED_CHAR;
2606 }
2607 if (start_char == __DISABLED_CHAR )
2608 {
2609 start_char = ~__DISABLED_CHAR;
2610 }
2611 /////////////////////////////////
2612
2613 if ( o_tios->c_cc[VSTART] != start_char )
2614 {
2615 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
2616 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
2617 }
2618 if ( o_tios->c_cc[VSTOP] != stop_char )
2619 {
2620 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
2621 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
2622 }
2623 if (stop_char == __DISABLED_CHAR )
2624 {
2625 stop_char = ~__DISABLED_CHAR; //TEST123
2626 goto no_xoff;
2627 }
2628 if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF)))
2629 {
2630 if ( iflag & IXOFF ) { // Enable XOFF output flow control
2631 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
2632 } else { // Disable XOFF output flow control
2633no_xoff:
2634 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
2635 }
2636 }
2637 if (start_char == __DISABLED_CHAR )
2638 {
2639 goto no_xon;
2640 }
2641 if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY)))
2642 {
2643 if ( iflag & IXON ) {
2644 if ( iflag & IXANY ) { // Enable XON/XANY output flow control
2645 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
2646 } else { // Enable XON output flow control
2647 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
2648 }
2649 } else { // Disable XON output flow control
2650no_xon:
2651 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
2652 }
2653 }
2654 if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) )
2655 {
2656 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2657 CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
2658 }
2659 if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) )
2660 {
2661 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2662 CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
2663 }
2664
2665 if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR))
2666 ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) )
2667 {
2668 char brkrpt = 0;
2669 char parrpt = 0;
2670
2671 if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
2672 /* Ignore breaks altogether */
2673 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
2674 } else {
2675 if ( iflag & BRKINT ) {
2676 if ( iflag & PARMRK ) {
2677 brkrpt = 0x0a; // exception an inline triple
2678 } else {
2679 brkrpt = 0x1a; // exception and NULL
2680 }
2681 brkrpt |= 0x04; // flush input
2682 } else {
2683 if ( iflag & PARMRK ) {
2684 brkrpt = 0x0b; //POSIX triple \0377 \0 \0
2685 } else {
2686 brkrpt = 0x01; // Null only
2687 }
2688 }
2689 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
2690 }
2691
2692 if (iflag & IGNPAR) {
2693 parrpt = 0x20;
2694 /* would be 2 for not cirrus bug */
2695 /* would be 0x20 cept for cirrus bug */
2696 } else {
2697 if ( iflag & PARMRK ) {
2698 /*
2699 * Replace error characters with 3-byte sequence (\0377,\0,char)
2700 */
2701 parrpt = 0x04 ;
2702 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
2703 } else {
2704 parrpt = 0x03;
2705 }
2706 }
2707 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
2708 }
2709 if (cflag & CLOCAL) {
2710 // Status reporting fails for DCD if this is off
2711 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
2712 pCh->flags &= ~ASYNC_CHECK_CD;
2713 } else {
2714 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
2715 pCh->flags |= ASYNC_CHECK_CD;
2716 }
2717
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718service_it:
2719 i2DrainOutput( pCh, 100 );
2720}
2721
2722/******************************************************************************/
2723/* IPL Device Section */
2724/******************************************************************************/
2725
2726/******************************************************************************/
2727/* Function: ip2_ipl_read() */
2728/* Parameters: Pointer to device inode */
2729/* Pointer to file structure */
2730/* Pointer to data */
2731/* Number of bytes to read */
2732/* Returns: Success or failure */
2733/* */
2734/* Description: Ugly */
2735/* */
2736/* */
2737/******************************************************************************/
2738
2739static
2740ssize_t
2741ip2_ipl_read(struct file *pFile, char __user *pData, size_t count, loff_t *off )
2742{
Josef Sipeka7113a92006-12-08 02:36:55 -08002743 unsigned int minor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 int rc = 0;
2745
2746#ifdef IP2DEBUG_IPL
2747 printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
2748#endif
2749
2750 switch( minor ) {
2751 case 0: // IPL device
2752 rc = -EINVAL;
2753 break;
2754 case 1: // Status dump
2755 rc = -EINVAL;
2756 break;
2757 case 2: // Ping device
2758 rc = -EINVAL;
2759 break;
2760 case 3: // Trace device
2761 rc = DumpTraceBuffer ( pData, count );
2762 break;
2763 case 4: // Trace device
2764 rc = DumpFifoBuffer ( pData, count );
2765 break;
2766 default:
2767 rc = -ENODEV;
2768 break;
2769 }
2770 return rc;
2771}
2772
2773static int
2774DumpFifoBuffer ( char __user *pData, int count )
2775{
2776#ifdef DEBUG_FIFO
2777 int rc;
2778 rc = copy_to_user(pData, DBGBuf, count);
2779
2780 printk(KERN_DEBUG "Last index %d\n", I );
2781
2782 return count;
2783#endif /* DEBUG_FIFO */
2784 return 0;
2785}
2786
2787static int
2788DumpTraceBuffer ( char __user *pData, int count )
2789{
2790#ifdef IP2DEBUG_TRACE
2791 int rc;
2792 int dumpcount;
2793 int chunk;
2794 int *pIndex = (int __user *)pData;
2795
2796 if ( count < (sizeof(int) * 6) ) {
2797 return -EIO;
2798 }
2799 rc = put_user(tracewrap, pIndex );
2800 rc = put_user(TRACEMAX, ++pIndex );
2801 rc = put_user(tracestrip, ++pIndex );
2802 rc = put_user(tracestuff, ++pIndex );
2803 pData += sizeof(int) * 6;
2804 count -= sizeof(int) * 6;
2805
2806 dumpcount = tracestuff - tracestrip;
2807 if ( dumpcount < 0 ) {
2808 dumpcount += TRACEMAX;
2809 }
2810 if ( dumpcount > count ) {
2811 dumpcount = count;
2812 }
2813 chunk = TRACEMAX - tracestrip;
2814 if ( dumpcount > chunk ) {
2815 rc = copy_to_user(pData, &tracebuf[tracestrip],
2816 chunk * sizeof(tracebuf[0]) );
2817 pData += chunk * sizeof(tracebuf[0]);
2818 tracestrip = 0;
2819 chunk = dumpcount - chunk;
2820 } else {
2821 chunk = dumpcount;
2822 }
2823 rc = copy_to_user(pData, &tracebuf[tracestrip],
2824 chunk * sizeof(tracebuf[0]) );
2825 tracestrip += chunk;
2826 tracewrap = 0;
2827
2828 rc = put_user(tracestrip, ++pIndex );
2829 rc = put_user(tracestuff, ++pIndex );
2830
2831 return dumpcount;
2832#else
2833 return 0;
2834#endif
2835}
2836
2837/******************************************************************************/
2838/* Function: ip2_ipl_write() */
2839/* Parameters: */
2840/* Pointer to file structure */
2841/* Pointer to data */
2842/* Number of bytes to write */
2843/* Returns: Success or failure */
2844/* */
2845/* Description: */
2846/* */
2847/* */
2848/******************************************************************************/
2849static ssize_t
2850ip2_ipl_write(struct file *pFile, const char __user *pData, size_t count, loff_t *off)
2851{
2852#ifdef IP2DEBUG_IPL
2853 printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
2854#endif
2855 return 0;
2856}
2857
2858/******************************************************************************/
2859/* Function: ip2_ipl_ioctl() */
2860/* Parameters: Pointer to device inode */
2861/* Pointer to file structure */
2862/* Command */
2863/* Argument */
2864/* Returns: Success or failure */
2865/* */
2866/* Description: */
2867/* */
2868/* */
2869/******************************************************************************/
Alan Cox47be36a2008-07-25 01:48:13 -07002870static long
2871ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872{
Alan Cox47be36a2008-07-25 01:48:13 -07002873 unsigned int iplminor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 int rc = 0;
2875 void __user *argp = (void __user *)arg;
2876 ULONG __user *pIndex = argp;
2877 i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
2878 i2ChanStrPtr pCh;
2879
2880#ifdef IP2DEBUG_IPL
2881 printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
2882#endif
2883
Alan Cox47be36a2008-07-25 01:48:13 -07002884 lock_kernel();
2885
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 switch ( iplminor ) {
2887 case 0: // IPL device
2888 rc = -EINVAL;
2889 break;
2890 case 1: // Status dump
2891 case 5:
2892 case 9:
2893 case 13:
2894 switch ( cmd ) {
2895 case 64: /* Driver - ip2stat */
Alan Cox7d7b93c2008-10-13 10:42:09 +01002896 rc = put_user(-1, pIndex++ );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 rc = put_user(irq_counter, pIndex++ );
2898 rc = put_user(bh_counter, pIndex++ );
2899 break;
2900
2901 case 65: /* Board - ip2stat */
2902 if ( pB ) {
2903 rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002904 rc = put_user(inb(pB->i2eStatus),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 (ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
2906 } else {
2907 rc = -ENODEV;
2908 }
2909 break;
2910
2911 default:
2912 if (cmd < IP2_MAX_PORTS) {
2913 pCh = DevTable[cmd];
2914 if ( pCh )
2915 {
2916 rc = copy_to_user(argp, pCh, sizeof(i2ChanStr));
2917 } else {
2918 rc = -ENODEV;
2919 }
2920 } else {
2921 rc = -EINVAL;
2922 }
2923 }
2924 break;
2925
2926 case 2: // Ping device
2927 rc = -EINVAL;
2928 break;
2929 case 3: // Trace device
Andrew Mortondef93912006-02-03 03:04:47 -08002930 /*
2931 * akpm: This used to write a whole bunch of function addresses
2932 * to userspace, which generated lots of put_user() warnings.
2933 * I killed it all. Just return "success" and don't do
2934 * anything.
2935 */
2936 if (cmd == 1)
2937 rc = 0;
2938 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 break;
2941
2942 default:
2943 rc = -ENODEV;
2944 break;
2945 }
Alan Cox47be36a2008-07-25 01:48:13 -07002946 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 return rc;
2948}
2949
2950/******************************************************************************/
2951/* Function: ip2_ipl_open() */
2952/* Parameters: Pointer to device inode */
2953/* Pointer to file structure */
2954/* Returns: Success or failure */
2955/* */
2956/* Description: */
2957/* */
2958/* */
2959/******************************************************************************/
2960static int
2961ip2_ipl_open( struct inode *pInode, struct file *pFile )
2962{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963
2964#ifdef IP2DEBUG_IPL
2965 printk (KERN_DEBUG "IP2IPL: open\n" );
2966#endif
Jonathan Corbetf2b98572008-05-18 15:32:43 -06002967 cycle_kernel_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 return 0;
2969}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
2971static int
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002972proc_ip2mem_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973{
2974 i2eBordStrPtr pB;
2975 i2ChanStrPtr pCh;
2976 PTTY tty;
2977 int i;
2978
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
2980#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
2981#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
2982
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002983 seq_printf(m,"\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984
2985 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
2986 pB = i2BoardPtrTable[i];
2987 if ( pB ) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002988 seq_printf(m,"board %d:\n",i);
2989 seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
2991 }
2992 }
2993
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002994 seq_printf(m,"#: tty flags, port flags, cflags, iflags\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 for (i=0; i < IP2_MAX_PORTS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 pCh = DevTable[i];
2997 if (pCh) {
2998 tty = pCh->pTTY;
2999 if (tty && tty->count) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003000 seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 tty->termios->c_cflag,tty->termios->c_iflag);
3002
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003003 seq_printf(m,FMTLIN2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003005 seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 }
3007 }
3008 }
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003009 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010}
3011
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003012static int proc_ip2mem_open(struct inode *inode, struct file *file)
3013{
3014 return single_open(file, proc_ip2mem_show, NULL);
3015}
3016
3017static const struct file_operations ip2mem_proc_fops = {
3018 .owner = THIS_MODULE,
3019 .open = proc_ip2mem_open,
3020 .read = seq_read,
3021 .llseek = seq_lseek,
3022 .release = single_release,
3023};
3024
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025/*
3026 * This is the handler for /proc/tty/driver/ip2
3027 *
3028 * This stretch of code has been largely plagerized from at least three
3029 * different sources including ip2mkdev.c and a couple of other drivers.
3030 * The bugs are all mine. :-) =mhw=
3031 */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003032static int ip2_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033{
3034 int i, j, box;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 int boxes = 0;
3036 int ports = 0;
3037 int tports = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 i2eBordStrPtr pB;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003039 char *sep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003041 seq_printf(m, "ip2info: 1.0 driver: %s\n", pcVersion);
3042 seq_printf(m, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
3044 IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
3045
3046 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3047 /* This need to be reset for a board by board count... */
3048 boxes = 0;
3049 pB = i2BoardPtrTable[i];
3050 if( pB ) {
3051 switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED )
3052 {
3053 case POR_ID_FIIEX:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003054 seq_printf(m, "Board %d: EX ports=", i);
3055 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 for( box = 0; box < ABS_MAX_BOXES; ++box )
3057 {
3058 ports = 0;
3059
3060 if( pB->i2eChannelMap[box] != 0 ) ++boxes;
3061 for( j = 0; j < ABS_BIGGEST_BOX; ++j )
3062 {
3063 if( pB->i2eChannelMap[box] & 1<< j ) {
3064 ++ports;
3065 }
3066 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003067 seq_printf(m, "%s%d", sep, ports);
3068 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 tports += ports;
3070 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003071 seq_printf(m, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 break;
3073
3074 case POR_ID_II_4:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003075 seq_printf(m, "Board %d: ISA-4 ports=4 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 tports = ports = 4;
3077 break;
3078
3079 case POR_ID_II_8:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003080 seq_printf(m, "Board %d: ISA-8-std ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 tports = ports = 8;
3082 break;
3083
3084 case POR_ID_II_8R:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003085 seq_printf(m, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 tports = ports = 8;
3087 break;
3088
3089 default:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003090 seq_printf(m, "Board %d: unknown", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 /* Don't try and probe for minor numbers */
3092 tports = ports = 0;
3093 }
3094
3095 } else {
3096 /* Don't try and probe for minor numbers */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003097 seq_printf(m, "Board %d: vacant", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 tports = ports = 0;
3099 }
3100
3101 if( tports ) {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003102 seq_puts(m, " minors=");
3103 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 for ( box = 0; box < ABS_MAX_BOXES; ++box )
3105 {
3106 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
3107 {
3108 if ( pB->i2eChannelMap[box] & (1 << j) )
3109 {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003110 seq_printf(m, "%s%d", sep,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 j + ABS_BIGGEST_BOX *
3112 (box+i*ABS_MAX_BOXES));
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003113 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 }
3115 }
3116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003118 seq_putc(m, '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003120 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003122
3123static int ip2_proc_open(struct inode *inode, struct file *file)
3124{
3125 return single_open(file, ip2_proc_show, NULL);
3126}
3127
3128static const struct file_operations ip2_proc_fops = {
3129 .owner = THIS_MODULE,
3130 .open = ip2_proc_open,
3131 .read = seq_read,
3132 .llseek = seq_lseek,
3133 .release = single_release,
3134};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135
3136/******************************************************************************/
3137/* Function: ip2trace() */
3138/* Parameters: Value to add to trace buffer */
3139/* Returns: Nothing */
3140/* */
3141/* Description: */
3142/* */
3143/* */
3144/******************************************************************************/
3145#ifdef IP2DEBUG_TRACE
3146void
3147ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
3148{
3149 long flags;
3150 unsigned long *pCode = &codes;
3151 union ip2breadcrumb bc;
3152 i2ChanStrPtr pCh;
3153
3154
3155 tracebuf[tracestuff++] = jiffies;
3156 if ( tracestuff == TRACEMAX ) {
3157 tracestuff = 0;
3158 }
3159 if ( tracestuff == tracestrip ) {
3160 if ( ++tracestrip == TRACEMAX ) {
3161 tracestrip = 0;
3162 }
3163 ++tracewrap;
3164 }
3165
3166 bc.hdr.port = 0xff & pn;
3167 bc.hdr.cat = cat;
3168 bc.hdr.codes = (unsigned char)( codes & 0xff );
3169 bc.hdr.label = label;
3170 tracebuf[tracestuff++] = bc.value;
3171
3172 for (;;) {
3173 if ( tracestuff == TRACEMAX ) {
3174 tracestuff = 0;
3175 }
3176 if ( tracestuff == tracestrip ) {
3177 if ( ++tracestrip == TRACEMAX ) {
3178 tracestrip = 0;
3179 }
3180 ++tracewrap;
3181 }
3182
3183 if ( !codes-- )
3184 break;
3185
3186 tracebuf[tracestuff++] = *++pCode;
3187 }
3188}
3189#endif
3190
3191
3192MODULE_LICENSE("GPL");
Chuck Shorteb0e71c2006-07-10 04:43:59 -07003193
3194static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
3195 { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
3196 { }
3197};
3198
3199MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);