blob: 476cd087118e4d0339fd78467d640ecbd0701e5c [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>
Arnd Bergmann613655f2010-06-02 14:28:52 +0200101#include <linux/mutex.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
Arnd Bergmann613655f2010-06-02 14:28:52 +0200141static DEFINE_MUTEX(ip2_mutex);
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700142static const struct file_operations ip2mem_proc_fops;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700143static const struct file_operations ip2_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145/********************/
146/* Type Definitions */
147/********************/
148
149/*************/
150/* Constants */
151/*************/
152
153/* String constants to identify ourselves */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100154static const char pcName[] = "Computone IntelliPort Plus multiport driver";
155static const char pcVersion[] = "1.2.14";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157/* String constants for port names */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100158static const char pcDriver_name[] = "ip2";
159static const char pcIpl[] = "ip2ipl";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161/***********************/
162/* Function Prototypes */
163/***********************/
164
165/* Global module entry functions */
166
167/* Private (static) functions */
168static int ip2_open(PTTY, struct file *);
169static void ip2_close(PTTY, struct file *);
Alan Coxd9e39532006-01-09 20:54:20 -0800170static int ip2_write(PTTY, const unsigned char *, int);
Alan Coxf34d7a52008-04-30 00:54:13 -0700171static int ip2_putchar(PTTY, unsigned char);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static void ip2_flush_chars(PTTY);
173static int ip2_write_room(PTTY);
174static int ip2_chars_in_buf(PTTY);
175static void ip2_flush_buffer(PTTY);
176static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);
Alan Cox606d0992006-12-08 02:38:45 -0800177static void ip2_set_termios(PTTY, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178static void ip2_set_line_discipline(PTTY);
179static void ip2_throttle(PTTY);
180static void ip2_unthrottle(PTTY);
181static void ip2_stop(PTTY);
182static void ip2_start(PTTY);
183static void ip2_hangup(PTTY);
Alan Cox60b33c12011-02-14 16:26:14 +0000184static int ip2_tiocmget(struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
186 unsigned int set, unsigned int clear);
Alan Cox05871022010-09-16 18:21:52 +0100187static int ip2_get_icount(struct tty_struct *tty,
188 struct serial_icounter_struct *icount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190static void set_irq(int, int);
David Howellsc4028952006-11-22 14:57:56 +0000191static void ip2_interrupt_bh(struct work_struct *work);
David Howells7d12e782006-10-05 14:55:46 +0100192static irqreturn_t ip2_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193static void ip2_poll(unsigned long arg);
194static inline void service_all_boards(void);
David Howellsc4028952006-11-22 14:57:56 +0000195static void do_input(struct work_struct *);
196static void do_status(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198static void ip2_wait_until_sent(PTTY,int);
199
Alan Cox606d0992006-12-08 02:38:45 -0800200static void set_params (i2ChanStrPtr, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *);
202static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *);
203
204static ssize_t ip2_ipl_read(struct file *, char __user *, size_t, loff_t *);
205static ssize_t ip2_ipl_write(struct file *, const char __user *, size_t, loff_t *);
Alan Cox47be36a2008-07-25 01:48:13 -0700206static long ip2_ipl_ioctl(struct file *, UINT, ULONG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207static int ip2_ipl_open(struct inode *, struct file *);
208
209static int DumpTraceBuffer(char __user *, int);
210static int DumpFifoBuffer( char __user *, int);
211
David Woodhouse547d8bb2008-06-11 16:57:21 +0100212static void ip2_init_board(int, const struct firmware *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213static unsigned short find_eisa_board(int);
Rakib Mullick02c95a62010-01-23 18:53:51 +0600214static int ip2_setup(char *str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216/***************/
217/* Static Data */
218/***************/
219
220static struct tty_driver *ip2_tty_driver;
221
222/* Here, then is a table of board pointers which the interrupt routine should
223 * scan through to determine who it must service.
224 */
225static unsigned short i2nBoards; // Number of boards here
226
227static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS];
228
229static i2ChanStrPtr DevTable[IP2_MAX_PORTS];
230//DevTableMem just used to save addresses for kfree
231static void *DevTableMem[IP2_MAX_BOARDS];
232
233/* This is the driver descriptor for the ip2ipl device, which is used to
234 * download the loadware to the boards.
235 */
Arjan van de Ven62322d22006-07-03 00:24:21 -0700236static const struct file_operations ip2_ipl = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 .owner = THIS_MODULE,
238 .read = ip2_ipl_read,
239 .write = ip2_ipl_write,
Alan Cox47be36a2008-07-25 01:48:13 -0700240 .unlocked_ioctl = ip2_ipl_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 .open = ip2_ipl_open,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200242 .llseek = noop_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243};
244
Jiri Slabycf176bc2008-10-13 10:34:36 +0100245static unsigned long irq_counter;
246static unsigned long bh_counter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248// Use immediate queue to service interrupts
249#define USE_IQI
250//#define USE_IQ // PCI&2.2 needs work
251
252/* The timer_list entry for our poll routine. If interrupt operation is not
253 * selected, the board is serviced periodically to see if anything needs doing.
254 */
255#define POLL_TIMEOUT (jiffies + 1)
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700256static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258#ifdef IP2DEBUG_TRACE
259/* Trace (debug) buffer data */
260#define TRACEMAX 1000
261static unsigned long tracebuf[TRACEMAX];
262static int tracestuff;
263static int tracestrip;
264static int tracewrap;
265#endif
266
267/**********/
268/* Macros */
269/**********/
270
Rakib Mullick795877c2009-12-09 12:34:18 -0800271#ifdef IP2DEBUG_OPEN
Alan Cox7d7b93c2008-10-13 10:42:09 +0100272#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
273 tty->name,(pCh->flags), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 tty->count,/*GET_USE_COUNT(module)*/0,s)
275#else
276#define DBG_CNT(s)
277#endif
278
279/********/
280/* Code */
281/********/
282
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100283#include "i2ellis.c" /* Extremely low-level interface services */
284#include "i2cmd.c" /* Standard loadware command definitions */
285#include "i2lib.c" /* High level interface services */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287/* Configuration area for modprobe */
288
289MODULE_AUTHOR("Doug McNash");
290MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
Jiri Slaby47babd42008-10-13 10:34:27 +0100291MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Rakib Mullick02c95a62010-01-23 18:53:51 +0600293#define MAX_CMD_STR 50
294
Jiri Slabycf176bc2008-10-13 10:34:36 +0100295static int poll_only;
Rakib Mullick02c95a62010-01-23 18:53:51 +0600296static char cmd[MAX_CMD_STR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298static int Eisa_irq;
299static int Eisa_slot;
300
301static int iindx;
302static char rirqs[IP2_MAX_BOARDS];
303static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
304
Jiri Slaby47babd42008-10-13 10:34:27 +0100305/* Note: Add compiled in defaults to these arrays, not to the structure
306 in ip2.h any longer. That structure WILL get overridden
307 by these values, or command line values, or insmod values!!! =mhw=
308*/
309static int io[IP2_MAX_BOARDS];
310static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
311
312MODULE_AUTHOR("Doug McNash");
313MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
314module_param_array(irq, int, NULL, 0);
315MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
316module_param_array(io, int, NULL, 0);
317MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
318module_param(poll_only, bool, 0);
319MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
Rakib Mullick02c95a62010-01-23 18:53:51 +0600320module_param_string(ip2, cmd, MAX_CMD_STR, 0);
321MODULE_PARM_DESC(ip2, "Contains module parameter passed with 'ip2='");
Jiri Slaby47babd42008-10-13 10:34:27 +0100322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323/* for sysfs class support */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800324static struct class *ip2_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100326/* Some functions to keep track of what irqs we have */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100328static int __init is_valid_irq(int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 int *i = Valid_Irqs;
331
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100332 while (*i != 0 && *i != irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 i++;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100334
335 return *i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100338static void __init mark_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
340 rirqs[iindx++] = irq;
341}
342
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100343static int __exit clear_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
345 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100346 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 if (rirqs[i] == irq) {
348 rirqs[i] = 0;
349 return 1;
350 }
351 }
352 return 0;
353}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100355static int have_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100357 /* array init to zeros so 0 irq will not be requested as a side
358 * effect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100360 for (i = 0; i < IP2_MAX_BOARDS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 if (rirqs[i] == irq)
362 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 return 0;
364}
365
366/******************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367/* Function: cleanup_module() */
368/* Parameters: None */
369/* Returns: Nothing */
370/* */
371/* Description: */
372/* This is a required entry point for an installable module. It has to return */
373/* the device and the driver to a passive state. It should not be necessary */
374/* to reset the board fully, especially as the loadware is downloaded */
375/* externally rather than in the driver. We just want to disable the board */
376/* and clear the loadware to a reset state. To allow this there has to be a */
377/* way to detect whether the board has the loadware running at init time to */
378/* handle subsequent installations of the driver. All memory allocated by the */
379/* driver should be returned since it may be unloaded from memory. */
380/******************************************************************************/
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100381static void __exit ip2_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
383 int err;
384 int i;
385
Akinobu Mita9d020a22008-10-13 10:35:05 +0100386 del_timer_sync(&PollTimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 /* Reset the boards we have. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100389 for (i = 0; i < IP2_MAX_BOARDS; i++)
390 if (i2BoardPtrTable[i])
391 iiReset(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 /* The following is done at most once, if any boards were installed. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100394 for (i = 0; i < IP2_MAX_BOARDS; i++) {
395 if (i2BoardPtrTable[i]) {
396 iiResetDelay(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 /* free io addresses and Tibet */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100398 release_region(ip2config.addr[i], 8);
tonyj@suse.de07c015e2007-08-07 22:28:44 -0700399 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100400 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
401 4 * i + 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 }
403 /* Disable and remove interrupt handler. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100404 if (ip2config.irq[i] > 0 &&
405 have_requested_irq(ip2config.irq[i])) {
406 free_irq(ip2config.irq[i], (void *)&pcName);
407 clear_requested_irq(ip2config.irq[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 }
409 }
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800410 class_destroy(ip2_class);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100411 err = tty_unregister_driver(ip2_tty_driver);
412 if (err)
413 printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
414 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 put_tty_driver(ip2_tty_driver);
Akinobu Mita68fc4fa2007-07-19 01:47:50 -0700416 unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
Alexey Dobriyanc74c1202008-04-29 01:01:44 -0700417 remove_proc_entry("ip2mem", NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100419 /* free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 for (i = 0; i < IP2_MAX_BOARDS; i++) {
421 void *pB;
422#ifdef CONFIG_PCI
423 if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
424 pci_disable_device(ip2config.pci_dev[i]);
Alan Cox1aff0ec2006-09-30 23:27:59 -0700425 pci_dev_put(ip2config.pci_dev[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 ip2config.pci_dev[i] = NULL;
427 }
428#endif
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100429 pB = i2BoardPtrTable[i];
430 if (pB != NULL) {
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100431 kfree(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 i2BoardPtrTable[i] = NULL;
433 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100434 if (DevTableMem[i] != NULL) {
435 kfree(DevTableMem[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 DevTableMem[i] = NULL;
437 }
438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439}
Jon Schindler83e422b2008-04-30 00:53:53 -0700440module_exit(ip2_cleanup_module);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700442static const struct tty_operations ip2_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 .open = ip2_open,
444 .close = ip2_close,
445 .write = ip2_write,
446 .put_char = ip2_putchar,
447 .flush_chars = ip2_flush_chars,
448 .write_room = ip2_write_room,
449 .chars_in_buffer = ip2_chars_in_buf,
450 .flush_buffer = ip2_flush_buffer,
451 .ioctl = ip2_ioctl,
452 .throttle = ip2_throttle,
453 .unthrottle = ip2_unthrottle,
454 .set_termios = ip2_set_termios,
455 .set_ldisc = ip2_set_line_discipline,
456 .stop = ip2_stop,
457 .start = ip2_start,
458 .hangup = ip2_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 .tiocmget = ip2_tiocmget,
460 .tiocmset = ip2_tiocmset,
Alan Cox05871022010-09-16 18:21:52 +0100461 .get_icount = ip2_get_icount,
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700462 .proc_fops = &ip2_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463};
464
465/******************************************************************************/
466/* Function: ip2_loadmain() */
467/* Parameters: irq, io from command line of insmod et. al. */
468/* pointer to fip firmware and firmware size for boards */
469/* Returns: Success (0) */
470/* */
471/* Description: */
472/* This was the required entry point for all drivers (now in ip2.c) */
473/* It performs all */
474/* initialisation of the devices and driver structures, and registers itself */
475/* with the relevant kernel modules. */
476/******************************************************************************/
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700477/* IRQF_DISABLED - if set blocks all interrupts else only this line */
478/* IRQF_SHARED - for shared irq PCI or maybe EISA only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479/* SA_RANDOM - can be source for cert. random number generators */
480#define IP2_SA_FLAGS 0
481
David Woodhouse547d8bb2008-06-11 16:57:21 +0100482
483static const struct firmware *ip2_request_firmware(void)
484{
485 struct platform_device *pdev;
486 const struct firmware *fw;
487
488 pdev = platform_device_register_simple("ip2", 0, NULL, 0);
489 if (IS_ERR(pdev)) {
490 printk(KERN_ERR "Failed to register platform device for ip2\n");
491 return NULL;
492 }
493 if (request_firmware(&fw, "intelliport2.bin", &pdev->dev)) {
494 printk(KERN_ERR "Failed to load firmware 'intelliport2.bin'\n");
495 fw = NULL;
496 }
497 platform_device_unregister(pdev);
498 return fw;
499}
500
Jiri Slaby47babd42008-10-13 10:34:27 +0100501/******************************************************************************
502 * ip2_setup:
503 * str: kernel command line string
504 *
505 * Can't autoprobe the boards so user must specify configuration on
506 * kernel command line. Sane people build it modular but the others
507 * come here.
508 *
509 * Alternating pairs of io,irq for up to 4 boards.
510 * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
511 *
512 * io=0 => No board
513 * io=1 => PCI
514 * io=2 => EISA
515 * else => ISA I/O address
516 *
517 * irq=0 or invalid for ISA will revert to polling mode
518 *
519 * Any value = -1, do not overwrite compiled in value.
520 *
521 ******************************************************************************/
522static int __init ip2_setup(char *str)
523{
524 int j, ints[10]; /* 4 boards, 2 parameters + 2 */
525 unsigned int i;
526
527 str = get_options(str, ARRAY_SIZE(ints), ints);
528
529 for (i = 0, j = 1; i < 4; i++) {
530 if (j > ints[0])
531 break;
532 if (ints[j] >= 0)
533 io[i] = ints[j];
534 j++;
535 if (j > ints[0])
536 break;
537 if (ints[j] >= 0)
538 irq[i] = ints[j];
539 j++;
540 }
541 return 1;
542}
543__setup("ip2=", ip2_setup);
Jiri Slaby47babd42008-10-13 10:34:27 +0100544
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100545static int __init ip2_loadmain(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 int i, j, box;
548 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 i2eBordStrPtr pB = NULL;
550 int rc = -1;
David Woodhouse547d8bb2008-06-11 16:57:21 +0100551 const struct firmware *fw = NULL;
Rakib Mullick02c95a62010-01-23 18:53:51 +0600552 char *str;
553
554 str = cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Jiri Slaby47babd42008-10-13 10:34:27 +0100556 if (poll_only) {
557 /* Hard lock the interrupts to zero */
558 irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
559 }
560
Rakib Mullick02c95a62010-01-23 18:53:51 +0600561 /* Check module parameter with 'ip2=' has been passed or not */
562 if (!poll_only && (!strncmp(str, "ip2=", 4)))
563 ip2_setup(str);
564
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100565 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567 /* process command line arguments to modprobe or
568 insmod i.e. iop & irqp */
569 /* irqp and iop should ALWAYS be specified now... But we check
570 them individually just to be sure, anyways... */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100571 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Jiri Slaby47babd42008-10-13 10:34:27 +0100572 ip2config.addr[i] = io[i];
573 if (irq[i] >= 0)
574 ip2config.irq[i] = irq[i];
575 else
576 ip2config.irq[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100577 /* This is a little bit of a hack. If poll_only=1 on command
578 line back in ip2.c OR all IRQs on all specified boards are
579 explicitly set to 0, then drop to poll only mode and override
580 PCI or EISA interrupts. This superceeds the old hack of
581 triggering if all interrupts were zero (like da default).
582 Still a hack but less prone to random acts of terrorism.
583
584 What we really should do, now that the IRQ default is set
585 to -1, is to use 0 as a hard coded, do not probe.
586
587 /\/\|=mhw=|\/\/
588 */
Jiri Slaby47babd42008-10-13 10:34:27 +0100589 poll_only |= irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
591 poll_only = !poll_only;
592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 /* Announce our presence */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100594 printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
597 if (!ip2_tty_driver)
598 return -ENOMEM;
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 /* Initialise all the boards we can find (up to the maximum). */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100601 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
602 switch (ip2config.addr[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 case 0: /* skip this slot even if card is present */
604 break;
605 default: /* ISA */
606 /* ISA address must be specified */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100607 if (ip2config.addr[i] < 0x100 ||
608 ip2config.addr[i] > 0x3f8) {
609 printk(KERN_ERR "IP2: Bad ISA board %d "
610 "address %x\n", i,
611 ip2config.addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 ip2config.addr[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100613 break;
614 }
615 ip2config.type[i] = ISA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100617 /* Check for valid irq argument, set for polling if
618 * invalid */
619 if (ip2config.irq[i] &&
620 !is_valid_irq(ip2config.irq[i])) {
621 printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
622 ip2config.irq[i]);
623 /* 0 is polling and is valid in that sense */
624 ip2config.irq[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 }
626 break;
627 case PCI:
628#ifdef CONFIG_PCI
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100629 {
Rakib Mullick795877c2009-12-09 12:34:18 -0800630 struct pci_dev *pdev = NULL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100631 u32 addr;
632 int status;
Andrew Mortonad4a5bb2007-07-31 00:39:41 -0700633
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100634 pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
635 PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
636 if (pdev == NULL) {
637 ip2config.addr[i] = 0;
638 printk(KERN_ERR "IP2: PCI board %d not "
639 "found\n", i);
640 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100642
643 if (pci_enable_device(pdev)) {
644 dev_err(&pdev->dev, "can't enable device\n");
Rakib Mullick795877c2009-12-09 12:34:18 -0800645 goto out;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100646 }
647 ip2config.type[i] = PCI;
648 ip2config.pci_dev[i] = pci_dev_get(pdev);
649 status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
650 &addr);
651 if (addr & 1)
652 ip2config.addr[i] = (USHORT)(addr & 0xfffe);
653 else
654 dev_err(&pdev->dev, "I/O address error\n");
655
656 ip2config.irq[i] = pdev->irq;
Rakib Mullick795877c2009-12-09 12:34:18 -0800657out:
658 pci_dev_put(pdev);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660#else
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100661 printk(KERN_ERR "IP2: PCI card specified but PCI "
662 "support not enabled.\n");
663 printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
664 "defined!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665#endif /* CONFIG_PCI */
666 break;
667 case EISA:
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100668 ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
669 if (ip2config.addr[i] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 /* Eisa_irq set as side effect, boo */
671 ip2config.type[i] = EISA;
672 }
673 ip2config.irq[i] = Eisa_irq;
674 break;
675 } /* switch */
676 } /* for */
Alan Cox1aff0ec2006-09-30 23:27:59 -0700677
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100678 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
679 if (ip2config.addr[i]) {
Mariusz Kozlowski978550b2007-10-16 23:26:45 -0700680 pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
681 if (pB) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 i2BoardPtrTable[i] = pB;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100683 iiSetAddress(pB, ip2config.addr[i],
684 ii2DelayTimer);
685 iiReset(pB);
686 } else
687 printk(KERN_ERR "IP2: board memory allocation "
688 "error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
690 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100691 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
692 pB = i2BoardPtrTable[i];
693 if (pB != NULL) {
694 iiResetDelay(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 break;
696 }
697 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100698 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100699 /* We don't want to request the firmware unless we have at
700 least one board */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100701 if (i2BoardPtrTable[i] != NULL) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100702 if (!fw)
703 fw = ip2_request_firmware();
704 if (!fw)
705 break;
706 ip2_init_board(i, fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 }
708 }
David Woodhouse547d8bb2008-06-11 16:57:21 +0100709 if (fw)
710 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100712 ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
714 ip2_tty_driver->owner = THIS_MODULE;
715 ip2_tty_driver->name = "ttyF";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 ip2_tty_driver->driver_name = pcDriver_name;
717 ip2_tty_driver->major = IP2_TTY_MAJOR;
718 ip2_tty_driver->minor_start = 0;
719 ip2_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
720 ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL;
721 ip2_tty_driver->init_termios = tty_std_termios;
722 ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100723 ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW |
724 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 tty_set_operations(ip2_tty_driver, &ip2_ops);
726
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100727 ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100729 err = tty_register_driver(ip2_tty_driver);
730 if (err) {
731 printk(KERN_ERR "IP2: failed to register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 put_tty_driver(ip2_tty_driver);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100733 return err; /* leaking resources */
734 }
735
736 err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
737 if (err) {
738 printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
739 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 } else {
741 /* create the sysfs class */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800742 ip2_class = class_create(THIS_MODULE, "ip2");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (IS_ERR(ip2_class)) {
744 err = PTR_ERR(ip2_class);
745 goto out_chrdev;
746 }
747 }
748 /* Register the read_procmem thing */
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700749 if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 printk(KERN_ERR "IP2: failed to register read_procmem\n");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100751 return -EIO; /* leaking resources */
752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100754 ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
755 /* Register the interrupt handler or poll handler, depending upon the
756 * specified interrupt.
757 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100759 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
760 if (ip2config.addr[i] == 0)
761 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100763 pB = i2BoardPtrTable[i];
764 if (pB != NULL) {
Greg Kroah-Hartman03457cd2008-07-21 20:03:34 -0700765 device_create(ip2_class, NULL,
766 MKDEV(IP2_IPL_MAJOR, 4 * i),
767 NULL, "ipl%d", i);
768 device_create(ip2_class, NULL,
769 MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
770 NULL, "stat%d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100772 for (box = 0; box < ABS_MAX_BOXES; box++)
773 for (j = 0; j < ABS_BIGGEST_BOX; j++)
774 if (pB->i2eChannelMap[box] & (1 << j))
775 tty_register_device(
776 ip2_tty_driver,
777 j + ABS_BIGGEST_BOX *
778 (box+i*ABS_MAX_BOXES),
779 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100781
782 if (poll_only) {
783 /* Poll only forces driver to only use polling and
784 to ignore the probed PCI or EISA interrupts. */
785 ip2config.irq[i] = CIR_POLL;
786 }
787 if (ip2config.irq[i] == CIR_POLL) {
788retry:
Akinobu Mita9d020a22008-10-13 10:35:05 +0100789 if (!timer_pending(&PollTimer)) {
790 mod_timer(&PollTimer, POLL_TIMEOUT);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100791 printk(KERN_INFO "IP2: polling\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100793 } else {
794 if (have_requested_irq(ip2config.irq[i]))
795 continue;
796 rc = request_irq(ip2config.irq[i], ip2_interrupt,
797 IP2_SA_FLAGS |
798 (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
799 pcName, i2BoardPtrTable[i]);
800 if (rc) {
801 printk(KERN_ERR "IP2: request_irq failed: "
802 "error %d\n", rc);
803 ip2config.irq[i] = CIR_POLL;
804 printk(KERN_INFO "IP2: Polling %ld/sec.\n",
805 (POLL_TIMEOUT - jiffies));
806 goto retry;
807 }
808 mark_requested_irq(ip2config.irq[i]);
809 /* Initialise the interrupt handler bottom half
810 * (aka slih). */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 }
812 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100813
814 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
815 if (i2BoardPtrTable[i]) {
816 /* set and enable board interrupt */
817 set_irq(i, ip2config.irq[i]);
818 }
819 }
820
821 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
822
823 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825out_chrdev:
826 unregister_chrdev(IP2_IPL_MAJOR, "ip2");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100827 /* unregister and put tty here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 return err;
829}
Jiri Slaby47babd42008-10-13 10:34:27 +0100830module_init(ip2_loadmain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832/******************************************************************************/
833/* Function: ip2_init_board() */
834/* Parameters: Index of board in configuration structure */
835/* Returns: Success (0) */
836/* */
837/* Description: */
838/* This function initializes the specified board. The loadware is copied to */
839/* the board, the channel structures are initialized, and the board details */
840/* are reported on the console. */
841/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700842static void
David Woodhouse547d8bb2008-06-11 16:57:21 +0100843ip2_init_board(int boardnum, const struct firmware *fw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844{
845 int i;
846 int nports = 0, nboxes = 0;
847 i2ChanStrPtr pCh;
848 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
849
850 if ( !iiInitialize ( pB ) ) {
851 printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
852 pB->i2eBase, pB->i2eError );
853 goto err_initialize;
854 }
855 printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
856 ip2config.addr[boardnum], ip2config.irq[boardnum] );
857
858 if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
859 printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
860 goto err_initialize;
861 }
862
David Woodhouse547d8bb2008-06-11 16:57:21 +0100863 if ( iiDownloadAll ( pB, (loadHdrStrPtr)fw->data, 1, fw->size )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 != II_DOWN_GOOD ) {
865 printk ( KERN_ERR "IP2: failed to download loadware\n" );
866 goto err_release_region;
867 } else {
868 printk ( KERN_INFO "IP2: fv=%d.%d.%d lv=%d.%d.%d\n",
869 pB->i2ePom.e.porVersion,
870 pB->i2ePom.e.porRevision,
871 pB->i2ePom.e.porSubRev, pB->i2eLVersion,
872 pB->i2eLRevision, pB->i2eLSub );
873 }
874
875 switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
876
877 default:
878 printk( KERN_ERR "IP2: Unknown board type, ID = %x\n",
879 pB->i2ePom.e.porID );
880 nports = 0;
881 goto err_release_region;
882 break;
883
884 case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
885 printk ( KERN_INFO "IP2: ISA-4\n" );
886 nports = 4;
887 break;
888
889 case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
890 printk ( KERN_INFO "IP2: ISA-8 std\n" );
891 nports = 8;
892 break;
893
894 case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
895 printk ( KERN_INFO "IP2: ISA-8 RJ11\n" );
896 nports = 8;
897 break;
898
899 case POR_ID_FIIEX: /* IntelliPort IIEX */
900 {
901 int portnum = IP2_PORTS_PER_BOARD * boardnum;
902 int box;
903
904 for( box = 0; box < ABS_MAX_BOXES; ++box ) {
905 if ( pB->i2eChannelMap[box] != 0 ) {
906 ++nboxes;
907 }
908 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
909 if ( pB->i2eChannelMap[box] & 1<< i ) {
910 ++nports;
911 }
912 }
913 }
914 DevTableMem[boardnum] = pCh =
915 kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
916 if ( !pCh ) {
917 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
918 goto err_release_region;
919 }
920 if ( !i2InitChannels( pB, nports, pCh ) ) {
921 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
922 kfree ( pCh );
923 goto err_release_region;
924 }
925 pB->i2eChannelPtr = &DevTable[portnum];
926 pB->i2eChannelCnt = ABS_MOST_PORTS;
927
928 for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
929 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
930 if ( pB->i2eChannelMap[box] & (1 << i) ) {
931 DevTable[portnum + i] = pCh;
932 pCh->port_index = portnum + i;
933 pCh++;
934 }
935 }
936 }
937 printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit\n",
938 nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
939 }
940 goto ex_exit;
941 }
942 DevTableMem[boardnum] = pCh =
943 kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
944 if ( !pCh ) {
945 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
946 goto err_release_region;
947 }
948 pB->i2eChannelPtr = pCh;
949 pB->i2eChannelCnt = nports;
950 if ( !i2InitChannels( pB, nports, pCh ) ) {
951 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
952 kfree ( pCh );
953 goto err_release_region;
954 }
955 pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
956
957 for( i = 0; i < pB->i2eChannelCnt; ++i ) {
958 DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
959 pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
960 pCh++;
961 }
962ex_exit:
David Howellsc4028952006-11-22 14:57:56 +0000963 INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return;
965
966err_release_region:
967 release_region(ip2config.addr[boardnum], 8);
968err_initialize:
969 kfree ( pB );
970 i2BoardPtrTable[boardnum] = NULL;
971 return;
972}
973
974/******************************************************************************/
975/* Function: find_eisa_board ( int start_slot ) */
976/* Parameters: First slot to check */
977/* Returns: Address of EISA IntelliPort II controller */
978/* */
979/* Description: */
980/* This function searches for an EISA IntelliPort controller, starting */
981/* from the specified slot number. If the motherboard is not identified as an */
982/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
983/* it returns the base address of the controller. */
984/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700985static unsigned short
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986find_eisa_board( int start_slot )
987{
988 int i, j;
989 unsigned int idm = 0;
990 unsigned int idp = 0;
991 unsigned int base = 0;
992 unsigned int value;
993 int setup_address;
994 int setup_irq;
995 int ismine = 0;
996
997 /*
998 * First a check for an EISA motherboard, which we do by comparing the
999 * EISA ID registers for the system board and the first couple of slots.
1000 * No slot ID should match the system board ID, but on an ISA or PCI
1001 * machine the odds are that an empty bus will return similar values for
1002 * each slot.
1003 */
1004 i = 0x0c80;
1005 value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
1006 for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
1007 j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
1008 if ( value == j )
1009 return 0;
1010 }
1011
1012 /*
1013 * OK, so we are inclined to believe that this is an EISA machine. Find
1014 * an IntelliPort controller.
1015 */
1016 for( i = start_slot; i < 16; i++ ) {
1017 base = i << 12;
1018 idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
1019 idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
1020 ismine = 0;
1021 if ( idm == 0x0e8e ) {
1022 if ( idp == 0x0281 || idp == 0x0218 ) {
1023 ismine = 1;
1024 } else if ( idp == 0x0282 || idp == 0x0283 ) {
1025 ismine = 3; /* Can do edge-trigger */
1026 }
1027 if ( ismine ) {
1028 Eisa_slot = i;
1029 break;
1030 }
1031 }
1032 }
1033 if ( !ismine )
1034 return 0;
1035
1036 /* It's some sort of EISA card, but at what address is it configured? */
1037
1038 setup_address = base + 0xc88;
1039 value = inb(base + 0xc86);
1040 setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
1041
1042 if ( (ismine & 2) && !(value & 0x10) ) {
1043 ismine = 1; /* Could be edging, but not */
1044 }
1045
1046 if ( Eisa_irq == 0 ) {
1047 Eisa_irq = setup_irq;
1048 } else if ( Eisa_irq != setup_irq ) {
1049 printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
1050 }
1051
1052#ifdef IP2DEBUG_INIT
1053printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
1054 base >> 12, idm, idp, setup_address);
1055 if ( Eisa_irq ) {
1056 printk(KERN_DEBUG ", Interrupt %d %s\n",
1057 setup_irq, (ismine & 2) ? "(edge)" : "(level)");
1058 } else {
1059 printk(KERN_DEBUG ", (polled)\n");
1060 }
1061#endif
1062 return setup_address;
1063}
1064
1065/******************************************************************************/
1066/* Function: set_irq() */
1067/* Parameters: index to board in board table */
1068/* IRQ to use */
1069/* Returns: Success (0) */
1070/* */
1071/* Description: */
1072/******************************************************************************/
1073static void
1074set_irq( int boardnum, int boardIrq )
1075{
1076 unsigned char tempCommand[16];
1077 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
1078 unsigned long flags;
1079
1080 /*
1081 * Notify the boards they may generate interrupts. This is done by
1082 * sending an in-line command to channel 0 on each board. This is why
1083 * the channels have to be defined already. For each board, if the
1084 * interrupt has never been defined, we must do so NOW, directly, since
1085 * board will not send flow control or even give an interrupt until this
1086 * is done. If polling we must send 0 as the interrupt parameter.
1087 */
1088
1089 // We will get an interrupt here at the end of this function
1090
1091 iiDisableMailIrq(pB);
1092
1093 /* We build up the entire packet header. */
1094 CHANNEL_OF(tempCommand) = 0;
1095 PTYPE_OF(tempCommand) = PTYPE_INLINE;
1096 CMD_COUNT_OF(tempCommand) = 2;
1097 (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
1098 (CMD_OF(tempCommand))[1] = boardIrq;
1099 /*
1100 * Write to FIFO; don't bother to adjust fifo capacity for this, since
1101 * board will respond almost immediately after SendMail hit.
1102 */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001103 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001105 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 pB->i2eUsingIrq = boardIrq;
1107 pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
1108
1109 /* Need to update number of boards before you enable mailbox int */
1110 ++i2nBoards;
1111
1112 CHANNEL_OF(tempCommand) = 0;
1113 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1114 CMD_COUNT_OF(tempCommand) = 6;
1115 (CMD_OF(tempCommand))[0] = 88; // SILO
1116 (CMD_OF(tempCommand))[1] = 64; // chars
1117 (CMD_OF(tempCommand))[2] = 32; // ms
1118
1119 (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK
1120 (CMD_OF(tempCommand))[4] = 64; // chars
1121
1122 (CMD_OF(tempCommand))[5] = 87; // HW_TEST
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, 8);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001125 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
1127 CHANNEL_OF(tempCommand) = 0;
1128 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1129 CMD_COUNT_OF(tempCommand) = 1;
1130 (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */
1131 iiWriteBuf(pB, tempCommand, 3);
1132
1133#ifdef XXX
1134 // enable heartbeat for test porpoises
1135 CHANNEL_OF(tempCommand) = 0;
1136 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1137 CMD_COUNT_OF(tempCommand) = 2;
1138 (CMD_OF(tempCommand))[0] = 44; /* get ping */
1139 (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001140 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001142 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143#endif
1144
1145 iiEnableMailIrq(pB);
1146 iiSendPendingMail(pB);
1147}
1148
1149/******************************************************************************/
1150/* Interrupt Handler Section */
1151/******************************************************************************/
1152
1153static inline void
1154service_all_boards(void)
1155{
1156 int i;
1157 i2eBordStrPtr pB;
1158
1159 /* Service every board on the list */
1160 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
1161 pB = i2BoardPtrTable[i];
1162 if ( pB ) {
1163 i2ServiceBoard( pB );
1164 }
1165 }
1166}
1167
1168
1169/******************************************************************************/
David Howellsc4028952006-11-22 14:57:56 +00001170/* Function: ip2_interrupt_bh(work) */
1171/* Parameters: work - pointer to the board structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172/* Returns: Nothing */
1173/* */
1174/* Description: */
1175/* Service the board in a bottom half interrupt handler and then */
1176/* reenable the board's interrupts if it has an IRQ number */
1177/* */
1178/******************************************************************************/
1179static void
David Howellsc4028952006-11-22 14:57:56 +00001180ip2_interrupt_bh(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181{
David Howellsc4028952006-11-22 14:57:56 +00001182 i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183// pB better well be set or we have a problem! We can only get
1184// here from the IMMEDIATE queue. Here, we process the boards.
1185// Checking pB doesn't cost much and it saves us from the sanity checkers.
1186
1187 bh_counter++;
1188
1189 if ( pB ) {
1190 i2ServiceBoard( pB );
1191 if( pB->i2eUsingIrq ) {
1192// Re-enable his interrupts
1193 iiEnableMailIrq(pB);
1194 }
1195 }
1196}
1197
1198
1199/******************************************************************************/
David Howells7d12e782006-10-05 14:55:46 +01001200/* Function: ip2_interrupt(int irq, void *dev_id) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201/* Parameters: irq - interrupt number */
1202/* pointer to optional device ID structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203/* Returns: Nothing */
1204/* */
1205/* Description: */
1206/* */
1207/* Our task here is simply to identify each board which needs servicing. */
1208/* If we are queuing then, queue it to be serviced, and disable its irq */
1209/* mask otherwise process the board directly. */
1210/* */
1211/* We could queue by IRQ but that just complicates things on both ends */
1212/* with very little gain in performance (how many instructions does */
1213/* it take to iterate on the immediate queue). */
1214/* */
1215/* */
1216/******************************************************************************/
Jeff Garzikf3518e42007-10-19 15:24:59 -04001217static void
1218ip2_irq_work(i2eBordStrPtr pB)
1219{
1220#ifdef USE_IQI
1221 if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
1222// Disable his interrupt (will be enabled when serviced)
1223// This is mostly to protect from reentrancy.
1224 iiDisableMailIrq(pB);
1225
1226// Park the board on the immediate queue for processing.
1227 schedule_work(&pB->tqueue_interrupt);
1228
1229// Make sure the immediate queue is flagged to fire.
1230 }
1231#else
1232
1233// We are using immediate servicing here. This sucks and can
1234// cause all sorts of havoc with ppp and others. The failsafe
1235// check on iiSendPendingMail could also throw a hairball.
1236
1237 i2ServiceBoard( pB );
1238
1239#endif /* USE_IQI */
1240}
1241
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001242static void
1243ip2_polled_interrupt(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244{
1245 int i;
1246 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001248 ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 /* Service just the boards on the list using this irq */
1251 for( i = 0; i < i2nBoards; ++i ) {
1252 pB = i2BoardPtrTable[i];
1253
1254// Only process those boards which match our IRQ.
1255// IRQ = 0 for polled boards, we won't poll "IRQ" boards
1256
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001257 if (pB && pB->i2eUsingIrq == 0)
Jeff Garzikf3518e42007-10-19 15:24:59 -04001258 ip2_irq_work(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260
1261 ++irq_counter;
1262
1263 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001264}
1265
1266static irqreturn_t
1267ip2_interrupt(int irq, void *dev_id)
1268{
1269 i2eBordStrPtr pB = dev_id;
1270
1271 ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, pB->i2eUsingIrq );
1272
1273 ip2_irq_work(pB);
1274
1275 ++irq_counter;
1276
1277 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1278 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279}
1280
1281/******************************************************************************/
1282/* Function: ip2_poll(unsigned long arg) */
1283/* Parameters: ? */
1284/* Returns: Nothing */
1285/* */
1286/* Description: */
1287/* This function calls the library routine i2ServiceBoard for each board in */
1288/* the board table. This is used instead of the interrupt routine when polled */
1289/* mode is specified. */
1290/******************************************************************************/
1291static void
1292ip2_poll(unsigned long arg)
1293{
1294 ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
1295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
1297 // It will NOT poll boards handled by hard interrupts.
Joe Perches8dfba4d2008-02-03 17:11:42 +02001298 // The issue of queued BH interrupts is handled in ip2_interrupt().
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001299 ip2_polled_interrupt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Akinobu Mita9d020a22008-10-13 10:35:05 +01001301 mod_timer(&PollTimer, POLL_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
1303 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1304}
1305
David Howellsc4028952006-11-22 14:57:56 +00001306static void do_input(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307{
David Howellsc4028952006-11-22 14:57:56 +00001308 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 unsigned long flags;
1310
1311 ip2trace(CHANN, ITRC_INPUT, 21, 0 );
1312
1313 // Data input
1314 if ( pCh->pTTY != NULL ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001315 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001317 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 i2Input( pCh );
1319 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001320 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 } else {
1322 ip2trace(CHANN, ITRC_INPUT, 22, 0 );
1323
1324 i2InputFlush( pCh );
1325 }
1326}
1327
1328// code duplicated from n_tty (ldisc)
1329static inline void isig(int sig, struct tty_struct *tty, int flush)
1330{
Alan Coxa352def2008-07-16 21:53:12 +01001331 /* FIXME: This is completely bogus */
Eric W. Biedermanab521dc2007-02-12 00:53:00 -08001332 if (tty->pgrp)
1333 kill_pgrp(tty->pgrp, sig, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (flush || !L_NOFLSH(tty)) {
Alan Coxc65c9bc2009-06-11 12:50:12 +01001335 if ( tty->ldisc->ops->flush_buffer )
1336 tty->ldisc->ops->flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 i2InputFlush( tty->driver_data );
1338 }
1339}
1340
David Howellsc4028952006-11-22 14:57:56 +00001341static void do_status(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342{
David Howellsc4028952006-11-22 14:57:56 +00001343 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 int status;
1345
1346 status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
1347
1348 ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
1349
1350 if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
1351 if ( (status & I2_BRK) ) {
1352 // code duplicated from n_tty (ldisc)
1353 if (I_IGNBRK(pCh->pTTY))
1354 goto skip_this;
1355 if (I_BRKINT(pCh->pTTY)) {
1356 isig(SIGINT, pCh->pTTY, 1);
1357 goto skip_this;
1358 }
1359 wake_up_interruptible(&pCh->pTTY->read_wait);
1360 }
1361#ifdef NEVER_HAPPENS_AS_SETUP_XXX
1362 // and can't work because we don't know the_char
1363 // as the_char is reported on a separate path
1364 // The intelligent board does this stuff as setup
1365 {
1366 char brkf = TTY_NORMAL;
1367 unsigned char brkc = '\0';
1368 unsigned char tmp;
1369 if ( (status & I2_BRK) ) {
1370 brkf = TTY_BREAK;
1371 brkc = '\0';
1372 }
1373 else if (status & I2_PAR) {
1374 brkf = TTY_PARITY;
1375 brkc = the_char;
1376 } else if (status & I2_FRA) {
1377 brkf = TTY_FRAME;
1378 brkc = the_char;
1379 } else if (status & I2_OVR) {
1380 brkf = TTY_OVERRUN;
1381 brkc = the_char;
1382 }
1383 tmp = pCh->pTTY->real_raw;
1384 pCh->pTTY->real_raw = 0;
Alan Coxa352def2008-07-16 21:53:12 +01001385 pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 pCh->pTTY->real_raw = tmp;
1387 }
1388#endif /* NEVER_HAPPENS_AS_SETUP_XXX */
1389 }
1390skip_this:
1391
1392 if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
1393 wake_up_interruptible(&pCh->delta_msr_wait);
1394
1395 if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
1396 if ( status & I2_DCD ) {
1397 if ( pCh->wopen ) {
1398 wake_up_interruptible ( &pCh->open_wait );
1399 }
1400 } else {
1401 if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
1402 tty_hangup( pCh->pTTY );
1403 }
1404 }
1405 }
1406 }
1407
1408 ip2trace (CHANN, ITRC_STATUS, 26, 0 );
1409}
1410
1411/******************************************************************************/
1412/* Device Open/Close/Ioctl Entry Point Section */
1413/******************************************************************************/
1414
1415/******************************************************************************/
1416/* Function: open_sanity_check() */
1417/* Parameters: Pointer to tty structure */
1418/* Pointer to file structure */
1419/* Returns: Success or failure */
1420/* */
1421/* Description: */
1422/* Verifies the structure magic numbers and cross links. */
1423/******************************************************************************/
1424#ifdef IP2DEBUG_OPEN
1425static void
1426open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
1427{
1428 if ( pBrd->i2eValid != I2E_MAGIC ) {
1429 printk(KERN_ERR "IP2: invalid board structure\n" );
1430 } else if ( pBrd != pCh->pMyBord ) {
1431 printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
1432 pCh->pMyBord );
1433 } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
1434 printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
1435 } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
1436 } else {
1437 printk(KERN_INFO "IP2: all pointers check out!\n" );
1438 }
1439}
1440#endif
1441
1442
1443/******************************************************************************/
1444/* Function: ip2_open() */
1445/* Parameters: Pointer to tty structure */
1446/* Pointer to file structure */
1447/* Returns: Success or failure */
1448/* */
1449/* Description: (MANDATORY) */
1450/* A successful device open has to run a gauntlet of checks before it */
1451/* completes. After some sanity checking and pointer setup, the function */
1452/* blocks until all conditions are satisfied. It then initialises the port to */
1453/* the default characteristics and returns. */
1454/******************************************************************************/
1455static int
1456ip2_open( PTTY tty, struct file *pFile )
1457{
1458 wait_queue_t wait;
1459 int rc = 0;
1460 int do_clocal = 0;
1461 i2ChanStrPtr pCh = DevTable[tty->index];
1462
1463 ip2trace (tty->index, ITRC_OPEN, ITRC_ENTER, 0 );
1464
1465 if ( pCh == NULL ) {
1466 return -ENODEV;
1467 }
1468 /* Setup pointer links in device and tty structures */
1469 pCh->pTTY = tty;
1470 tty->driver_data = pCh;
1471
1472#ifdef IP2DEBUG_OPEN
1473 printk(KERN_DEBUG \
1474 "IP2:open(tty=%p,pFile=%p):dev=%s,ch=%d,idx=%d\n",
1475 tty, pFile, tty->name, pCh->infl.hd.i2sChannel, pCh->port_index);
1476 open_sanity_check ( pCh, pCh->pMyBord );
1477#endif
1478
1479 i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP);
1480 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1481 serviceOutgoingFifo( pCh->pMyBord );
1482
1483 /* Block here until the port is ready (per serial and istallion) */
1484 /*
1485 * 1. If the port is in the middle of closing wait for the completion
1486 * and then return the appropriate error.
1487 */
1488 init_waitqueue_entry(&wait, current);
1489 add_wait_queue(&pCh->close_wait, &wait);
1490 set_current_state( TASK_INTERRUPTIBLE );
1491
1492 if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
1493 if ( pCh->flags & ASYNC_CLOSING ) {
Arnd Bergmanne142a312010-06-01 22:53:10 +02001494 tty_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 schedule();
Arnd Bergmanne142a312010-06-01 22:53:10 +02001496 tty_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 }
1498 if ( tty_hung_up_p(pFile) ) {
1499 set_current_state( TASK_RUNNING );
1500 remove_wait_queue(&pCh->close_wait, &wait);
1501 return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
1502 }
1503 }
1504 set_current_state( TASK_RUNNING );
1505 remove_wait_queue(&pCh->close_wait, &wait);
1506
1507 /*
1508 * 3. Handle a non-blocking open of a normal port.
1509 */
1510 if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
1511 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1512 goto noblock;
1513 }
1514 /*
1515 * 4. Now loop waiting for the port to be free and carrier present
1516 * (if required).
1517 */
1518 if ( tty->termios->c_cflag & CLOCAL )
1519 do_clocal = 1;
1520
1521#ifdef IP2DEBUG_OPEN
1522 printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
1523#endif
1524
1525 ++pCh->wopen;
1526
1527 init_waitqueue_entry(&wait, current);
1528 add_wait_queue(&pCh->open_wait, &wait);
1529
1530 for(;;) {
1531 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1532 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1533 set_current_state( TASK_INTERRUPTIBLE );
1534 serviceOutgoingFifo( pCh->pMyBord );
1535 if ( tty_hung_up_p(pFile) ) {
1536 set_current_state( TASK_RUNNING );
1537 remove_wait_queue(&pCh->open_wait, &wait);
1538 return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
1539 }
1540 if (!(pCh->flags & ASYNC_CLOSING) &&
1541 (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
1542 rc = 0;
1543 break;
1544 }
1545
1546#ifdef IP2DEBUG_OPEN
1547 printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
1548 (pCh->flags & ASYNC_CLOSING)?"True":"False");
1549 printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
1550#endif
1551 ip2trace (CHANN, ITRC_OPEN, 3, 2, 0,
1552 (pCh->flags & ASYNC_CLOSING) );
1553 /* check for signal */
1554 if (signal_pending(current)) {
1555 rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
1556 break;
1557 }
Arnd Bergmanne142a312010-06-01 22:53:10 +02001558 tty_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 schedule();
Arnd Bergmanne142a312010-06-01 22:53:10 +02001560 tty_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 }
1562 set_current_state( TASK_RUNNING );
1563 remove_wait_queue(&pCh->open_wait, &wait);
1564
1565 --pCh->wopen; //why count?
1566
1567 ip2trace (CHANN, ITRC_OPEN, 4, 0 );
1568
1569 if (rc != 0 ) {
1570 return rc;
1571 }
1572 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1573
1574noblock:
1575
1576 /* first open - Assign termios structure to port */
1577 if ( tty->count == 1 ) {
1578 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1579 /* Now we must send the termios settings to the loadware */
1580 set_params( pCh, NULL );
1581 }
1582
1583 /*
1584 * Now set any i2lib options. These may go away if the i2lib code ends
1585 * up rolled into the mainline.
1586 */
1587 pCh->channelOptions |= CO_NBLOCK_WRITE;
1588
1589#ifdef IP2DEBUG_OPEN
1590 printk (KERN_DEBUG "IP2: open completed\n" );
1591#endif
1592 serviceOutgoingFifo( pCh->pMyBord );
1593
1594 ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
1595
1596 return 0;
1597}
1598
1599/******************************************************************************/
1600/* Function: ip2_close() */
1601/* Parameters: Pointer to tty structure */
1602/* Pointer to file structure */
1603/* Returns: Nothing */
1604/* */
1605/* Description: */
1606/* */
1607/* */
1608/******************************************************************************/
1609static void
1610ip2_close( PTTY tty, struct file *pFile )
1611{
1612 i2ChanStrPtr pCh = tty->driver_data;
1613
1614 if ( !pCh ) {
1615 return;
1616 }
1617
1618 ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
1619
1620#ifdef IP2DEBUG_OPEN
1621 printk(KERN_DEBUG "IP2:close %s:\n",tty->name);
1622#endif
1623
1624 if ( tty_hung_up_p ( pFile ) ) {
1625
1626 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
1627
1628 return;
1629 }
1630 if ( tty->count > 1 ) { /* not the last close */
1631
1632 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
1633
1634 return;
1635 }
1636 pCh->flags |= ASYNC_CLOSING; // last close actually
1637
1638 tty->closing = 1;
1639
1640 if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
1641 /*
1642 * Before we drop DTR, make sure the transmitter has completely drained.
1643 * This uses an timeout, after which the close
1644 * completes.
1645 */
1646 ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
1647 }
1648 /*
1649 * At this point we stop accepting input. Here we flush the channel
1650 * input buffer which will allow the board to send up more data. Any
1651 * additional input is tossed at interrupt/poll time.
1652 */
1653 i2InputFlush( pCh );
1654
1655 /* disable DSS reporting */
1656 i2QueueCommands(PTYPE_INLINE, pCh, 100, 4,
1657 CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
Dan Carpenterf64ac982010-08-12 13:48:57 -07001658 if (tty->termios->c_cflag & HUPCL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
1660 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1661 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1662 }
1663
1664 serviceOutgoingFifo ( pCh->pMyBord );
1665
Alan Coxf34d7a52008-04-30 00:54:13 -07001666 tty_ldisc_flush(tty);
Alan Coxa6fc8192008-04-30 00:54:18 -07001667 tty_driver_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 tty->closing = 0;
1669
1670 pCh->pTTY = NULL;
1671
1672 if (pCh->wopen) {
1673 if (pCh->ClosingDelay) {
1674 msleep_interruptible(jiffies_to_msecs(pCh->ClosingDelay));
1675 }
1676 wake_up_interruptible(&pCh->open_wait);
1677 }
1678
1679 pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1680 wake_up_interruptible(&pCh->close_wait);
1681
1682#ifdef IP2DEBUG_OPEN
1683 DBG_CNT("ip2_close: after wakeups--");
1684#endif
1685
1686
1687 ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
1688
1689 return;
1690}
1691
1692/******************************************************************************/
1693/* Function: ip2_hangup() */
1694/* Parameters: Pointer to tty structure */
1695/* Returns: Nothing */
1696/* */
1697/* Description: */
1698/* */
1699/* */
1700/******************************************************************************/
1701static void
1702ip2_hangup ( PTTY tty )
1703{
1704 i2ChanStrPtr pCh = tty->driver_data;
1705
1706 if( !pCh ) {
1707 return;
1708 }
1709
1710 ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
1711
1712 ip2_flush_buffer(tty);
1713
1714 /* disable DSS reporting */
1715
1716 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
1717 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1718 if ( (tty->termios->c_cflag & HUPCL) ) {
1719 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
1720 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1721 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1722 }
1723 i2QueueCommands(PTYPE_INLINE, pCh, 1, 3,
1724 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1725 serviceOutgoingFifo ( pCh->pMyBord );
1726
1727 wake_up_interruptible ( &pCh->delta_msr_wait );
1728
1729 pCh->flags &= ~ASYNC_NORMAL_ACTIVE;
1730 pCh->pTTY = NULL;
1731 wake_up_interruptible ( &pCh->open_wait );
1732
1733 ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
1734}
1735
1736/******************************************************************************/
1737/******************************************************************************/
1738/* Device Output Section */
1739/******************************************************************************/
1740/******************************************************************************/
1741
1742/******************************************************************************/
1743/* Function: ip2_write() */
1744/* Parameters: Pointer to tty structure */
1745/* Flag denoting data is in user (1) or kernel (0) space */
1746/* Pointer to data */
1747/* Number of bytes to write */
1748/* Returns: Number of bytes actually written */
1749/* */
1750/* Description: (MANDATORY) */
1751/* */
1752/* */
1753/******************************************************************************/
1754static int
Alan Coxd9e39532006-01-09 20:54:20 -08001755ip2_write( PTTY tty, const unsigned char *pData, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756{
1757 i2ChanStrPtr pCh = tty->driver_data;
1758 int bytesSent = 0;
1759 unsigned long flags;
1760
1761 ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
1762
1763 /* Flush out any buffered data left over from ip2_putchar() calls. */
1764 ip2_flush_chars( tty );
1765
1766 /* This is the actual move bit. Make sure it does what we need!!!!! */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001767 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Al Virof061c582006-10-11 17:45:47 +01001768 bytesSent = i2Output( pCh, pData, count);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001769 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
1771 ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
1772
1773 return bytesSent > 0 ? bytesSent : 0;
1774}
1775
1776/******************************************************************************/
1777/* Function: ip2_putchar() */
1778/* Parameters: Pointer to tty structure */
1779/* Character to write */
1780/* Returns: Nothing */
1781/* */
1782/* Description: */
1783/* */
1784/* */
1785/******************************************************************************/
Alan Coxf34d7a52008-04-30 00:54:13 -07001786static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787ip2_putchar( PTTY tty, unsigned char ch )
1788{
1789 i2ChanStrPtr pCh = tty->driver_data;
1790 unsigned long flags;
1791
1792// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
1793
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001794 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
1796 if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001797 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 ip2_flush_chars( tty );
1799 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001800 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Alan Coxf34d7a52008-04-30 00:54:13 -07001801 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
1803// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
1804}
1805
1806/******************************************************************************/
1807/* Function: ip2_flush_chars() */
1808/* Parameters: Pointer to tty structure */
1809/* Returns: Nothing */
1810/* */
1811/* Description: */
1812/* */
1813/******************************************************************************/
1814static void
1815ip2_flush_chars( PTTY tty )
1816{
1817 int strip;
1818 i2ChanStrPtr pCh = tty->driver_data;
1819 unsigned long flags;
1820
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001821 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 if ( pCh->Pbuf_stuff ) {
1823
1824// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
1825
1826 //
1827 // We may need to restart i2Output if it does not fullfill this request
1828 //
Al Virof061c582006-10-11 17:45:47 +01001829 strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 if ( strip != pCh->Pbuf_stuff ) {
1831 memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
1832 }
1833 pCh->Pbuf_stuff -= strip;
1834 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001835 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836}
1837
1838/******************************************************************************/
1839/* Function: ip2_write_room() */
1840/* Parameters: Pointer to tty structure */
1841/* Returns: Number of bytes that the driver can accept */
1842/* */
1843/* Description: */
1844/* */
1845/******************************************************************************/
1846static int
1847ip2_write_room ( PTTY tty )
1848{
1849 int bytesFree;
1850 i2ChanStrPtr pCh = tty->driver_data;
1851 unsigned long flags;
1852
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001853 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001855 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
1857 ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
1858
1859 return ((bytesFree > 0) ? bytesFree : 0);
1860}
1861
1862/******************************************************************************/
1863/* Function: ip2_chars_in_buf() */
1864/* Parameters: Pointer to tty structure */
1865/* Returns: Number of bytes queued for transmission */
1866/* */
1867/* Description: */
1868/* */
1869/* */
1870/******************************************************************************/
1871static int
1872ip2_chars_in_buf ( PTTY tty )
1873{
1874 i2ChanStrPtr pCh = tty->driver_data;
1875 int rc;
1876 unsigned long flags;
1877
1878 ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
1879
1880#ifdef IP2DEBUG_WRITE
1881 printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
1882 pCh->Obuf_char_count + pCh->Pbuf_stuff,
1883 pCh->Obuf_char_count, pCh->Pbuf_stuff );
1884#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001885 read_lock_irqsave(&pCh->Obuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 rc = pCh->Obuf_char_count;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001887 read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
1888 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 rc += pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001890 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 return rc;
1892}
1893
1894/******************************************************************************/
1895/* Function: ip2_flush_buffer() */
1896/* Parameters: Pointer to tty structure */
1897/* Returns: Nothing */
1898/* */
1899/* Description: */
1900/* */
1901/* */
1902/******************************************************************************/
1903static void
1904ip2_flush_buffer( PTTY tty )
1905{
1906 i2ChanStrPtr pCh = tty->driver_data;
1907 unsigned long flags;
1908
1909 ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
1910
1911#ifdef IP2DEBUG_WRITE
1912 printk (KERN_DEBUG "IP2: flush buffer\n" );
1913#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001914 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 pCh->Pbuf_stuff = 0;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001916 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 i2FlushOutput( pCh );
1918 ip2_owake(tty);
1919
1920 ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
1921
1922}
1923
1924/******************************************************************************/
1925/* Function: ip2_wait_until_sent() */
1926/* Parameters: Pointer to tty structure */
1927/* Timeout for wait. */
1928/* Returns: Nothing */
1929/* */
1930/* Description: */
1931/* This function is used in place of the normal tty_wait_until_sent, which */
1932/* only waits for the driver buffers to be empty (or rather, those buffers */
1933/* reported by chars_in_buffer) which doesn't work for IP2 due to the */
1934/* indeterminate number of bytes buffered on the board. */
1935/******************************************************************************/
1936static void
1937ip2_wait_until_sent ( PTTY tty, int timeout )
1938{
1939 int i = jiffies;
1940 i2ChanStrPtr pCh = tty->driver_data;
1941
1942 tty_wait_until_sent(tty, timeout );
1943 if ( (i = timeout - (jiffies -i)) > 0)
1944 i2DrainOutput( pCh, i );
1945}
1946
1947/******************************************************************************/
1948/******************************************************************************/
1949/* Device Input Section */
1950/******************************************************************************/
1951/******************************************************************************/
1952
1953/******************************************************************************/
1954/* Function: ip2_throttle() */
1955/* Parameters: Pointer to tty structure */
1956/* Returns: Nothing */
1957/* */
1958/* Description: */
1959/* */
1960/* */
1961/******************************************************************************/
1962static void
1963ip2_throttle ( PTTY tty )
1964{
1965 i2ChanStrPtr pCh = tty->driver_data;
1966
1967#ifdef IP2DEBUG_READ
1968 printk (KERN_DEBUG "IP2: throttle\n" );
1969#endif
1970 /*
1971 * Signal the poll/interrupt handlers not to forward incoming data to
1972 * the line discipline. This will cause the buffers to fill up in the
1973 * library and thus cause the library routines to send the flow control
1974 * stuff.
1975 */
1976 pCh->throttled = 1;
1977}
1978
1979/******************************************************************************/
1980/* Function: ip2_unthrottle() */
1981/* Parameters: Pointer to tty structure */
1982/* Returns: Nothing */
1983/* */
1984/* Description: */
1985/* */
1986/* */
1987/******************************************************************************/
1988static void
1989ip2_unthrottle ( PTTY tty )
1990{
1991 i2ChanStrPtr pCh = tty->driver_data;
1992 unsigned long flags;
1993
1994#ifdef IP2DEBUG_READ
1995 printk (KERN_DEBUG "IP2: unthrottle\n" );
1996#endif
1997
1998 /* Pass incoming data up to the line discipline again. */
1999 pCh->throttled = 0;
2000 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
2001 serviceOutgoingFifo( pCh->pMyBord );
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002002 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002004 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005#ifdef IP2DEBUG_READ
2006 printk (KERN_DEBUG "i2Input called from unthrottle\n" );
2007#endif
2008 i2Input( pCh );
2009 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002010 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011}
2012
2013static void
2014ip2_start ( PTTY tty )
2015{
2016 i2ChanStrPtr pCh = DevTable[tty->index];
2017
2018 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
2019 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
2020 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
2021#ifdef IP2DEBUG_WRITE
2022 printk (KERN_DEBUG "IP2: start tx\n" );
2023#endif
2024}
2025
2026static void
2027ip2_stop ( PTTY tty )
2028{
2029 i2ChanStrPtr pCh = DevTable[tty->index];
2030
2031 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
2032#ifdef IP2DEBUG_WRITE
2033 printk (KERN_DEBUG "IP2: stop tx\n" );
2034#endif
2035}
2036
2037/******************************************************************************/
2038/* Device Ioctl Section */
2039/******************************************************************************/
2040
Alan Cox60b33c12011-02-14 16:26:14 +00002041static int ip2_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042{
2043 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002044#ifdef ENABLE_DSSNOW
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 wait_queue_t wait;
Alan Coxd9e39532006-01-09 20:54:20 -08002046#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047
2048 if (pCh == NULL)
2049 return -ENODEV;
2050
2051/*
2052 FIXME - the following code is causing a NULL pointer dereference in
2053 2.3.51 in an interrupt handler. It's suppose to prompt the board
2054 to return the DSS signal status immediately. Why doesn't it do
2055 the same thing in 2.2.14?
2056*/
2057
2058/* This thing is still busted in the 1.2.12 driver on 2.4.x
2059 and even hoses the serial console so the oops can be trapped.
2060 /\/\|=mhw=|\/\/ */
2061
2062#ifdef ENABLE_DSSNOW
2063 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
2064
2065 init_waitqueue_entry(&wait, current);
2066 add_wait_queue(&pCh->dss_now_wait, &wait);
2067 set_current_state( TASK_INTERRUPTIBLE );
2068
2069 serviceOutgoingFifo( pCh->pMyBord );
2070
2071 schedule();
2072
2073 set_current_state( TASK_RUNNING );
2074 remove_wait_queue(&pCh->dss_now_wait, &wait);
2075
2076 if (signal_pending(current)) {
2077 return -EINTR;
2078 }
2079#endif
2080 return ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
2081 | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
2082 | ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0)
2083 | ((pCh->dataSetIn & I2_RI) ? TIOCM_RNG : 0)
2084 | ((pCh->dataSetIn & I2_DSR) ? TIOCM_DSR : 0)
2085 | ((pCh->dataSetIn & I2_CTS) ? TIOCM_CTS : 0);
2086}
2087
2088static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
2089 unsigned int set, unsigned int clear)
2090{
2091 i2ChanStrPtr pCh = DevTable[tty->index];
2092
2093 if (pCh == NULL)
2094 return -ENODEV;
2095
2096 if (set & TIOCM_RTS) {
2097 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2098 pCh->dataSetOut |= I2_RTS;
2099 }
2100 if (set & TIOCM_DTR) {
2101 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2102 pCh->dataSetOut |= I2_DTR;
2103 }
2104
2105 if (clear & TIOCM_RTS) {
2106 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2107 pCh->dataSetOut &= ~I2_RTS;
2108 }
2109 if (clear & TIOCM_DTR) {
2110 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2111 pCh->dataSetOut &= ~I2_DTR;
2112 }
2113 serviceOutgoingFifo( pCh->pMyBord );
2114 return 0;
2115}
2116
2117/******************************************************************************/
2118/* Function: ip2_ioctl() */
2119/* Parameters: Pointer to tty structure */
2120/* Pointer to file structure */
2121/* Command */
2122/* Argument */
2123/* Returns: Success or failure */
2124/* */
2125/* Description: */
2126/* */
2127/* */
2128/******************************************************************************/
2129static int
2130ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
2131{
2132 wait_queue_t wait;
2133 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002134 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 struct async_icount cprev, cnow; /* kernel counter temps */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 int rc = 0;
2137 unsigned long flags;
2138 void __user *argp = (void __user *)arg;
2139
Alan Coxd9e39532006-01-09 20:54:20 -08002140 if ( pCh == NULL )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 return -ENODEV;
Alan Coxd9e39532006-01-09 20:54:20 -08002142
2143 pB = pCh->pMyBord;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
2145 ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
2146
2147#ifdef IP2DEBUG_IOCTL
2148 printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
2149#endif
2150
2151 switch(cmd) {
2152 case TIOCGSERIAL:
2153
2154 ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
2155
2156 rc = get_serial_info(pCh, argp);
2157 if (rc)
2158 return rc;
2159 break;
2160
2161 case TIOCSSERIAL:
2162
2163 ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
2164
2165 rc = set_serial_info(pCh, argp);
2166 if (rc)
2167 return rc;
2168 break;
2169
2170 case TCXONC:
2171 rc = tty_check_change(tty);
2172 if (rc)
2173 return rc;
2174 switch (arg) {
2175 case TCOOFF:
2176 //return -ENOIOCTLCMD;
2177 break;
2178 case TCOON:
2179 //return -ENOIOCTLCMD;
2180 break;
2181 case TCIOFF:
2182 if (STOP_CHAR(tty) != __DISABLED_CHAR) {
2183 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2184 CMD_XMIT_NOW(STOP_CHAR(tty)));
2185 }
2186 break;
2187 case TCION:
2188 if (START_CHAR(tty) != __DISABLED_CHAR) {
2189 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2190 CMD_XMIT_NOW(START_CHAR(tty)));
2191 }
2192 break;
2193 default:
2194 return -EINVAL;
2195 }
2196 return 0;
2197
2198 case TCSBRK: /* SVID version: non-zero arg --> no break */
2199 rc = tty_check_change(tty);
2200
2201 ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
2202
2203 if (!rc) {
2204 ip2_wait_until_sent(tty,0);
2205 if (!arg) {
2206 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
2207 serviceOutgoingFifo( pCh->pMyBord );
2208 }
2209 }
2210 break;
2211
2212 case TCSBRKP: /* support for POSIX tcsendbreak() */
2213 rc = tty_check_change(tty);
2214
2215 ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
2216
2217 if (!rc) {
2218 ip2_wait_until_sent(tty,0);
2219 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2220 CMD_SEND_BRK(arg ? arg*100 : 250));
2221 serviceOutgoingFifo ( pCh->pMyBord );
2222 }
2223 break;
2224
2225 case TIOCGSOFTCAR:
2226
2227 ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
2228
2229 rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
2230 if (rc)
2231 return rc;
2232 break;
2233
2234 case TIOCSSOFTCAR:
2235
2236 ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
2237
2238 rc = get_user(arg,(unsigned long __user *) argp);
2239 if (rc)
2240 return rc;
2241 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
2242 | (arg ? CLOCAL : 0));
2243
2244 break;
2245
2246 /*
2247 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
2248 * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
2249 * for masking). Caller should use TIOCGICOUNT to see which one it was
2250 */
2251 case TIOCMIWAIT:
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002252 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 cprev = pCh->icount; /* note the counters on entry */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002254 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
2256 CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
2257 init_waitqueue_entry(&wait, current);
2258 add_wait_queue(&pCh->delta_msr_wait, &wait);
2259 set_current_state( TASK_INTERRUPTIBLE );
2260
2261 serviceOutgoingFifo( pCh->pMyBord );
2262 for(;;) {
2263 ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
2264
2265 schedule();
2266
2267 ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
2268
2269 /* see if a signal did it */
2270 if (signal_pending(current)) {
2271 rc = -ERESTARTSYS;
2272 break;
2273 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002274 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 cnow = pCh->icount; /* atomic copy */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002276 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2278 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2279 rc = -EIO; /* no change => rc */
2280 break;
2281 }
2282 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2283 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2284 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2285 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2286 rc = 0;
2287 break;
2288 }
2289 cprev = cnow;
2290 }
2291 set_current_state( TASK_RUNNING );
2292 remove_wait_queue(&pCh->delta_msr_wait, &wait);
2293
2294 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3,
2295 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
2296 if ( ! (pCh->flags & ASYNC_CHECK_CD)) {
2297 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP);
2298 }
2299 serviceOutgoingFifo( pCh->pMyBord );
2300 return rc;
2301 break;
2302
2303 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
2305 * will be passed to the line discipline for it to handle.
2306 */
2307 case TIOCSERCONFIG:
2308 case TIOCSERGWILD:
2309 case TIOCSERGETLSR:
2310 case TIOCSERSWILD:
2311 case TIOCSERGSTRUCT:
2312 case TIOCSERGETMULTI:
2313 case TIOCSERSETMULTI:
2314
2315 default:
2316 ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
2317
2318 rc = -ENOIOCTLCMD;
2319 break;
2320 }
2321
2322 ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
2323
2324 return rc;
2325}
2326
Alan Cox05871022010-09-16 18:21:52 +01002327static int ip2_get_icount(struct tty_struct *tty,
2328 struct serial_icounter_struct *icount)
2329{
2330 i2ChanStrPtr pCh = DevTable[tty->index];
2331 i2eBordStrPtr pB;
2332 struct async_icount cnow; /* kernel counter temp */
2333 unsigned long flags;
2334
2335 if ( pCh == NULL )
2336 return -ENODEV;
2337
2338 pB = pCh->pMyBord;
2339
2340 /*
2341 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2342 * Return: write counters to the user passed counter struct
2343 * NB: both 1->0 and 0->1 transitions are counted except for RI where
2344 * only 0->1 is counted. The controller is quite capable of counting
2345 * both, but this done to preserve compatibility with the standard
2346 * serial driver.
2347 */
2348
2349 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
2350 cnow = pCh->icount;
2351 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
2352
2353 icount->cts = cnow.cts;
2354 icount->dsr = cnow.dsr;
2355 icount->rng = cnow.rng;
2356 icount->dcd = cnow.dcd;
2357 icount->rx = cnow.rx;
2358 icount->tx = cnow.tx;
2359 icount->frame = cnow.frame;
2360 icount->overrun = cnow.overrun;
2361 icount->parity = cnow.parity;
2362 icount->brk = cnow.brk;
2363 icount->buf_overrun = cnow.buf_overrun;
2364 return 0;
2365}
2366
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367/******************************************************************************/
2368/* Function: GetSerialInfo() */
2369/* Parameters: Pointer to channel structure */
2370/* Pointer to old termios structure */
2371/* Returns: Nothing */
2372/* */
2373/* Description: */
2374/* This is to support the setserial command, and requires processing of the */
2375/* standard Linux serial structure. */
2376/******************************************************************************/
2377static int
2378get_serial_info ( i2ChanStrPtr pCh, struct serial_struct __user *retinfo )
2379{
2380 struct serial_struct tmp;
2381
2382 memset ( &tmp, 0, sizeof(tmp) );
2383 tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
2384 if (BID_HAS_654(tmp.type)) {
2385 tmp.type = PORT_16650;
2386 } else {
2387 tmp.type = PORT_CIRRUS;
2388 }
2389 tmp.line = pCh->port_index;
2390 tmp.port = pCh->pMyBord->i2eBase;
2391 tmp.irq = ip2config.irq[pCh->port_index/64];
2392 tmp.flags = pCh->flags;
2393 tmp.baud_base = pCh->BaudBase;
2394 tmp.close_delay = pCh->ClosingDelay;
2395 tmp.closing_wait = pCh->ClosingWaitTime;
2396 tmp.custom_divisor = pCh->BaudDivisor;
2397 return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
2398}
2399
2400/******************************************************************************/
2401/* Function: SetSerialInfo() */
2402/* Parameters: Pointer to channel structure */
2403/* Pointer to old termios structure */
2404/* Returns: Nothing */
2405/* */
2406/* Description: */
2407/* This function provides support for setserial, which uses the TIOCSSERIAL */
2408/* ioctl. Not all setserial parameters are relevant. If the user attempts to */
2409/* change the IRQ, address or type of the port the ioctl fails. */
2410/******************************************************************************/
2411static int
2412set_serial_info( i2ChanStrPtr pCh, struct serial_struct __user *new_info )
2413{
2414 struct serial_struct ns;
2415 int old_flags, old_baud_divisor;
2416
2417 if (copy_from_user(&ns, new_info, sizeof (ns)))
2418 return -EFAULT;
2419
2420 /*
2421 * We don't allow setserial to change IRQ, board address, type or baud
2422 * base. Also line nunber as such is meaningless but we use it for our
2423 * array index so it is fixed also.
2424 */
2425 if ( (ns.irq != ip2config.irq[pCh->port_index])
2426 || ((int) ns.port != ((int) (pCh->pMyBord->i2eBase)))
2427 || (ns.baud_base != pCh->BaudBase)
2428 || (ns.line != pCh->port_index) ) {
2429 return -EINVAL;
2430 }
2431
2432 old_flags = pCh->flags;
2433 old_baud_divisor = pCh->BaudDivisor;
2434
2435 if ( !capable(CAP_SYS_ADMIN) ) {
2436 if ( ( ns.close_delay != pCh->ClosingDelay ) ||
2437 ( (ns.flags & ~ASYNC_USR_MASK) !=
2438 (pCh->flags & ~ASYNC_USR_MASK) ) ) {
2439 return -EPERM;
2440 }
2441
2442 pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
2443 (ns.flags & ASYNC_USR_MASK);
2444 pCh->BaudDivisor = ns.custom_divisor;
2445 } else {
2446 pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
2447 (ns.flags & ASYNC_FLAGS);
2448 pCh->BaudDivisor = ns.custom_divisor;
2449 pCh->ClosingDelay = ns.close_delay * HZ/100;
2450 pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
2451 }
2452
2453 if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
2454 || (old_baud_divisor != pCh->BaudDivisor) ) {
2455 // Invalidate speed and reset parameters
2456 set_params( pCh, NULL );
2457 }
2458
2459 return 0;
2460}
2461
2462/******************************************************************************/
2463/* Function: ip2_set_termios() */
2464/* Parameters: Pointer to tty structure */
2465/* Pointer to old termios structure */
2466/* Returns: Nothing */
2467/* */
2468/* Description: */
2469/* */
2470/* */
2471/******************************************************************************/
2472static void
Alan Cox606d0992006-12-08 02:38:45 -08002473ip2_set_termios( PTTY tty, struct ktermios *old_termios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474{
2475 i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
2476
2477#ifdef IP2DEBUG_IOCTL
2478 printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
2479#endif
2480
2481 set_params( pCh, old_termios );
2482}
2483
2484/******************************************************************************/
2485/* Function: ip2_set_line_discipline() */
2486/* Parameters: Pointer to tty structure */
2487/* Returns: Nothing */
2488/* */
2489/* Description: Does nothing */
2490/* */
2491/* */
2492/******************************************************************************/
2493static void
2494ip2_set_line_discipline ( PTTY tty )
2495{
2496#ifdef IP2DEBUG_IOCTL
2497 printk (KERN_DEBUG "IP2: set line discipline\n" );
2498#endif
2499
2500 ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
2501
2502}
2503
2504/******************************************************************************/
2505/* Function: SetLine Characteristics() */
2506/* Parameters: Pointer to channel structure */
2507/* Returns: Nothing */
2508/* */
2509/* Description: */
2510/* This routine is called to update the channel structure with the new line */
2511/* characteristics, and send the appropriate commands to the board when they */
2512/* change. */
2513/******************************************************************************/
2514static void
Alan Cox606d0992006-12-08 02:38:45 -08002515set_params( i2ChanStrPtr pCh, struct ktermios *o_tios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516{
2517 tcflag_t cflag, iflag, lflag;
2518 char stop_char, start_char;
Alan Cox606d0992006-12-08 02:38:45 -08002519 struct ktermios dummy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
2521 lflag = pCh->pTTY->termios->c_lflag;
2522 cflag = pCh->pTTY->termios->c_cflag;
2523 iflag = pCh->pTTY->termios->c_iflag;
2524
2525 if (o_tios == NULL) {
2526 dummy.c_lflag = ~lflag;
2527 dummy.c_cflag = ~cflag;
2528 dummy.c_iflag = ~iflag;
2529 o_tios = &dummy;
2530 }
2531
2532 {
2533 switch ( cflag & CBAUD ) {
2534 case B0:
2535 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
2536 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
2537 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
2538 pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
2539 goto service_it;
2540 break;
2541 case B38400:
2542 /*
2543 * This is the speed that is overloaded with all the other high
2544 * speeds, depending upon the flag settings.
2545 */
2546 if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
2547 pCh->speed = CBR_57600;
2548 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
2549 pCh->speed = CBR_115200;
2550 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
2551 pCh->speed = CBR_C1;
2552 } else {
2553 pCh->speed = CBR_38400;
2554 }
2555 break;
2556 case B50: pCh->speed = CBR_50; break;
2557 case B75: pCh->speed = CBR_75; break;
2558 case B110: pCh->speed = CBR_110; break;
2559 case B134: pCh->speed = CBR_134; break;
2560 case B150: pCh->speed = CBR_150; break;
2561 case B200: pCh->speed = CBR_200; break;
2562 case B300: pCh->speed = CBR_300; break;
2563 case B600: pCh->speed = CBR_600; break;
2564 case B1200: pCh->speed = CBR_1200; break;
2565 case B1800: pCh->speed = CBR_1800; break;
2566 case B2400: pCh->speed = CBR_2400; break;
2567 case B4800: pCh->speed = CBR_4800; break;
2568 case B9600: pCh->speed = CBR_9600; break;
2569 case B19200: pCh->speed = CBR_19200; break;
2570 case B57600: pCh->speed = CBR_57600; break;
2571 case B115200: pCh->speed = CBR_115200; break;
2572 case B153600: pCh->speed = CBR_153600; break;
2573 case B230400: pCh->speed = CBR_230400; break;
2574 case B307200: pCh->speed = CBR_307200; break;
2575 case B460800: pCh->speed = CBR_460800; break;
2576 case B921600: pCh->speed = CBR_921600; break;
2577 default: pCh->speed = CBR_9600; break;
2578 }
2579 if ( pCh->speed == CBR_C1 ) {
2580 // Process the custom speed parameters.
2581 int bps = pCh->BaudBase / pCh->BaudDivisor;
2582 if ( bps == 921600 ) {
2583 pCh->speed = CBR_921600;
2584 } else {
2585 bps = bps/10;
2586 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
2587 }
2588 }
2589 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
2590
2591 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
2592 pCh->dataSetOut |= (I2_DTR | I2_RTS);
2593 }
2594 if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag))
2595 {
2596 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2597 CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
2598 }
2599 if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag))
2600 {
2601 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2602 CMD_SETPAR(
2603 (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
2604 )
2605 );
2606 }
2607 /* byte size and parity */
2608 if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag))
2609 {
2610 int datasize;
2611 switch ( cflag & CSIZE ) {
2612 case CS5: datasize = CSZ_5; break;
2613 case CS6: datasize = CSZ_6; break;
2614 case CS7: datasize = CSZ_7; break;
2615 case CS8: datasize = CSZ_8; break;
2616 default: datasize = CSZ_5; break; /* as per serial.c */
2617 }
2618 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
2619 }
2620 /* Process CTS flow control flag setting */
2621 if ( (cflag & CRTSCTS) ) {
2622 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2623 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
2624 } else {
2625 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2626 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
2627 }
2628 //
2629 // Process XON/XOFF flow control flags settings
2630 //
2631 stop_char = STOP_CHAR(pCh->pTTY);
2632 start_char = START_CHAR(pCh->pTTY);
2633
2634 //////////// can't be \000
2635 if (stop_char == __DISABLED_CHAR )
2636 {
2637 stop_char = ~__DISABLED_CHAR;
2638 }
2639 if (start_char == __DISABLED_CHAR )
2640 {
2641 start_char = ~__DISABLED_CHAR;
2642 }
2643 /////////////////////////////////
2644
2645 if ( o_tios->c_cc[VSTART] != start_char )
2646 {
2647 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
2648 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
2649 }
2650 if ( o_tios->c_cc[VSTOP] != stop_char )
2651 {
2652 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
2653 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
2654 }
2655 if (stop_char == __DISABLED_CHAR )
2656 {
2657 stop_char = ~__DISABLED_CHAR; //TEST123
2658 goto no_xoff;
2659 }
2660 if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF)))
2661 {
2662 if ( iflag & IXOFF ) { // Enable XOFF output flow control
2663 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
2664 } else { // Disable XOFF output flow control
2665no_xoff:
2666 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
2667 }
2668 }
2669 if (start_char == __DISABLED_CHAR )
2670 {
2671 goto no_xon;
2672 }
2673 if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY)))
2674 {
2675 if ( iflag & IXON ) {
2676 if ( iflag & IXANY ) { // Enable XON/XANY output flow control
2677 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
2678 } else { // Enable XON output flow control
2679 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
2680 }
2681 } else { // Disable XON output flow control
2682no_xon:
2683 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
2684 }
2685 }
2686 if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) )
2687 {
2688 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2689 CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
2690 }
2691 if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) )
2692 {
2693 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2694 CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
2695 }
2696
2697 if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR))
2698 ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) )
2699 {
2700 char brkrpt = 0;
2701 char parrpt = 0;
2702
2703 if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
2704 /* Ignore breaks altogether */
2705 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
2706 } else {
2707 if ( iflag & BRKINT ) {
2708 if ( iflag & PARMRK ) {
2709 brkrpt = 0x0a; // exception an inline triple
2710 } else {
2711 brkrpt = 0x1a; // exception and NULL
2712 }
2713 brkrpt |= 0x04; // flush input
2714 } else {
2715 if ( iflag & PARMRK ) {
2716 brkrpt = 0x0b; //POSIX triple \0377 \0 \0
2717 } else {
2718 brkrpt = 0x01; // Null only
2719 }
2720 }
2721 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
2722 }
2723
2724 if (iflag & IGNPAR) {
2725 parrpt = 0x20;
2726 /* would be 2 for not cirrus bug */
2727 /* would be 0x20 cept for cirrus bug */
2728 } else {
2729 if ( iflag & PARMRK ) {
2730 /*
2731 * Replace error characters with 3-byte sequence (\0377,\0,char)
2732 */
2733 parrpt = 0x04 ;
2734 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
2735 } else {
2736 parrpt = 0x03;
2737 }
2738 }
2739 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
2740 }
2741 if (cflag & CLOCAL) {
2742 // Status reporting fails for DCD if this is off
2743 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
2744 pCh->flags &= ~ASYNC_CHECK_CD;
2745 } else {
2746 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
2747 pCh->flags |= ASYNC_CHECK_CD;
2748 }
2749
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750service_it:
2751 i2DrainOutput( pCh, 100 );
2752}
2753
2754/******************************************************************************/
2755/* IPL Device Section */
2756/******************************************************************************/
2757
2758/******************************************************************************/
2759/* Function: ip2_ipl_read() */
2760/* Parameters: Pointer to device inode */
2761/* Pointer to file structure */
2762/* Pointer to data */
2763/* Number of bytes to read */
2764/* Returns: Success or failure */
2765/* */
2766/* Description: Ugly */
2767/* */
2768/* */
2769/******************************************************************************/
2770
2771static
2772ssize_t
2773ip2_ipl_read(struct file *pFile, char __user *pData, size_t count, loff_t *off )
2774{
Josef Sipeka7113a92006-12-08 02:36:55 -08002775 unsigned int minor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 int rc = 0;
2777
2778#ifdef IP2DEBUG_IPL
2779 printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
2780#endif
2781
2782 switch( minor ) {
2783 case 0: // IPL device
2784 rc = -EINVAL;
2785 break;
2786 case 1: // Status dump
2787 rc = -EINVAL;
2788 break;
2789 case 2: // Ping device
2790 rc = -EINVAL;
2791 break;
2792 case 3: // Trace device
2793 rc = DumpTraceBuffer ( pData, count );
2794 break;
2795 case 4: // Trace device
2796 rc = DumpFifoBuffer ( pData, count );
2797 break;
2798 default:
2799 rc = -ENODEV;
2800 break;
2801 }
2802 return rc;
2803}
2804
2805static int
2806DumpFifoBuffer ( char __user *pData, int count )
2807{
2808#ifdef DEBUG_FIFO
2809 int rc;
2810 rc = copy_to_user(pData, DBGBuf, count);
2811
2812 printk(KERN_DEBUG "Last index %d\n", I );
2813
2814 return count;
2815#endif /* DEBUG_FIFO */
2816 return 0;
2817}
2818
2819static int
2820DumpTraceBuffer ( char __user *pData, int count )
2821{
2822#ifdef IP2DEBUG_TRACE
2823 int rc;
2824 int dumpcount;
2825 int chunk;
2826 int *pIndex = (int __user *)pData;
2827
2828 if ( count < (sizeof(int) * 6) ) {
2829 return -EIO;
2830 }
2831 rc = put_user(tracewrap, pIndex );
2832 rc = put_user(TRACEMAX, ++pIndex );
2833 rc = put_user(tracestrip, ++pIndex );
2834 rc = put_user(tracestuff, ++pIndex );
2835 pData += sizeof(int) * 6;
2836 count -= sizeof(int) * 6;
2837
2838 dumpcount = tracestuff - tracestrip;
2839 if ( dumpcount < 0 ) {
2840 dumpcount += TRACEMAX;
2841 }
2842 if ( dumpcount > count ) {
2843 dumpcount = count;
2844 }
2845 chunk = TRACEMAX - tracestrip;
2846 if ( dumpcount > chunk ) {
2847 rc = copy_to_user(pData, &tracebuf[tracestrip],
2848 chunk * sizeof(tracebuf[0]) );
2849 pData += chunk * sizeof(tracebuf[0]);
2850 tracestrip = 0;
2851 chunk = dumpcount - chunk;
2852 } else {
2853 chunk = dumpcount;
2854 }
2855 rc = copy_to_user(pData, &tracebuf[tracestrip],
2856 chunk * sizeof(tracebuf[0]) );
2857 tracestrip += chunk;
2858 tracewrap = 0;
2859
2860 rc = put_user(tracestrip, ++pIndex );
2861 rc = put_user(tracestuff, ++pIndex );
2862
2863 return dumpcount;
2864#else
2865 return 0;
2866#endif
2867}
2868
2869/******************************************************************************/
2870/* Function: ip2_ipl_write() */
2871/* Parameters: */
2872/* Pointer to file structure */
2873/* Pointer to data */
2874/* Number of bytes to write */
2875/* Returns: Success or failure */
2876/* */
2877/* Description: */
2878/* */
2879/* */
2880/******************************************************************************/
2881static ssize_t
2882ip2_ipl_write(struct file *pFile, const char __user *pData, size_t count, loff_t *off)
2883{
2884#ifdef IP2DEBUG_IPL
2885 printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
2886#endif
2887 return 0;
2888}
2889
2890/******************************************************************************/
2891/* Function: ip2_ipl_ioctl() */
2892/* Parameters: Pointer to device inode */
2893/* Pointer to file structure */
2894/* Command */
2895/* Argument */
2896/* Returns: Success or failure */
2897/* */
2898/* Description: */
2899/* */
2900/* */
2901/******************************************************************************/
Alan Cox47be36a2008-07-25 01:48:13 -07002902static long
2903ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904{
Alan Cox47be36a2008-07-25 01:48:13 -07002905 unsigned int iplminor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 int rc = 0;
2907 void __user *argp = (void __user *)arg;
2908 ULONG __user *pIndex = argp;
2909 i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
2910 i2ChanStrPtr pCh;
2911
2912#ifdef IP2DEBUG_IPL
2913 printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
2914#endif
2915
Arnd Bergmann613655f2010-06-02 14:28:52 +02002916 mutex_lock(&ip2_mutex);
Alan Cox47be36a2008-07-25 01:48:13 -07002917
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 switch ( iplminor ) {
2919 case 0: // IPL device
2920 rc = -EINVAL;
2921 break;
2922 case 1: // Status dump
2923 case 5:
2924 case 9:
2925 case 13:
2926 switch ( cmd ) {
2927 case 64: /* Driver - ip2stat */
Alan Cox7d7b93c2008-10-13 10:42:09 +01002928 rc = put_user(-1, pIndex++ );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 rc = put_user(irq_counter, pIndex++ );
2930 rc = put_user(bh_counter, pIndex++ );
2931 break;
2932
2933 case 65: /* Board - ip2stat */
2934 if ( pB ) {
2935 rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002936 rc = put_user(inb(pB->i2eStatus),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 (ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
2938 } else {
2939 rc = -ENODEV;
2940 }
2941 break;
2942
2943 default:
2944 if (cmd < IP2_MAX_PORTS) {
2945 pCh = DevTable[cmd];
2946 if ( pCh )
2947 {
2948 rc = copy_to_user(argp, pCh, sizeof(i2ChanStr));
Dan Carpenter05254a22010-08-12 13:48:59 -07002949 if (rc)
2950 rc = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 } else {
2952 rc = -ENODEV;
2953 }
2954 } else {
2955 rc = -EINVAL;
2956 }
2957 }
2958 break;
2959
2960 case 2: // Ping device
2961 rc = -EINVAL;
2962 break;
2963 case 3: // Trace device
Andrew Mortondef93912006-02-03 03:04:47 -08002964 /*
2965 * akpm: This used to write a whole bunch of function addresses
2966 * to userspace, which generated lots of put_user() warnings.
2967 * I killed it all. Just return "success" and don't do
2968 * anything.
2969 */
2970 if (cmd == 1)
2971 rc = 0;
2972 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 break;
2975
2976 default:
2977 rc = -ENODEV;
2978 break;
2979 }
Arnd Bergmann613655f2010-06-02 14:28:52 +02002980 mutex_unlock(&ip2_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 return rc;
2982}
2983
2984/******************************************************************************/
2985/* Function: ip2_ipl_open() */
2986/* Parameters: Pointer to device inode */
2987/* Pointer to file structure */
2988/* Returns: Success or failure */
2989/* */
2990/* Description: */
2991/* */
2992/* */
2993/******************************************************************************/
2994static int
2995ip2_ipl_open( struct inode *pInode, struct file *pFile )
2996{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997
2998#ifdef IP2DEBUG_IPL
2999 printk (KERN_DEBUG "IP2IPL: open\n" );
3000#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 return 0;
3002}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003
3004static int
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003005proc_ip2mem_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006{
3007 i2eBordStrPtr pB;
3008 i2ChanStrPtr pCh;
3009 PTTY tty;
3010 int i;
3011
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
3013#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
3014#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
3015
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003016 seq_printf(m,"\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
3018 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3019 pB = i2BoardPtrTable[i];
3020 if ( pB ) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003021 seq_printf(m,"board %d:\n",i);
3022 seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
3024 }
3025 }
3026
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003027 seq_printf(m,"#: tty flags, port flags, cflags, iflags\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 for (i=0; i < IP2_MAX_PORTS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 pCh = DevTable[i];
3030 if (pCh) {
3031 tty = pCh->pTTY;
3032 if (tty && tty->count) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003033 seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 tty->termios->c_cflag,tty->termios->c_iflag);
3035
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003036 seq_printf(m,FMTLIN2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003038 seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 }
3040 }
3041 }
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003042 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043}
3044
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003045static int proc_ip2mem_open(struct inode *inode, struct file *file)
3046{
3047 return single_open(file, proc_ip2mem_show, NULL);
3048}
3049
3050static const struct file_operations ip2mem_proc_fops = {
3051 .owner = THIS_MODULE,
3052 .open = proc_ip2mem_open,
3053 .read = seq_read,
3054 .llseek = seq_lseek,
3055 .release = single_release,
3056};
3057
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058/*
3059 * This is the handler for /proc/tty/driver/ip2
3060 *
3061 * This stretch of code has been largely plagerized from at least three
3062 * different sources including ip2mkdev.c and a couple of other drivers.
3063 * The bugs are all mine. :-) =mhw=
3064 */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003065static int ip2_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066{
3067 int i, j, box;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 int boxes = 0;
3069 int ports = 0;
3070 int tports = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 i2eBordStrPtr pB;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003072 char *sep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003074 seq_printf(m, "ip2info: 1.0 driver: %s\n", pcVersion);
3075 seq_printf(m, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
3077 IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
3078
3079 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3080 /* This need to be reset for a board by board count... */
3081 boxes = 0;
3082 pB = i2BoardPtrTable[i];
3083 if( pB ) {
3084 switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED )
3085 {
3086 case POR_ID_FIIEX:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003087 seq_printf(m, "Board %d: EX ports=", i);
3088 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 for( box = 0; box < ABS_MAX_BOXES; ++box )
3090 {
3091 ports = 0;
3092
3093 if( pB->i2eChannelMap[box] != 0 ) ++boxes;
3094 for( j = 0; j < ABS_BIGGEST_BOX; ++j )
3095 {
3096 if( pB->i2eChannelMap[box] & 1<< j ) {
3097 ++ports;
3098 }
3099 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003100 seq_printf(m, "%s%d", sep, ports);
3101 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 tports += ports;
3103 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003104 seq_printf(m, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 break;
3106
3107 case POR_ID_II_4:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003108 seq_printf(m, "Board %d: ISA-4 ports=4 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 tports = ports = 4;
3110 break;
3111
3112 case POR_ID_II_8:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003113 seq_printf(m, "Board %d: ISA-8-std ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 tports = ports = 8;
3115 break;
3116
3117 case POR_ID_II_8R:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003118 seq_printf(m, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 tports = ports = 8;
3120 break;
3121
3122 default:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003123 seq_printf(m, "Board %d: unknown", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 /* Don't try and probe for minor numbers */
3125 tports = ports = 0;
3126 }
3127
3128 } else {
3129 /* Don't try and probe for minor numbers */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003130 seq_printf(m, "Board %d: vacant", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 tports = ports = 0;
3132 }
3133
3134 if( tports ) {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003135 seq_puts(m, " minors=");
3136 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 for ( box = 0; box < ABS_MAX_BOXES; ++box )
3138 {
3139 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
3140 {
3141 if ( pB->i2eChannelMap[box] & (1 << j) )
3142 {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003143 seq_printf(m, "%s%d", sep,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 j + ABS_BIGGEST_BOX *
3145 (box+i*ABS_MAX_BOXES));
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003146 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 }
3148 }
3149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003151 seq_putc(m, '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003153 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003155
3156static int ip2_proc_open(struct inode *inode, struct file *file)
3157{
3158 return single_open(file, ip2_proc_show, NULL);
3159}
3160
3161static const struct file_operations ip2_proc_fops = {
3162 .owner = THIS_MODULE,
3163 .open = ip2_proc_open,
3164 .read = seq_read,
3165 .llseek = seq_lseek,
3166 .release = single_release,
3167};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
3169/******************************************************************************/
3170/* Function: ip2trace() */
3171/* Parameters: Value to add to trace buffer */
3172/* Returns: Nothing */
3173/* */
3174/* Description: */
3175/* */
3176/* */
3177/******************************************************************************/
3178#ifdef IP2DEBUG_TRACE
3179void
3180ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
3181{
3182 long flags;
3183 unsigned long *pCode = &codes;
3184 union ip2breadcrumb bc;
3185 i2ChanStrPtr pCh;
3186
3187
3188 tracebuf[tracestuff++] = jiffies;
3189 if ( tracestuff == TRACEMAX ) {
3190 tracestuff = 0;
3191 }
3192 if ( tracestuff == tracestrip ) {
3193 if ( ++tracestrip == TRACEMAX ) {
3194 tracestrip = 0;
3195 }
3196 ++tracewrap;
3197 }
3198
3199 bc.hdr.port = 0xff & pn;
3200 bc.hdr.cat = cat;
3201 bc.hdr.codes = (unsigned char)( codes & 0xff );
3202 bc.hdr.label = label;
3203 tracebuf[tracestuff++] = bc.value;
3204
3205 for (;;) {
3206 if ( tracestuff == TRACEMAX ) {
3207 tracestuff = 0;
3208 }
3209 if ( tracestuff == tracestrip ) {
3210 if ( ++tracestrip == TRACEMAX ) {
3211 tracestrip = 0;
3212 }
3213 ++tracewrap;
3214 }
3215
3216 if ( !codes-- )
3217 break;
3218
3219 tracebuf[tracestuff++] = *++pCode;
3220 }
3221}
3222#endif
3223
3224
3225MODULE_LICENSE("GPL");
Chuck Shorteb0e71c2006-07-10 04:43:59 -07003226
Namhyung Kim53139e32010-12-07 23:27:43 +09003227static struct pci_device_id ip2main_pci_tbl[] __devinitdata __used = {
Chuck Shorteb0e71c2006-07-10 04:43:59 -07003228 { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
3229 { }
3230};
3231
3232MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);
Ben Hutchingse6c4ef92010-01-13 23:34:18 +00003233
3234MODULE_FIRMWARE("intelliport2.bin");