blob: 2e49e515d8e7037b5dd2edbca23db380db58717a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2*
3* (c) 1999 by Computone Corporation
4*
5********************************************************************************
6*
7* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
8* serial I/O controllers.
9*
10* DESCRIPTION: Mainline code for the device driver
11*
12*******************************************************************************/
13// ToDo:
14//
15// Fix the immediate DSS_NOW problem.
16// Work over the channel stats return logic in ip2_ipl_ioctl so they
17// make sense for all 256 possible channels and so the user space
18// utilities will compile and work properly.
19//
20// Done:
21//
22// 1.2.14 /\/\|=mhw=|\/\/
23// Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts.
24// Changed the definition of ip2trace to be more consistent with kernel style
25// Thanks to Andreas Dilger <adilger@turbolabs.com> for these updates
26//
27// 1.2.13 /\/\|=mhw=|\/\/
28// DEVFS: Renamed ttf/{n} to tts/F{n} and cuf/{n} to cua/F{n} to conform
29// to agreed devfs serial device naming convention.
30//
31// 1.2.12 /\/\|=mhw=|\/\/
32// Cleaned up some remove queue cut and paste errors
33//
34// 1.2.11 /\/\|=mhw=|\/\/
35// Clean up potential NULL pointer dereferences
36// Clean up devfs registration
37// Add kernel command line parsing for io and irq
Adrian Bunk9c4b5622006-01-19 18:07:10 +010038// Compile defaults for io and irq are now set in ip2.c not ip2.h!
Linus Torvalds1da177e2005-04-16 15:20:36 -070039// Reworked poll_only hack for explicit parameter setting
40// You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
41// Merged ip2_loadmain and old_ip2_init
42// Converted all instances of interruptible_sleep_on into queue calls
43// Most of these had no race conditions but better to clean up now
44//
45// 1.2.10 /\/\|=mhw=|\/\/
46// Fixed the bottom half interrupt handler and enabled USE_IQI
47// to split the interrupt handler into a formal top-half / bottom-half
48// Fixed timing window on high speed processors that queued messages to
49// the outbound mail fifo faster than the board could handle.
50//
51// 1.2.9
52// Four box EX was barfing on >128k kmalloc, made structure smaller by
53// reducing output buffer size
54//
55// 1.2.8
56// Device file system support (MHW)
57//
58// 1.2.7
59// Fixed
60// Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules
61//
62// 1.2.6
63//Fixes DCD problems
64// DCD was not reported when CLOCAL was set on call to TIOCMGET
65//
66//Enhancements:
67// TIOCMGET requests and waits for status return
68// No DSS interrupts enabled except for DCD when needed
69//
70// For internal use only
71//
72//#define IP2DEBUG_INIT
73//#define IP2DEBUG_OPEN
74//#define IP2DEBUG_WRITE
75//#define IP2DEBUG_READ
76//#define IP2DEBUG_IOCTL
77//#define IP2DEBUG_IPL
78
79//#define IP2DEBUG_TRACE
80//#define DEBUG_FIFO
81
82/************/
83/* Includes */
84/************/
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86#include <linux/ctype.h>
87#include <linux/string.h>
88#include <linux/fcntl.h>
89#include <linux/errno.h>
90#include <linux/module.h>
91#include <linux/signal.h>
92#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070093#include <linux/timer.h>
94#include <linux/interrupt.h>
95#include <linux/pci.h>
96#include <linux/mm.h>
97#include <linux/slab.h>
98#include <linux/major.h>
99#include <linux/wait.h>
100#include <linux/device.h>
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600101#include <linux/smp_lock.h>
David Woodhouse547d8bb2008-06-11 16:57:21 +0100102#include <linux/firmware.h>
103#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105#include <linux/tty.h>
106#include <linux/tty_flip.h>
107#include <linux/termios.h>
108#include <linux/tty_driver.h>
109#include <linux/serial.h>
110#include <linux/ptrace.h>
111#include <linux/ioport.h>
112
113#include <linux/cdk.h>
114#include <linux/comstats.h>
115#include <linux/delay.h>
116#include <linux/bitops.h>
117
118#include <asm/system.h>
119#include <asm/io.h>
120#include <asm/irq.h>
121
122#include <linux/vmalloc.h>
123#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125#include <asm/uaccess.h>
126
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100127#include "ip2types.h"
128#include "ip2trace.h"
129#include "ip2ioctl.h"
130#include "ip2.h"
131#include "i2ellis.h"
132#include "i2lib.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134/*****************
135 * /proc/ip2mem *
136 *****************/
137
138#include <linux/proc_fs.h>
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700139#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700141static const struct file_operations ip2mem_proc_fops;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700142static const struct file_operations ip2_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144/********************/
145/* Type Definitions */
146/********************/
147
148/*************/
149/* Constants */
150/*************/
151
152/* String constants to identify ourselves */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100153static const char pcName[] = "Computone IntelliPort Plus multiport driver";
154static const char pcVersion[] = "1.2.14";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156/* String constants for port names */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100157static const char pcDriver_name[] = "ip2";
158static const char pcIpl[] = "ip2ipl";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160/***********************/
161/* Function Prototypes */
162/***********************/
163
164/* Global module entry functions */
165
166/* Private (static) functions */
167static int ip2_open(PTTY, struct file *);
168static void ip2_close(PTTY, struct file *);
Alan Coxd9e39532006-01-09 20:54:20 -0800169static int ip2_write(PTTY, const unsigned char *, int);
Alan Coxf34d7a52008-04-30 00:54:13 -0700170static int ip2_putchar(PTTY, unsigned char);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static void ip2_flush_chars(PTTY);
172static int ip2_write_room(PTTY);
173static int ip2_chars_in_buf(PTTY);
174static void ip2_flush_buffer(PTTY);
175static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);
Alan Cox606d0992006-12-08 02:38:45 -0800176static void ip2_set_termios(PTTY, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177static void ip2_set_line_discipline(PTTY);
178static void ip2_throttle(PTTY);
179static void ip2_unthrottle(PTTY);
180static void ip2_stop(PTTY);
181static void ip2_start(PTTY);
182static void ip2_hangup(PTTY);
183static int ip2_tiocmget(struct tty_struct *tty, struct file *file);
184static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
185 unsigned int set, unsigned int clear);
186
187static void set_irq(int, int);
David Howellsc4028952006-11-22 14:57:56 +0000188static void ip2_interrupt_bh(struct work_struct *work);
David Howells7d12e782006-10-05 14:55:46 +0100189static irqreturn_t ip2_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void ip2_poll(unsigned long arg);
191static inline void service_all_boards(void);
David Howellsc4028952006-11-22 14:57:56 +0000192static void do_input(struct work_struct *);
193static void do_status(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195static void ip2_wait_until_sent(PTTY,int);
196
Alan Cox606d0992006-12-08 02:38:45 -0800197static void set_params (i2ChanStrPtr, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *);
199static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *);
200
201static ssize_t ip2_ipl_read(struct file *, char __user *, size_t, loff_t *);
202static ssize_t ip2_ipl_write(struct file *, const char __user *, size_t, loff_t *);
Alan Cox47be36a2008-07-25 01:48:13 -0700203static long ip2_ipl_ioctl(struct file *, UINT, ULONG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static int ip2_ipl_open(struct inode *, struct file *);
205
206static int DumpTraceBuffer(char __user *, int);
207static int DumpFifoBuffer( char __user *, int);
208
David Woodhouse547d8bb2008-06-11 16:57:21 +0100209static void ip2_init_board(int, const struct firmware *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210static unsigned short find_eisa_board(int);
Rakib Mullick02c95a62010-01-23 18:53:51 +0600211static int ip2_setup(char *str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213/***************/
214/* Static Data */
215/***************/
216
217static struct tty_driver *ip2_tty_driver;
218
219/* Here, then is a table of board pointers which the interrupt routine should
220 * scan through to determine who it must service.
221 */
222static unsigned short i2nBoards; // Number of boards here
223
224static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS];
225
226static i2ChanStrPtr DevTable[IP2_MAX_PORTS];
227//DevTableMem just used to save addresses for kfree
228static void *DevTableMem[IP2_MAX_BOARDS];
229
230/* This is the driver descriptor for the ip2ipl device, which is used to
231 * download the loadware to the boards.
232 */
Arjan van de Ven62322d22006-07-03 00:24:21 -0700233static const struct file_operations ip2_ipl = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 .owner = THIS_MODULE,
235 .read = ip2_ipl_read,
236 .write = ip2_ipl_write,
Alan Cox47be36a2008-07-25 01:48:13 -0700237 .unlocked_ioctl = ip2_ipl_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 .open = ip2_ipl_open,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200239 .llseek = noop_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240};
241
Jiri Slabycf176bc2008-10-13 10:34:36 +0100242static unsigned long irq_counter;
243static unsigned long bh_counter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
245// Use immediate queue to service interrupts
246#define USE_IQI
247//#define USE_IQ // PCI&2.2 needs work
248
249/* The timer_list entry for our poll routine. If interrupt operation is not
250 * selected, the board is serviced periodically to see if anything needs doing.
251 */
252#define POLL_TIMEOUT (jiffies + 1)
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700253static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255#ifdef IP2DEBUG_TRACE
256/* Trace (debug) buffer data */
257#define TRACEMAX 1000
258static unsigned long tracebuf[TRACEMAX];
259static int tracestuff;
260static int tracestrip;
261static int tracewrap;
262#endif
263
264/**********/
265/* Macros */
266/**********/
267
Rakib Mullick795877c2009-12-09 12:34:18 -0800268#ifdef IP2DEBUG_OPEN
Alan Cox7d7b93c2008-10-13 10:42:09 +0100269#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
270 tty->name,(pCh->flags), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 tty->count,/*GET_USE_COUNT(module)*/0,s)
272#else
273#define DBG_CNT(s)
274#endif
275
276/********/
277/* Code */
278/********/
279
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100280#include "i2ellis.c" /* Extremely low-level interface services */
281#include "i2cmd.c" /* Standard loadware command definitions */
282#include "i2lib.c" /* High level interface services */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
284/* Configuration area for modprobe */
285
286MODULE_AUTHOR("Doug McNash");
287MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
Jiri Slaby47babd42008-10-13 10:34:27 +0100288MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Rakib Mullick02c95a62010-01-23 18:53:51 +0600290#define MAX_CMD_STR 50
291
Jiri Slabycf176bc2008-10-13 10:34:36 +0100292static int poll_only;
Rakib Mullick02c95a62010-01-23 18:53:51 +0600293static char cmd[MAX_CMD_STR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295static int Eisa_irq;
296static int Eisa_slot;
297
298static int iindx;
299static char rirqs[IP2_MAX_BOARDS];
300static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
301
Jiri Slaby47babd42008-10-13 10:34:27 +0100302/* Note: Add compiled in defaults to these arrays, not to the structure
303 in ip2.h any longer. That structure WILL get overridden
304 by these values, or command line values, or insmod values!!! =mhw=
305*/
306static int io[IP2_MAX_BOARDS];
307static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
308
309MODULE_AUTHOR("Doug McNash");
310MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
311module_param_array(irq, int, NULL, 0);
312MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
313module_param_array(io, int, NULL, 0);
314MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
315module_param(poll_only, bool, 0);
316MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
Rakib Mullick02c95a62010-01-23 18:53:51 +0600317module_param_string(ip2, cmd, MAX_CMD_STR, 0);
318MODULE_PARM_DESC(ip2, "Contains module parameter passed with 'ip2='");
Jiri Slaby47babd42008-10-13 10:34:27 +0100319
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320/* for sysfs class support */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800321static struct class *ip2_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100323/* Some functions to keep track of what irqs we have */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100325static int __init is_valid_irq(int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
327 int *i = Valid_Irqs;
328
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100329 while (*i != 0 && *i != irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 i++;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100331
332 return *i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333}
334
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100335static void __init mark_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
337 rirqs[iindx++] = irq;
338}
339
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100340static int __exit clear_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100343 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 if (rirqs[i] == irq) {
345 rirqs[i] = 0;
346 return 1;
347 }
348 }
349 return 0;
350}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100352static int have_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100354 /* array init to zeros so 0 irq will not be requested as a side
355 * effect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100357 for (i = 0; i < IP2_MAX_BOARDS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 if (rirqs[i] == irq)
359 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 return 0;
361}
362
363/******************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364/* Function: cleanup_module() */
365/* Parameters: None */
366/* Returns: Nothing */
367/* */
368/* Description: */
369/* This is a required entry point for an installable module. It has to return */
370/* the device and the driver to a passive state. It should not be necessary */
371/* to reset the board fully, especially as the loadware is downloaded */
372/* externally rather than in the driver. We just want to disable the board */
373/* and clear the loadware to a reset state. To allow this there has to be a */
374/* way to detect whether the board has the loadware running at init time to */
375/* handle subsequent installations of the driver. All memory allocated by the */
376/* driver should be returned since it may be unloaded from memory. */
377/******************************************************************************/
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100378static void __exit ip2_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380 int err;
381 int i;
382
Akinobu Mita9d020a22008-10-13 10:35:05 +0100383 del_timer_sync(&PollTimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 /* Reset the boards we have. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100386 for (i = 0; i < IP2_MAX_BOARDS; i++)
387 if (i2BoardPtrTable[i])
388 iiReset(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390 /* The following is done at most once, if any boards were installed. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100391 for (i = 0; i < IP2_MAX_BOARDS; i++) {
392 if (i2BoardPtrTable[i]) {
393 iiResetDelay(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 /* free io addresses and Tibet */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100395 release_region(ip2config.addr[i], 8);
tonyj@suse.de07c015e2007-08-07 22:28:44 -0700396 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100397 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
398 4 * i + 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 }
400 /* Disable and remove interrupt handler. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100401 if (ip2config.irq[i] > 0 &&
402 have_requested_irq(ip2config.irq[i])) {
403 free_irq(ip2config.irq[i], (void *)&pcName);
404 clear_requested_irq(ip2config.irq[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 }
406 }
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800407 class_destroy(ip2_class);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100408 err = tty_unregister_driver(ip2_tty_driver);
409 if (err)
410 printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
411 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 put_tty_driver(ip2_tty_driver);
Akinobu Mita68fc4fa2007-07-19 01:47:50 -0700413 unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
Alexey Dobriyanc74c1202008-04-29 01:01:44 -0700414 remove_proc_entry("ip2mem", NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100416 /* free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 for (i = 0; i < IP2_MAX_BOARDS; i++) {
418 void *pB;
419#ifdef CONFIG_PCI
420 if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
421 pci_disable_device(ip2config.pci_dev[i]);
Alan Cox1aff0ec2006-09-30 23:27:59 -0700422 pci_dev_put(ip2config.pci_dev[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 ip2config.pci_dev[i] = NULL;
424 }
425#endif
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100426 pB = i2BoardPtrTable[i];
427 if (pB != NULL) {
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100428 kfree(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 i2BoardPtrTable[i] = NULL;
430 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100431 if (DevTableMem[i] != NULL) {
432 kfree(DevTableMem[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 DevTableMem[i] = NULL;
434 }
435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436}
Jon Schindler83e422b2008-04-30 00:53:53 -0700437module_exit(ip2_cleanup_module);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700439static const struct tty_operations ip2_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 .open = ip2_open,
441 .close = ip2_close,
442 .write = ip2_write,
443 .put_char = ip2_putchar,
444 .flush_chars = ip2_flush_chars,
445 .write_room = ip2_write_room,
446 .chars_in_buffer = ip2_chars_in_buf,
447 .flush_buffer = ip2_flush_buffer,
448 .ioctl = ip2_ioctl,
449 .throttle = ip2_throttle,
450 .unthrottle = ip2_unthrottle,
451 .set_termios = ip2_set_termios,
452 .set_ldisc = ip2_set_line_discipline,
453 .stop = ip2_stop,
454 .start = ip2_start,
455 .hangup = ip2_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 .tiocmget = ip2_tiocmget,
457 .tiocmset = ip2_tiocmset,
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700458 .proc_fops = &ip2_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459};
460
461/******************************************************************************/
462/* Function: ip2_loadmain() */
463/* Parameters: irq, io from command line of insmod et. al. */
464/* pointer to fip firmware and firmware size for boards */
465/* Returns: Success (0) */
466/* */
467/* Description: */
468/* This was the required entry point for all drivers (now in ip2.c) */
469/* It performs all */
470/* initialisation of the devices and driver structures, and registers itself */
471/* with the relevant kernel modules. */
472/******************************************************************************/
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700473/* IRQF_DISABLED - if set blocks all interrupts else only this line */
474/* IRQF_SHARED - for shared irq PCI or maybe EISA only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475/* SA_RANDOM - can be source for cert. random number generators */
476#define IP2_SA_FLAGS 0
477
David Woodhouse547d8bb2008-06-11 16:57:21 +0100478
479static const struct firmware *ip2_request_firmware(void)
480{
481 struct platform_device *pdev;
482 const struct firmware *fw;
483
484 pdev = platform_device_register_simple("ip2", 0, NULL, 0);
485 if (IS_ERR(pdev)) {
486 printk(KERN_ERR "Failed to register platform device for ip2\n");
487 return NULL;
488 }
489 if (request_firmware(&fw, "intelliport2.bin", &pdev->dev)) {
490 printk(KERN_ERR "Failed to load firmware 'intelliport2.bin'\n");
491 fw = NULL;
492 }
493 platform_device_unregister(pdev);
494 return fw;
495}
496
Jiri Slaby47babd42008-10-13 10:34:27 +0100497/******************************************************************************
498 * ip2_setup:
499 * str: kernel command line string
500 *
501 * Can't autoprobe the boards so user must specify configuration on
502 * kernel command line. Sane people build it modular but the others
503 * come here.
504 *
505 * Alternating pairs of io,irq for up to 4 boards.
506 * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
507 *
508 * io=0 => No board
509 * io=1 => PCI
510 * io=2 => EISA
511 * else => ISA I/O address
512 *
513 * irq=0 or invalid for ISA will revert to polling mode
514 *
515 * Any value = -1, do not overwrite compiled in value.
516 *
517 ******************************************************************************/
518static int __init ip2_setup(char *str)
519{
520 int j, ints[10]; /* 4 boards, 2 parameters + 2 */
521 unsigned int i;
522
523 str = get_options(str, ARRAY_SIZE(ints), ints);
524
525 for (i = 0, j = 1; i < 4; i++) {
526 if (j > ints[0])
527 break;
528 if (ints[j] >= 0)
529 io[i] = ints[j];
530 j++;
531 if (j > ints[0])
532 break;
533 if (ints[j] >= 0)
534 irq[i] = ints[j];
535 j++;
536 }
537 return 1;
538}
539__setup("ip2=", ip2_setup);
Jiri Slaby47babd42008-10-13 10:34:27 +0100540
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100541static int __init ip2_loadmain(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
543 int i, j, box;
544 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 i2eBordStrPtr pB = NULL;
546 int rc = -1;
David Woodhouse547d8bb2008-06-11 16:57:21 +0100547 const struct firmware *fw = NULL;
Rakib Mullick02c95a62010-01-23 18:53:51 +0600548 char *str;
549
550 str = cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Jiri Slaby47babd42008-10-13 10:34:27 +0100552 if (poll_only) {
553 /* Hard lock the interrupts to zero */
554 irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
555 }
556
Rakib Mullick02c95a62010-01-23 18:53:51 +0600557 /* Check module parameter with 'ip2=' has been passed or not */
558 if (!poll_only && (!strncmp(str, "ip2=", 4)))
559 ip2_setup(str);
560
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100561 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 /* process command line arguments to modprobe or
564 insmod i.e. iop & irqp */
565 /* irqp and iop should ALWAYS be specified now... But we check
566 them individually just to be sure, anyways... */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100567 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Jiri Slaby47babd42008-10-13 10:34:27 +0100568 ip2config.addr[i] = io[i];
569 if (irq[i] >= 0)
570 ip2config.irq[i] = irq[i];
571 else
572 ip2config.irq[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100573 /* This is a little bit of a hack. If poll_only=1 on command
574 line back in ip2.c OR all IRQs on all specified boards are
575 explicitly set to 0, then drop to poll only mode and override
576 PCI or EISA interrupts. This superceeds the old hack of
577 triggering if all interrupts were zero (like da default).
578 Still a hack but less prone to random acts of terrorism.
579
580 What we really should do, now that the IRQ default is set
581 to -1, is to use 0 as a hard coded, do not probe.
582
583 /\/\|=mhw=|\/\/
584 */
Jiri Slaby47babd42008-10-13 10:34:27 +0100585 poll_only |= irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 }
587 poll_only = !poll_only;
588
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 /* Announce our presence */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100590 printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
592 ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
593 if (!ip2_tty_driver)
594 return -ENOMEM;
595
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 /* Initialise all the boards we can find (up to the maximum). */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100597 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
598 switch (ip2config.addr[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 case 0: /* skip this slot even if card is present */
600 break;
601 default: /* ISA */
602 /* ISA address must be specified */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100603 if (ip2config.addr[i] < 0x100 ||
604 ip2config.addr[i] > 0x3f8) {
605 printk(KERN_ERR "IP2: Bad ISA board %d "
606 "address %x\n", i,
607 ip2config.addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 ip2config.addr[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100609 break;
610 }
611 ip2config.type[i] = ISA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100613 /* Check for valid irq argument, set for polling if
614 * invalid */
615 if (ip2config.irq[i] &&
616 !is_valid_irq(ip2config.irq[i])) {
617 printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
618 ip2config.irq[i]);
619 /* 0 is polling and is valid in that sense */
620 ip2config.irq[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 }
622 break;
623 case PCI:
624#ifdef CONFIG_PCI
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100625 {
Rakib Mullick795877c2009-12-09 12:34:18 -0800626 struct pci_dev *pdev = NULL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100627 u32 addr;
628 int status;
Andrew Mortonad4a5bb2007-07-31 00:39:41 -0700629
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100630 pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
631 PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
632 if (pdev == NULL) {
633 ip2config.addr[i] = 0;
634 printk(KERN_ERR "IP2: PCI board %d not "
635 "found\n", i);
636 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100638
639 if (pci_enable_device(pdev)) {
640 dev_err(&pdev->dev, "can't enable device\n");
Rakib Mullick795877c2009-12-09 12:34:18 -0800641 goto out;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100642 }
643 ip2config.type[i] = PCI;
644 ip2config.pci_dev[i] = pci_dev_get(pdev);
645 status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
646 &addr);
647 if (addr & 1)
648 ip2config.addr[i] = (USHORT)(addr & 0xfffe);
649 else
650 dev_err(&pdev->dev, "I/O address error\n");
651
652 ip2config.irq[i] = pdev->irq;
Rakib Mullick795877c2009-12-09 12:34:18 -0800653out:
654 pci_dev_put(pdev);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656#else
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100657 printk(KERN_ERR "IP2: PCI card specified but PCI "
658 "support not enabled.\n");
659 printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
660 "defined!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661#endif /* CONFIG_PCI */
662 break;
663 case EISA:
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100664 ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
665 if (ip2config.addr[i] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 /* Eisa_irq set as side effect, boo */
667 ip2config.type[i] = EISA;
668 }
669 ip2config.irq[i] = Eisa_irq;
670 break;
671 } /* switch */
672 } /* for */
Alan Cox1aff0ec2006-09-30 23:27:59 -0700673
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100674 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
675 if (ip2config.addr[i]) {
Mariusz Kozlowski978550b2007-10-16 23:26:45 -0700676 pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
677 if (pB) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 i2BoardPtrTable[i] = pB;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100679 iiSetAddress(pB, ip2config.addr[i],
680 ii2DelayTimer);
681 iiReset(pB);
682 } else
683 printk(KERN_ERR "IP2: board memory allocation "
684 "error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 }
686 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100687 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
688 pB = i2BoardPtrTable[i];
689 if (pB != NULL) {
690 iiResetDelay(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 break;
692 }
693 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100694 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100695 /* We don't want to request the firmware unless we have at
696 least one board */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100697 if (i2BoardPtrTable[i] != NULL) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100698 if (!fw)
699 fw = ip2_request_firmware();
700 if (!fw)
701 break;
702 ip2_init_board(i, fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 }
704 }
David Woodhouse547d8bb2008-06-11 16:57:21 +0100705 if (fw)
706 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100708 ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 ip2_tty_driver->owner = THIS_MODULE;
711 ip2_tty_driver->name = "ttyF";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 ip2_tty_driver->driver_name = pcDriver_name;
713 ip2_tty_driver->major = IP2_TTY_MAJOR;
714 ip2_tty_driver->minor_start = 0;
715 ip2_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
716 ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL;
717 ip2_tty_driver->init_termios = tty_std_termios;
718 ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100719 ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW |
720 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 tty_set_operations(ip2_tty_driver, &ip2_ops);
722
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100723 ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100725 err = tty_register_driver(ip2_tty_driver);
726 if (err) {
727 printk(KERN_ERR "IP2: failed to register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 put_tty_driver(ip2_tty_driver);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100729 return err; /* leaking resources */
730 }
731
732 err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
733 if (err) {
734 printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
735 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 } else {
737 /* create the sysfs class */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800738 ip2_class = class_create(THIS_MODULE, "ip2");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 if (IS_ERR(ip2_class)) {
740 err = PTR_ERR(ip2_class);
741 goto out_chrdev;
742 }
743 }
744 /* Register the read_procmem thing */
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700745 if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 printk(KERN_ERR "IP2: failed to register read_procmem\n");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100747 return -EIO; /* leaking resources */
748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100750 ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
751 /* Register the interrupt handler or poll handler, depending upon the
752 * specified interrupt.
753 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100755 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
756 if (ip2config.addr[i] == 0)
757 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100759 pB = i2BoardPtrTable[i];
760 if (pB != NULL) {
Greg Kroah-Hartman03457cd2008-07-21 20:03:34 -0700761 device_create(ip2_class, NULL,
762 MKDEV(IP2_IPL_MAJOR, 4 * i),
763 NULL, "ipl%d", i);
764 device_create(ip2_class, NULL,
765 MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
766 NULL, "stat%d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100768 for (box = 0; box < ABS_MAX_BOXES; box++)
769 for (j = 0; j < ABS_BIGGEST_BOX; j++)
770 if (pB->i2eChannelMap[box] & (1 << j))
771 tty_register_device(
772 ip2_tty_driver,
773 j + ABS_BIGGEST_BOX *
774 (box+i*ABS_MAX_BOXES),
775 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100777
778 if (poll_only) {
779 /* Poll only forces driver to only use polling and
780 to ignore the probed PCI or EISA interrupts. */
781 ip2config.irq[i] = CIR_POLL;
782 }
783 if (ip2config.irq[i] == CIR_POLL) {
784retry:
Akinobu Mita9d020a22008-10-13 10:35:05 +0100785 if (!timer_pending(&PollTimer)) {
786 mod_timer(&PollTimer, POLL_TIMEOUT);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100787 printk(KERN_INFO "IP2: polling\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100789 } else {
790 if (have_requested_irq(ip2config.irq[i]))
791 continue;
792 rc = request_irq(ip2config.irq[i], ip2_interrupt,
793 IP2_SA_FLAGS |
794 (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
795 pcName, i2BoardPtrTable[i]);
796 if (rc) {
797 printk(KERN_ERR "IP2: request_irq failed: "
798 "error %d\n", rc);
799 ip2config.irq[i] = CIR_POLL;
800 printk(KERN_INFO "IP2: Polling %ld/sec.\n",
801 (POLL_TIMEOUT - jiffies));
802 goto retry;
803 }
804 mark_requested_irq(ip2config.irq[i]);
805 /* Initialise the interrupt handler bottom half
806 * (aka slih). */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 }
808 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100809
810 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
811 if (i2BoardPtrTable[i]) {
812 /* set and enable board interrupt */
813 set_irq(i, ip2config.irq[i]);
814 }
815 }
816
817 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
818
819 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821out_chrdev:
822 unregister_chrdev(IP2_IPL_MAJOR, "ip2");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100823 /* unregister and put tty here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return err;
825}
Jiri Slaby47babd42008-10-13 10:34:27 +0100826module_init(ip2_loadmain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828/******************************************************************************/
829/* Function: ip2_init_board() */
830/* Parameters: Index of board in configuration structure */
831/* Returns: Success (0) */
832/* */
833/* Description: */
834/* This function initializes the specified board. The loadware is copied to */
835/* the board, the channel structures are initialized, and the board details */
836/* are reported on the console. */
837/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700838static void
David Woodhouse547d8bb2008-06-11 16:57:21 +0100839ip2_init_board(int boardnum, const struct firmware *fw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840{
841 int i;
842 int nports = 0, nboxes = 0;
843 i2ChanStrPtr pCh;
844 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
845
846 if ( !iiInitialize ( pB ) ) {
847 printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
848 pB->i2eBase, pB->i2eError );
849 goto err_initialize;
850 }
851 printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
852 ip2config.addr[boardnum], ip2config.irq[boardnum] );
853
854 if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
855 printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
856 goto err_initialize;
857 }
858
David Woodhouse547d8bb2008-06-11 16:57:21 +0100859 if ( iiDownloadAll ( pB, (loadHdrStrPtr)fw->data, 1, fw->size )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 != II_DOWN_GOOD ) {
861 printk ( KERN_ERR "IP2: failed to download loadware\n" );
862 goto err_release_region;
863 } else {
864 printk ( KERN_INFO "IP2: fv=%d.%d.%d lv=%d.%d.%d\n",
865 pB->i2ePom.e.porVersion,
866 pB->i2ePom.e.porRevision,
867 pB->i2ePom.e.porSubRev, pB->i2eLVersion,
868 pB->i2eLRevision, pB->i2eLSub );
869 }
870
871 switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
872
873 default:
874 printk( KERN_ERR "IP2: Unknown board type, ID = %x\n",
875 pB->i2ePom.e.porID );
876 nports = 0;
877 goto err_release_region;
878 break;
879
880 case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
881 printk ( KERN_INFO "IP2: ISA-4\n" );
882 nports = 4;
883 break;
884
885 case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
886 printk ( KERN_INFO "IP2: ISA-8 std\n" );
887 nports = 8;
888 break;
889
890 case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
891 printk ( KERN_INFO "IP2: ISA-8 RJ11\n" );
892 nports = 8;
893 break;
894
895 case POR_ID_FIIEX: /* IntelliPort IIEX */
896 {
897 int portnum = IP2_PORTS_PER_BOARD * boardnum;
898 int box;
899
900 for( box = 0; box < ABS_MAX_BOXES; ++box ) {
901 if ( pB->i2eChannelMap[box] != 0 ) {
902 ++nboxes;
903 }
904 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
905 if ( pB->i2eChannelMap[box] & 1<< i ) {
906 ++nports;
907 }
908 }
909 }
910 DevTableMem[boardnum] = pCh =
911 kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
912 if ( !pCh ) {
913 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
914 goto err_release_region;
915 }
916 if ( !i2InitChannels( pB, nports, pCh ) ) {
917 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
918 kfree ( pCh );
919 goto err_release_region;
920 }
921 pB->i2eChannelPtr = &DevTable[portnum];
922 pB->i2eChannelCnt = ABS_MOST_PORTS;
923
924 for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
925 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
926 if ( pB->i2eChannelMap[box] & (1 << i) ) {
927 DevTable[portnum + i] = pCh;
928 pCh->port_index = portnum + i;
929 pCh++;
930 }
931 }
932 }
933 printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit\n",
934 nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
935 }
936 goto ex_exit;
937 }
938 DevTableMem[boardnum] = pCh =
939 kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
940 if ( !pCh ) {
941 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
942 goto err_release_region;
943 }
944 pB->i2eChannelPtr = pCh;
945 pB->i2eChannelCnt = nports;
946 if ( !i2InitChannels( pB, nports, pCh ) ) {
947 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
948 kfree ( pCh );
949 goto err_release_region;
950 }
951 pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
952
953 for( i = 0; i < pB->i2eChannelCnt; ++i ) {
954 DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
955 pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
956 pCh++;
957 }
958ex_exit:
David Howellsc4028952006-11-22 14:57:56 +0000959 INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 return;
961
962err_release_region:
963 release_region(ip2config.addr[boardnum], 8);
964err_initialize:
965 kfree ( pB );
966 i2BoardPtrTable[boardnum] = NULL;
967 return;
968}
969
970/******************************************************************************/
971/* Function: find_eisa_board ( int start_slot ) */
972/* Parameters: First slot to check */
973/* Returns: Address of EISA IntelliPort II controller */
974/* */
975/* Description: */
976/* This function searches for an EISA IntelliPort controller, starting */
977/* from the specified slot number. If the motherboard is not identified as an */
978/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
979/* it returns the base address of the controller. */
980/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700981static unsigned short
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982find_eisa_board( int start_slot )
983{
984 int i, j;
985 unsigned int idm = 0;
986 unsigned int idp = 0;
987 unsigned int base = 0;
988 unsigned int value;
989 int setup_address;
990 int setup_irq;
991 int ismine = 0;
992
993 /*
994 * First a check for an EISA motherboard, which we do by comparing the
995 * EISA ID registers for the system board and the first couple of slots.
996 * No slot ID should match the system board ID, but on an ISA or PCI
997 * machine the odds are that an empty bus will return similar values for
998 * each slot.
999 */
1000 i = 0x0c80;
1001 value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
1002 for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
1003 j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
1004 if ( value == j )
1005 return 0;
1006 }
1007
1008 /*
1009 * OK, so we are inclined to believe that this is an EISA machine. Find
1010 * an IntelliPort controller.
1011 */
1012 for( i = start_slot; i < 16; i++ ) {
1013 base = i << 12;
1014 idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
1015 idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
1016 ismine = 0;
1017 if ( idm == 0x0e8e ) {
1018 if ( idp == 0x0281 || idp == 0x0218 ) {
1019 ismine = 1;
1020 } else if ( idp == 0x0282 || idp == 0x0283 ) {
1021 ismine = 3; /* Can do edge-trigger */
1022 }
1023 if ( ismine ) {
1024 Eisa_slot = i;
1025 break;
1026 }
1027 }
1028 }
1029 if ( !ismine )
1030 return 0;
1031
1032 /* It's some sort of EISA card, but at what address is it configured? */
1033
1034 setup_address = base + 0xc88;
1035 value = inb(base + 0xc86);
1036 setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
1037
1038 if ( (ismine & 2) && !(value & 0x10) ) {
1039 ismine = 1; /* Could be edging, but not */
1040 }
1041
1042 if ( Eisa_irq == 0 ) {
1043 Eisa_irq = setup_irq;
1044 } else if ( Eisa_irq != setup_irq ) {
1045 printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
1046 }
1047
1048#ifdef IP2DEBUG_INIT
1049printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
1050 base >> 12, idm, idp, setup_address);
1051 if ( Eisa_irq ) {
1052 printk(KERN_DEBUG ", Interrupt %d %s\n",
1053 setup_irq, (ismine & 2) ? "(edge)" : "(level)");
1054 } else {
1055 printk(KERN_DEBUG ", (polled)\n");
1056 }
1057#endif
1058 return setup_address;
1059}
1060
1061/******************************************************************************/
1062/* Function: set_irq() */
1063/* Parameters: index to board in board table */
1064/* IRQ to use */
1065/* Returns: Success (0) */
1066/* */
1067/* Description: */
1068/******************************************************************************/
1069static void
1070set_irq( int boardnum, int boardIrq )
1071{
1072 unsigned char tempCommand[16];
1073 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
1074 unsigned long flags;
1075
1076 /*
1077 * Notify the boards they may generate interrupts. This is done by
1078 * sending an in-line command to channel 0 on each board. This is why
1079 * the channels have to be defined already. For each board, if the
1080 * interrupt has never been defined, we must do so NOW, directly, since
1081 * board will not send flow control or even give an interrupt until this
1082 * is done. If polling we must send 0 as the interrupt parameter.
1083 */
1084
1085 // We will get an interrupt here at the end of this function
1086
1087 iiDisableMailIrq(pB);
1088
1089 /* We build up the entire packet header. */
1090 CHANNEL_OF(tempCommand) = 0;
1091 PTYPE_OF(tempCommand) = PTYPE_INLINE;
1092 CMD_COUNT_OF(tempCommand) = 2;
1093 (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
1094 (CMD_OF(tempCommand))[1] = boardIrq;
1095 /*
1096 * Write to FIFO; don't bother to adjust fifo capacity for this, since
1097 * board will respond almost immediately after SendMail hit.
1098 */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001099 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001101 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 pB->i2eUsingIrq = boardIrq;
1103 pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
1104
1105 /* Need to update number of boards before you enable mailbox int */
1106 ++i2nBoards;
1107
1108 CHANNEL_OF(tempCommand) = 0;
1109 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1110 CMD_COUNT_OF(tempCommand) = 6;
1111 (CMD_OF(tempCommand))[0] = 88; // SILO
1112 (CMD_OF(tempCommand))[1] = 64; // chars
1113 (CMD_OF(tempCommand))[2] = 32; // ms
1114
1115 (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK
1116 (CMD_OF(tempCommand))[4] = 64; // chars
1117
1118 (CMD_OF(tempCommand))[5] = 87; // HW_TEST
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001119 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 iiWriteBuf(pB, tempCommand, 8);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001121 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123 CHANNEL_OF(tempCommand) = 0;
1124 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1125 CMD_COUNT_OF(tempCommand) = 1;
1126 (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */
1127 iiWriteBuf(pB, tempCommand, 3);
1128
1129#ifdef XXX
1130 // enable heartbeat for test porpoises
1131 CHANNEL_OF(tempCommand) = 0;
1132 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1133 CMD_COUNT_OF(tempCommand) = 2;
1134 (CMD_OF(tempCommand))[0] = 44; /* get ping */
1135 (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001136 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001138 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139#endif
1140
1141 iiEnableMailIrq(pB);
1142 iiSendPendingMail(pB);
1143}
1144
1145/******************************************************************************/
1146/* Interrupt Handler Section */
1147/******************************************************************************/
1148
1149static inline void
1150service_all_boards(void)
1151{
1152 int i;
1153 i2eBordStrPtr pB;
1154
1155 /* Service every board on the list */
1156 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
1157 pB = i2BoardPtrTable[i];
1158 if ( pB ) {
1159 i2ServiceBoard( pB );
1160 }
1161 }
1162}
1163
1164
1165/******************************************************************************/
David Howellsc4028952006-11-22 14:57:56 +00001166/* Function: ip2_interrupt_bh(work) */
1167/* Parameters: work - pointer to the board structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168/* Returns: Nothing */
1169/* */
1170/* Description: */
1171/* Service the board in a bottom half interrupt handler and then */
1172/* reenable the board's interrupts if it has an IRQ number */
1173/* */
1174/******************************************************************************/
1175static void
David Howellsc4028952006-11-22 14:57:56 +00001176ip2_interrupt_bh(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177{
David Howellsc4028952006-11-22 14:57:56 +00001178 i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179// pB better well be set or we have a problem! We can only get
1180// here from the IMMEDIATE queue. Here, we process the boards.
1181// Checking pB doesn't cost much and it saves us from the sanity checkers.
1182
1183 bh_counter++;
1184
1185 if ( pB ) {
1186 i2ServiceBoard( pB );
1187 if( pB->i2eUsingIrq ) {
1188// Re-enable his interrupts
1189 iiEnableMailIrq(pB);
1190 }
1191 }
1192}
1193
1194
1195/******************************************************************************/
David Howells7d12e782006-10-05 14:55:46 +01001196/* Function: ip2_interrupt(int irq, void *dev_id) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197/* Parameters: irq - interrupt number */
1198/* pointer to optional device ID structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199/* Returns: Nothing */
1200/* */
1201/* Description: */
1202/* */
1203/* Our task here is simply to identify each board which needs servicing. */
1204/* If we are queuing then, queue it to be serviced, and disable its irq */
1205/* mask otherwise process the board directly. */
1206/* */
1207/* We could queue by IRQ but that just complicates things on both ends */
1208/* with very little gain in performance (how many instructions does */
1209/* it take to iterate on the immediate queue). */
1210/* */
1211/* */
1212/******************************************************************************/
Jeff Garzikf3518e42007-10-19 15:24:59 -04001213static void
1214ip2_irq_work(i2eBordStrPtr pB)
1215{
1216#ifdef USE_IQI
1217 if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
1218// Disable his interrupt (will be enabled when serviced)
1219// This is mostly to protect from reentrancy.
1220 iiDisableMailIrq(pB);
1221
1222// Park the board on the immediate queue for processing.
1223 schedule_work(&pB->tqueue_interrupt);
1224
1225// Make sure the immediate queue is flagged to fire.
1226 }
1227#else
1228
1229// We are using immediate servicing here. This sucks and can
1230// cause all sorts of havoc with ppp and others. The failsafe
1231// check on iiSendPendingMail could also throw a hairball.
1232
1233 i2ServiceBoard( pB );
1234
1235#endif /* USE_IQI */
1236}
1237
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001238static void
1239ip2_polled_interrupt(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240{
1241 int i;
1242 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001244 ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
1246 /* Service just the boards on the list using this irq */
1247 for( i = 0; i < i2nBoards; ++i ) {
1248 pB = i2BoardPtrTable[i];
1249
1250// Only process those boards which match our IRQ.
1251// IRQ = 0 for polled boards, we won't poll "IRQ" boards
1252
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001253 if (pB && pB->i2eUsingIrq == 0)
Jeff Garzikf3518e42007-10-19 15:24:59 -04001254 ip2_irq_work(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 }
1256
1257 ++irq_counter;
1258
1259 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001260}
1261
1262static irqreturn_t
1263ip2_interrupt(int irq, void *dev_id)
1264{
1265 i2eBordStrPtr pB = dev_id;
1266
1267 ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, pB->i2eUsingIrq );
1268
1269 ip2_irq_work(pB);
1270
1271 ++irq_counter;
1272
1273 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1274 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275}
1276
1277/******************************************************************************/
1278/* Function: ip2_poll(unsigned long arg) */
1279/* Parameters: ? */
1280/* Returns: Nothing */
1281/* */
1282/* Description: */
1283/* This function calls the library routine i2ServiceBoard for each board in */
1284/* the board table. This is used instead of the interrupt routine when polled */
1285/* mode is specified. */
1286/******************************************************************************/
1287static void
1288ip2_poll(unsigned long arg)
1289{
1290 ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
1291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
1293 // It will NOT poll boards handled by hard interrupts.
Joe Perches8dfba4d2008-02-03 17:11:42 +02001294 // The issue of queued BH interrupts is handled in ip2_interrupt().
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001295 ip2_polled_interrupt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Akinobu Mita9d020a22008-10-13 10:35:05 +01001297 mod_timer(&PollTimer, POLL_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1300}
1301
David Howellsc4028952006-11-22 14:57:56 +00001302static void do_input(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303{
David Howellsc4028952006-11-22 14:57:56 +00001304 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 unsigned long flags;
1306
1307 ip2trace(CHANN, ITRC_INPUT, 21, 0 );
1308
1309 // Data input
1310 if ( pCh->pTTY != NULL ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001311 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001313 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 i2Input( pCh );
1315 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001316 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 } else {
1318 ip2trace(CHANN, ITRC_INPUT, 22, 0 );
1319
1320 i2InputFlush( pCh );
1321 }
1322}
1323
1324// code duplicated from n_tty (ldisc)
1325static inline void isig(int sig, struct tty_struct *tty, int flush)
1326{
Alan Coxa352def2008-07-16 21:53:12 +01001327 /* FIXME: This is completely bogus */
Eric W. Biedermanab521dc2007-02-12 00:53:00 -08001328 if (tty->pgrp)
1329 kill_pgrp(tty->pgrp, sig, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 if (flush || !L_NOFLSH(tty)) {
Alan Coxc65c9bc2009-06-11 12:50:12 +01001331 if ( tty->ldisc->ops->flush_buffer )
1332 tty->ldisc->ops->flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 i2InputFlush( tty->driver_data );
1334 }
1335}
1336
David Howellsc4028952006-11-22 14:57:56 +00001337static void do_status(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338{
David Howellsc4028952006-11-22 14:57:56 +00001339 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 int status;
1341
1342 status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
1343
1344 ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
1345
1346 if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
1347 if ( (status & I2_BRK) ) {
1348 // code duplicated from n_tty (ldisc)
1349 if (I_IGNBRK(pCh->pTTY))
1350 goto skip_this;
1351 if (I_BRKINT(pCh->pTTY)) {
1352 isig(SIGINT, pCh->pTTY, 1);
1353 goto skip_this;
1354 }
1355 wake_up_interruptible(&pCh->pTTY->read_wait);
1356 }
1357#ifdef NEVER_HAPPENS_AS_SETUP_XXX
1358 // and can't work because we don't know the_char
1359 // as the_char is reported on a separate path
1360 // The intelligent board does this stuff as setup
1361 {
1362 char brkf = TTY_NORMAL;
1363 unsigned char brkc = '\0';
1364 unsigned char tmp;
1365 if ( (status & I2_BRK) ) {
1366 brkf = TTY_BREAK;
1367 brkc = '\0';
1368 }
1369 else if (status & I2_PAR) {
1370 brkf = TTY_PARITY;
1371 brkc = the_char;
1372 } else if (status & I2_FRA) {
1373 brkf = TTY_FRAME;
1374 brkc = the_char;
1375 } else if (status & I2_OVR) {
1376 brkf = TTY_OVERRUN;
1377 brkc = the_char;
1378 }
1379 tmp = pCh->pTTY->real_raw;
1380 pCh->pTTY->real_raw = 0;
Alan Coxa352def2008-07-16 21:53:12 +01001381 pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 pCh->pTTY->real_raw = tmp;
1383 }
1384#endif /* NEVER_HAPPENS_AS_SETUP_XXX */
1385 }
1386skip_this:
1387
1388 if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
1389 wake_up_interruptible(&pCh->delta_msr_wait);
1390
1391 if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
1392 if ( status & I2_DCD ) {
1393 if ( pCh->wopen ) {
1394 wake_up_interruptible ( &pCh->open_wait );
1395 }
1396 } else {
1397 if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
1398 tty_hangup( pCh->pTTY );
1399 }
1400 }
1401 }
1402 }
1403
1404 ip2trace (CHANN, ITRC_STATUS, 26, 0 );
1405}
1406
1407/******************************************************************************/
1408/* Device Open/Close/Ioctl Entry Point Section */
1409/******************************************************************************/
1410
1411/******************************************************************************/
1412/* Function: open_sanity_check() */
1413/* Parameters: Pointer to tty structure */
1414/* Pointer to file structure */
1415/* Returns: Success or failure */
1416/* */
1417/* Description: */
1418/* Verifies the structure magic numbers and cross links. */
1419/******************************************************************************/
1420#ifdef IP2DEBUG_OPEN
1421static void
1422open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
1423{
1424 if ( pBrd->i2eValid != I2E_MAGIC ) {
1425 printk(KERN_ERR "IP2: invalid board structure\n" );
1426 } else if ( pBrd != pCh->pMyBord ) {
1427 printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
1428 pCh->pMyBord );
1429 } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
1430 printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
1431 } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
1432 } else {
1433 printk(KERN_INFO "IP2: all pointers check out!\n" );
1434 }
1435}
1436#endif
1437
1438
1439/******************************************************************************/
1440/* Function: ip2_open() */
1441/* Parameters: Pointer to tty structure */
1442/* Pointer to file structure */
1443/* Returns: Success or failure */
1444/* */
1445/* Description: (MANDATORY) */
1446/* A successful device open has to run a gauntlet of checks before it */
1447/* completes. After some sanity checking and pointer setup, the function */
1448/* blocks until all conditions are satisfied. It then initialises the port to */
1449/* the default characteristics and returns. */
1450/******************************************************************************/
1451static int
1452ip2_open( PTTY tty, struct file *pFile )
1453{
1454 wait_queue_t wait;
1455 int rc = 0;
1456 int do_clocal = 0;
1457 i2ChanStrPtr pCh = DevTable[tty->index];
1458
1459 ip2trace (tty->index, ITRC_OPEN, ITRC_ENTER, 0 );
1460
1461 if ( pCh == NULL ) {
1462 return -ENODEV;
1463 }
1464 /* Setup pointer links in device and tty structures */
1465 pCh->pTTY = tty;
1466 tty->driver_data = pCh;
1467
1468#ifdef IP2DEBUG_OPEN
1469 printk(KERN_DEBUG \
1470 "IP2:open(tty=%p,pFile=%p):dev=%s,ch=%d,idx=%d\n",
1471 tty, pFile, tty->name, pCh->infl.hd.i2sChannel, pCh->port_index);
1472 open_sanity_check ( pCh, pCh->pMyBord );
1473#endif
1474
1475 i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP);
1476 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1477 serviceOutgoingFifo( pCh->pMyBord );
1478
1479 /* Block here until the port is ready (per serial and istallion) */
1480 /*
1481 * 1. If the port is in the middle of closing wait for the completion
1482 * and then return the appropriate error.
1483 */
1484 init_waitqueue_entry(&wait, current);
1485 add_wait_queue(&pCh->close_wait, &wait);
1486 set_current_state( TASK_INTERRUPTIBLE );
1487
1488 if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
1489 if ( pCh->flags & ASYNC_CLOSING ) {
Arnd Bergmanne142a312010-06-01 22:53:10 +02001490 tty_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 schedule();
Arnd Bergmanne142a312010-06-01 22:53:10 +02001492 tty_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 }
1494 if ( tty_hung_up_p(pFile) ) {
1495 set_current_state( TASK_RUNNING );
1496 remove_wait_queue(&pCh->close_wait, &wait);
1497 return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
1498 }
1499 }
1500 set_current_state( TASK_RUNNING );
1501 remove_wait_queue(&pCh->close_wait, &wait);
1502
1503 /*
1504 * 3. Handle a non-blocking open of a normal port.
1505 */
1506 if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
1507 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1508 goto noblock;
1509 }
1510 /*
1511 * 4. Now loop waiting for the port to be free and carrier present
1512 * (if required).
1513 */
1514 if ( tty->termios->c_cflag & CLOCAL )
1515 do_clocal = 1;
1516
1517#ifdef IP2DEBUG_OPEN
1518 printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
1519#endif
1520
1521 ++pCh->wopen;
1522
1523 init_waitqueue_entry(&wait, current);
1524 add_wait_queue(&pCh->open_wait, &wait);
1525
1526 for(;;) {
1527 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1528 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1529 set_current_state( TASK_INTERRUPTIBLE );
1530 serviceOutgoingFifo( pCh->pMyBord );
1531 if ( tty_hung_up_p(pFile) ) {
1532 set_current_state( TASK_RUNNING );
1533 remove_wait_queue(&pCh->open_wait, &wait);
1534 return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
1535 }
1536 if (!(pCh->flags & ASYNC_CLOSING) &&
1537 (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
1538 rc = 0;
1539 break;
1540 }
1541
1542#ifdef IP2DEBUG_OPEN
1543 printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
1544 (pCh->flags & ASYNC_CLOSING)?"True":"False");
1545 printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
1546#endif
1547 ip2trace (CHANN, ITRC_OPEN, 3, 2, 0,
1548 (pCh->flags & ASYNC_CLOSING) );
1549 /* check for signal */
1550 if (signal_pending(current)) {
1551 rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
1552 break;
1553 }
Arnd Bergmanne142a312010-06-01 22:53:10 +02001554 tty_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 schedule();
Arnd Bergmanne142a312010-06-01 22:53:10 +02001556 tty_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 }
1558 set_current_state( TASK_RUNNING );
1559 remove_wait_queue(&pCh->open_wait, &wait);
1560
1561 --pCh->wopen; //why count?
1562
1563 ip2trace (CHANN, ITRC_OPEN, 4, 0 );
1564
1565 if (rc != 0 ) {
1566 return rc;
1567 }
1568 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1569
1570noblock:
1571
1572 /* first open - Assign termios structure to port */
1573 if ( tty->count == 1 ) {
1574 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1575 /* Now we must send the termios settings to the loadware */
1576 set_params( pCh, NULL );
1577 }
1578
1579 /*
1580 * Now set any i2lib options. These may go away if the i2lib code ends
1581 * up rolled into the mainline.
1582 */
1583 pCh->channelOptions |= CO_NBLOCK_WRITE;
1584
1585#ifdef IP2DEBUG_OPEN
1586 printk (KERN_DEBUG "IP2: open completed\n" );
1587#endif
1588 serviceOutgoingFifo( pCh->pMyBord );
1589
1590 ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
1591
1592 return 0;
1593}
1594
1595/******************************************************************************/
1596/* Function: ip2_close() */
1597/* Parameters: Pointer to tty structure */
1598/* Pointer to file structure */
1599/* Returns: Nothing */
1600/* */
1601/* Description: */
1602/* */
1603/* */
1604/******************************************************************************/
1605static void
1606ip2_close( PTTY tty, struct file *pFile )
1607{
1608 i2ChanStrPtr pCh = tty->driver_data;
1609
1610 if ( !pCh ) {
1611 return;
1612 }
1613
1614 ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
1615
1616#ifdef IP2DEBUG_OPEN
1617 printk(KERN_DEBUG "IP2:close %s:\n",tty->name);
1618#endif
1619
1620 if ( tty_hung_up_p ( pFile ) ) {
1621
1622 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
1623
1624 return;
1625 }
1626 if ( tty->count > 1 ) { /* not the last close */
1627
1628 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
1629
1630 return;
1631 }
1632 pCh->flags |= ASYNC_CLOSING; // last close actually
1633
1634 tty->closing = 1;
1635
1636 if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
1637 /*
1638 * Before we drop DTR, make sure the transmitter has completely drained.
1639 * This uses an timeout, after which the close
1640 * completes.
1641 */
1642 ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
1643 }
1644 /*
1645 * At this point we stop accepting input. Here we flush the channel
1646 * input buffer which will allow the board to send up more data. Any
1647 * additional input is tossed at interrupt/poll time.
1648 */
1649 i2InputFlush( pCh );
1650
1651 /* disable DSS reporting */
1652 i2QueueCommands(PTYPE_INLINE, pCh, 100, 4,
1653 CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
Dan Carpenterf64ac982010-08-12 13:48:57 -07001654 if (tty->termios->c_cflag & HUPCL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
1656 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1657 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1658 }
1659
1660 serviceOutgoingFifo ( pCh->pMyBord );
1661
Alan Coxf34d7a52008-04-30 00:54:13 -07001662 tty_ldisc_flush(tty);
Alan Coxa6fc8192008-04-30 00:54:18 -07001663 tty_driver_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 tty->closing = 0;
1665
1666 pCh->pTTY = NULL;
1667
1668 if (pCh->wopen) {
1669 if (pCh->ClosingDelay) {
1670 msleep_interruptible(jiffies_to_msecs(pCh->ClosingDelay));
1671 }
1672 wake_up_interruptible(&pCh->open_wait);
1673 }
1674
1675 pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1676 wake_up_interruptible(&pCh->close_wait);
1677
1678#ifdef IP2DEBUG_OPEN
1679 DBG_CNT("ip2_close: after wakeups--");
1680#endif
1681
1682
1683 ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
1684
1685 return;
1686}
1687
1688/******************************************************************************/
1689/* Function: ip2_hangup() */
1690/* Parameters: Pointer to tty structure */
1691/* Returns: Nothing */
1692/* */
1693/* Description: */
1694/* */
1695/* */
1696/******************************************************************************/
1697static void
1698ip2_hangup ( PTTY tty )
1699{
1700 i2ChanStrPtr pCh = tty->driver_data;
1701
1702 if( !pCh ) {
1703 return;
1704 }
1705
1706 ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
1707
1708 ip2_flush_buffer(tty);
1709
1710 /* disable DSS reporting */
1711
1712 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
1713 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1714 if ( (tty->termios->c_cflag & HUPCL) ) {
1715 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
1716 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1717 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1718 }
1719 i2QueueCommands(PTYPE_INLINE, pCh, 1, 3,
1720 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1721 serviceOutgoingFifo ( pCh->pMyBord );
1722
1723 wake_up_interruptible ( &pCh->delta_msr_wait );
1724
1725 pCh->flags &= ~ASYNC_NORMAL_ACTIVE;
1726 pCh->pTTY = NULL;
1727 wake_up_interruptible ( &pCh->open_wait );
1728
1729 ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
1730}
1731
1732/******************************************************************************/
1733/******************************************************************************/
1734/* Device Output Section */
1735/******************************************************************************/
1736/******************************************************************************/
1737
1738/******************************************************************************/
1739/* Function: ip2_write() */
1740/* Parameters: Pointer to tty structure */
1741/* Flag denoting data is in user (1) or kernel (0) space */
1742/* Pointer to data */
1743/* Number of bytes to write */
1744/* Returns: Number of bytes actually written */
1745/* */
1746/* Description: (MANDATORY) */
1747/* */
1748/* */
1749/******************************************************************************/
1750static int
Alan Coxd9e39532006-01-09 20:54:20 -08001751ip2_write( PTTY tty, const unsigned char *pData, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752{
1753 i2ChanStrPtr pCh = tty->driver_data;
1754 int bytesSent = 0;
1755 unsigned long flags;
1756
1757 ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
1758
1759 /* Flush out any buffered data left over from ip2_putchar() calls. */
1760 ip2_flush_chars( tty );
1761
1762 /* This is the actual move bit. Make sure it does what we need!!!!! */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001763 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Al Virof061c582006-10-11 17:45:47 +01001764 bytesSent = i2Output( pCh, pData, count);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001765 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
1768
1769 return bytesSent > 0 ? bytesSent : 0;
1770}
1771
1772/******************************************************************************/
1773/* Function: ip2_putchar() */
1774/* Parameters: Pointer to tty structure */
1775/* Character to write */
1776/* Returns: Nothing */
1777/* */
1778/* Description: */
1779/* */
1780/* */
1781/******************************************************************************/
Alan Coxf34d7a52008-04-30 00:54:13 -07001782static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783ip2_putchar( PTTY tty, unsigned char ch )
1784{
1785 i2ChanStrPtr pCh = tty->driver_data;
1786 unsigned long flags;
1787
1788// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
1789
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001790 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
1792 if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001793 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 ip2_flush_chars( tty );
1795 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001796 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Alan Coxf34d7a52008-04-30 00:54:13 -07001797 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
1799// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
1800}
1801
1802/******************************************************************************/
1803/* Function: ip2_flush_chars() */
1804/* Parameters: Pointer to tty structure */
1805/* Returns: Nothing */
1806/* */
1807/* Description: */
1808/* */
1809/******************************************************************************/
1810static void
1811ip2_flush_chars( PTTY tty )
1812{
1813 int strip;
1814 i2ChanStrPtr pCh = tty->driver_data;
1815 unsigned long flags;
1816
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001817 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 if ( pCh->Pbuf_stuff ) {
1819
1820// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
1821
1822 //
1823 // We may need to restart i2Output if it does not fullfill this request
1824 //
Al Virof061c582006-10-11 17:45:47 +01001825 strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 if ( strip != pCh->Pbuf_stuff ) {
1827 memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
1828 }
1829 pCh->Pbuf_stuff -= strip;
1830 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001831 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832}
1833
1834/******************************************************************************/
1835/* Function: ip2_write_room() */
1836/* Parameters: Pointer to tty structure */
1837/* Returns: Number of bytes that the driver can accept */
1838/* */
1839/* Description: */
1840/* */
1841/******************************************************************************/
1842static int
1843ip2_write_room ( PTTY tty )
1844{
1845 int bytesFree;
1846 i2ChanStrPtr pCh = tty->driver_data;
1847 unsigned long flags;
1848
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001849 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001851 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853 ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
1854
1855 return ((bytesFree > 0) ? bytesFree : 0);
1856}
1857
1858/******************************************************************************/
1859/* Function: ip2_chars_in_buf() */
1860/* Parameters: Pointer to tty structure */
1861/* Returns: Number of bytes queued for transmission */
1862/* */
1863/* Description: */
1864/* */
1865/* */
1866/******************************************************************************/
1867static int
1868ip2_chars_in_buf ( PTTY tty )
1869{
1870 i2ChanStrPtr pCh = tty->driver_data;
1871 int rc;
1872 unsigned long flags;
1873
1874 ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
1875
1876#ifdef IP2DEBUG_WRITE
1877 printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
1878 pCh->Obuf_char_count + pCh->Pbuf_stuff,
1879 pCh->Obuf_char_count, pCh->Pbuf_stuff );
1880#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001881 read_lock_irqsave(&pCh->Obuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 rc = pCh->Obuf_char_count;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001883 read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
1884 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 rc += pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001886 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 return rc;
1888}
1889
1890/******************************************************************************/
1891/* Function: ip2_flush_buffer() */
1892/* Parameters: Pointer to tty structure */
1893/* Returns: Nothing */
1894/* */
1895/* Description: */
1896/* */
1897/* */
1898/******************************************************************************/
1899static void
1900ip2_flush_buffer( PTTY tty )
1901{
1902 i2ChanStrPtr pCh = tty->driver_data;
1903 unsigned long flags;
1904
1905 ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
1906
1907#ifdef IP2DEBUG_WRITE
1908 printk (KERN_DEBUG "IP2: flush buffer\n" );
1909#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001910 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 pCh->Pbuf_stuff = 0;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001912 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 i2FlushOutput( pCh );
1914 ip2_owake(tty);
1915
1916 ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
1917
1918}
1919
1920/******************************************************************************/
1921/* Function: ip2_wait_until_sent() */
1922/* Parameters: Pointer to tty structure */
1923/* Timeout for wait. */
1924/* Returns: Nothing */
1925/* */
1926/* Description: */
1927/* This function is used in place of the normal tty_wait_until_sent, which */
1928/* only waits for the driver buffers to be empty (or rather, those buffers */
1929/* reported by chars_in_buffer) which doesn't work for IP2 due to the */
1930/* indeterminate number of bytes buffered on the board. */
1931/******************************************************************************/
1932static void
1933ip2_wait_until_sent ( PTTY tty, int timeout )
1934{
1935 int i = jiffies;
1936 i2ChanStrPtr pCh = tty->driver_data;
1937
1938 tty_wait_until_sent(tty, timeout );
1939 if ( (i = timeout - (jiffies -i)) > 0)
1940 i2DrainOutput( pCh, i );
1941}
1942
1943/******************************************************************************/
1944/******************************************************************************/
1945/* Device Input Section */
1946/******************************************************************************/
1947/******************************************************************************/
1948
1949/******************************************************************************/
1950/* Function: ip2_throttle() */
1951/* Parameters: Pointer to tty structure */
1952/* Returns: Nothing */
1953/* */
1954/* Description: */
1955/* */
1956/* */
1957/******************************************************************************/
1958static void
1959ip2_throttle ( PTTY tty )
1960{
1961 i2ChanStrPtr pCh = tty->driver_data;
1962
1963#ifdef IP2DEBUG_READ
1964 printk (KERN_DEBUG "IP2: throttle\n" );
1965#endif
1966 /*
1967 * Signal the poll/interrupt handlers not to forward incoming data to
1968 * the line discipline. This will cause the buffers to fill up in the
1969 * library and thus cause the library routines to send the flow control
1970 * stuff.
1971 */
1972 pCh->throttled = 1;
1973}
1974
1975/******************************************************************************/
1976/* Function: ip2_unthrottle() */
1977/* Parameters: Pointer to tty structure */
1978/* Returns: Nothing */
1979/* */
1980/* Description: */
1981/* */
1982/* */
1983/******************************************************************************/
1984static void
1985ip2_unthrottle ( PTTY tty )
1986{
1987 i2ChanStrPtr pCh = tty->driver_data;
1988 unsigned long flags;
1989
1990#ifdef IP2DEBUG_READ
1991 printk (KERN_DEBUG "IP2: unthrottle\n" );
1992#endif
1993
1994 /* Pass incoming data up to the line discipline again. */
1995 pCh->throttled = 0;
1996 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
1997 serviceOutgoingFifo( pCh->pMyBord );
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001998 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002000 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001#ifdef IP2DEBUG_READ
2002 printk (KERN_DEBUG "i2Input called from unthrottle\n" );
2003#endif
2004 i2Input( pCh );
2005 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002006 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007}
2008
2009static void
2010ip2_start ( PTTY tty )
2011{
2012 i2ChanStrPtr pCh = DevTable[tty->index];
2013
2014 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
2015 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
2016 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
2017#ifdef IP2DEBUG_WRITE
2018 printk (KERN_DEBUG "IP2: start tx\n" );
2019#endif
2020}
2021
2022static void
2023ip2_stop ( PTTY tty )
2024{
2025 i2ChanStrPtr pCh = DevTable[tty->index];
2026
2027 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
2028#ifdef IP2DEBUG_WRITE
2029 printk (KERN_DEBUG "IP2: stop tx\n" );
2030#endif
2031}
2032
2033/******************************************************************************/
2034/* Device Ioctl Section */
2035/******************************************************************************/
2036
2037static int ip2_tiocmget(struct tty_struct *tty, struct file *file)
2038{
2039 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002040#ifdef ENABLE_DSSNOW
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 wait_queue_t wait;
Alan Coxd9e39532006-01-09 20:54:20 -08002042#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
2044 if (pCh == NULL)
2045 return -ENODEV;
2046
2047/*
2048 FIXME - the following code is causing a NULL pointer dereference in
2049 2.3.51 in an interrupt handler. It's suppose to prompt the board
2050 to return the DSS signal status immediately. Why doesn't it do
2051 the same thing in 2.2.14?
2052*/
2053
2054/* This thing is still busted in the 1.2.12 driver on 2.4.x
2055 and even hoses the serial console so the oops can be trapped.
2056 /\/\|=mhw=|\/\/ */
2057
2058#ifdef ENABLE_DSSNOW
2059 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
2060
2061 init_waitqueue_entry(&wait, current);
2062 add_wait_queue(&pCh->dss_now_wait, &wait);
2063 set_current_state( TASK_INTERRUPTIBLE );
2064
2065 serviceOutgoingFifo( pCh->pMyBord );
2066
2067 schedule();
2068
2069 set_current_state( TASK_RUNNING );
2070 remove_wait_queue(&pCh->dss_now_wait, &wait);
2071
2072 if (signal_pending(current)) {
2073 return -EINTR;
2074 }
2075#endif
2076 return ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
2077 | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
2078 | ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0)
2079 | ((pCh->dataSetIn & I2_RI) ? TIOCM_RNG : 0)
2080 | ((pCh->dataSetIn & I2_DSR) ? TIOCM_DSR : 0)
2081 | ((pCh->dataSetIn & I2_CTS) ? TIOCM_CTS : 0);
2082}
2083
2084static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
2085 unsigned int set, unsigned int clear)
2086{
2087 i2ChanStrPtr pCh = DevTable[tty->index];
2088
2089 if (pCh == NULL)
2090 return -ENODEV;
2091
2092 if (set & TIOCM_RTS) {
2093 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2094 pCh->dataSetOut |= I2_RTS;
2095 }
2096 if (set & TIOCM_DTR) {
2097 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2098 pCh->dataSetOut |= I2_DTR;
2099 }
2100
2101 if (clear & TIOCM_RTS) {
2102 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2103 pCh->dataSetOut &= ~I2_RTS;
2104 }
2105 if (clear & TIOCM_DTR) {
2106 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2107 pCh->dataSetOut &= ~I2_DTR;
2108 }
2109 serviceOutgoingFifo( pCh->pMyBord );
2110 return 0;
2111}
2112
2113/******************************************************************************/
2114/* Function: ip2_ioctl() */
2115/* Parameters: Pointer to tty structure */
2116/* Pointer to file structure */
2117/* Command */
2118/* Argument */
2119/* Returns: Success or failure */
2120/* */
2121/* Description: */
2122/* */
2123/* */
2124/******************************************************************************/
2125static int
2126ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
2127{
2128 wait_queue_t wait;
2129 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002130 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 struct async_icount cprev, cnow; /* kernel counter temps */
2132 struct serial_icounter_struct __user *p_cuser;
2133 int rc = 0;
2134 unsigned long flags;
2135 void __user *argp = (void __user *)arg;
2136
Alan Coxd9e39532006-01-09 20:54:20 -08002137 if ( pCh == NULL )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 return -ENODEV;
Alan Coxd9e39532006-01-09 20:54:20 -08002139
2140 pB = pCh->pMyBord;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
2142 ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
2143
2144#ifdef IP2DEBUG_IOCTL
2145 printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
2146#endif
2147
2148 switch(cmd) {
2149 case TIOCGSERIAL:
2150
2151 ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
2152
2153 rc = get_serial_info(pCh, argp);
2154 if (rc)
2155 return rc;
2156 break;
2157
2158 case TIOCSSERIAL:
2159
2160 ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
2161
2162 rc = set_serial_info(pCh, argp);
2163 if (rc)
2164 return rc;
2165 break;
2166
2167 case TCXONC:
2168 rc = tty_check_change(tty);
2169 if (rc)
2170 return rc;
2171 switch (arg) {
2172 case TCOOFF:
2173 //return -ENOIOCTLCMD;
2174 break;
2175 case TCOON:
2176 //return -ENOIOCTLCMD;
2177 break;
2178 case TCIOFF:
2179 if (STOP_CHAR(tty) != __DISABLED_CHAR) {
2180 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2181 CMD_XMIT_NOW(STOP_CHAR(tty)));
2182 }
2183 break;
2184 case TCION:
2185 if (START_CHAR(tty) != __DISABLED_CHAR) {
2186 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2187 CMD_XMIT_NOW(START_CHAR(tty)));
2188 }
2189 break;
2190 default:
2191 return -EINVAL;
2192 }
2193 return 0;
2194
2195 case TCSBRK: /* SVID version: non-zero arg --> no break */
2196 rc = tty_check_change(tty);
2197
2198 ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
2199
2200 if (!rc) {
2201 ip2_wait_until_sent(tty,0);
2202 if (!arg) {
2203 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
2204 serviceOutgoingFifo( pCh->pMyBord );
2205 }
2206 }
2207 break;
2208
2209 case TCSBRKP: /* support for POSIX tcsendbreak() */
2210 rc = tty_check_change(tty);
2211
2212 ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
2213
2214 if (!rc) {
2215 ip2_wait_until_sent(tty,0);
2216 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2217 CMD_SEND_BRK(arg ? arg*100 : 250));
2218 serviceOutgoingFifo ( pCh->pMyBord );
2219 }
2220 break;
2221
2222 case TIOCGSOFTCAR:
2223
2224 ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
2225
2226 rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
2227 if (rc)
2228 return rc;
2229 break;
2230
2231 case TIOCSSOFTCAR:
2232
2233 ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
2234
2235 rc = get_user(arg,(unsigned long __user *) argp);
2236 if (rc)
2237 return rc;
2238 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
2239 | (arg ? CLOCAL : 0));
2240
2241 break;
2242
2243 /*
2244 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
2245 * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
2246 * for masking). Caller should use TIOCGICOUNT to see which one it was
2247 */
2248 case TIOCMIWAIT:
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002249 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 cprev = pCh->icount; /* note the counters on entry */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002251 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
2253 CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
2254 init_waitqueue_entry(&wait, current);
2255 add_wait_queue(&pCh->delta_msr_wait, &wait);
2256 set_current_state( TASK_INTERRUPTIBLE );
2257
2258 serviceOutgoingFifo( pCh->pMyBord );
2259 for(;;) {
2260 ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
2261
2262 schedule();
2263
2264 ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
2265
2266 /* see if a signal did it */
2267 if (signal_pending(current)) {
2268 rc = -ERESTARTSYS;
2269 break;
2270 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002271 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 cnow = pCh->icount; /* atomic copy */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002273 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2275 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2276 rc = -EIO; /* no change => rc */
2277 break;
2278 }
2279 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2280 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2281 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2282 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2283 rc = 0;
2284 break;
2285 }
2286 cprev = cnow;
2287 }
2288 set_current_state( TASK_RUNNING );
2289 remove_wait_queue(&pCh->delta_msr_wait, &wait);
2290
2291 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3,
2292 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
2293 if ( ! (pCh->flags & ASYNC_CHECK_CD)) {
2294 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP);
2295 }
2296 serviceOutgoingFifo( pCh->pMyBord );
2297 return rc;
2298 break;
2299
2300 /*
2301 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2302 * Return: write counters to the user passed counter struct
2303 * NB: both 1->0 and 0->1 transitions are counted except for RI where
2304 * only 0->1 is counted. The controller is quite capable of counting
2305 * both, but this done to preserve compatibility with the standard
2306 * serial driver.
2307 */
2308 case TIOCGICOUNT:
2309 ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
2310
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002311 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 cnow = pCh->icount;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002313 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 p_cuser = argp;
2315 rc = put_user(cnow.cts, &p_cuser->cts);
2316 rc = put_user(cnow.dsr, &p_cuser->dsr);
2317 rc = put_user(cnow.rng, &p_cuser->rng);
2318 rc = put_user(cnow.dcd, &p_cuser->dcd);
2319 rc = put_user(cnow.rx, &p_cuser->rx);
2320 rc = put_user(cnow.tx, &p_cuser->tx);
2321 rc = put_user(cnow.frame, &p_cuser->frame);
2322 rc = put_user(cnow.overrun, &p_cuser->overrun);
2323 rc = put_user(cnow.parity, &p_cuser->parity);
2324 rc = put_user(cnow.brk, &p_cuser->brk);
2325 rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
2326 break;
2327
2328 /*
2329 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
2330 * will be passed to the line discipline for it to handle.
2331 */
2332 case TIOCSERCONFIG:
2333 case TIOCSERGWILD:
2334 case TIOCSERGETLSR:
2335 case TIOCSERSWILD:
2336 case TIOCSERGSTRUCT:
2337 case TIOCSERGETMULTI:
2338 case TIOCSERSETMULTI:
2339
2340 default:
2341 ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
2342
2343 rc = -ENOIOCTLCMD;
2344 break;
2345 }
2346
2347 ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
2348
2349 return rc;
2350}
2351
2352/******************************************************************************/
2353/* Function: GetSerialInfo() */
2354/* Parameters: Pointer to channel structure */
2355/* Pointer to old termios structure */
2356/* Returns: Nothing */
2357/* */
2358/* Description: */
2359/* This is to support the setserial command, and requires processing of the */
2360/* standard Linux serial structure. */
2361/******************************************************************************/
2362static int
2363get_serial_info ( i2ChanStrPtr pCh, struct serial_struct __user *retinfo )
2364{
2365 struct serial_struct tmp;
2366
2367 memset ( &tmp, 0, sizeof(tmp) );
2368 tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
2369 if (BID_HAS_654(tmp.type)) {
2370 tmp.type = PORT_16650;
2371 } else {
2372 tmp.type = PORT_CIRRUS;
2373 }
2374 tmp.line = pCh->port_index;
2375 tmp.port = pCh->pMyBord->i2eBase;
2376 tmp.irq = ip2config.irq[pCh->port_index/64];
2377 tmp.flags = pCh->flags;
2378 tmp.baud_base = pCh->BaudBase;
2379 tmp.close_delay = pCh->ClosingDelay;
2380 tmp.closing_wait = pCh->ClosingWaitTime;
2381 tmp.custom_divisor = pCh->BaudDivisor;
2382 return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
2383}
2384
2385/******************************************************************************/
2386/* Function: SetSerialInfo() */
2387/* Parameters: Pointer to channel structure */
2388/* Pointer to old termios structure */
2389/* Returns: Nothing */
2390/* */
2391/* Description: */
2392/* This function provides support for setserial, which uses the TIOCSSERIAL */
2393/* ioctl. Not all setserial parameters are relevant. If the user attempts to */
2394/* change the IRQ, address or type of the port the ioctl fails. */
2395/******************************************************************************/
2396static int
2397set_serial_info( i2ChanStrPtr pCh, struct serial_struct __user *new_info )
2398{
2399 struct serial_struct ns;
2400 int old_flags, old_baud_divisor;
2401
2402 if (copy_from_user(&ns, new_info, sizeof (ns)))
2403 return -EFAULT;
2404
2405 /*
2406 * We don't allow setserial to change IRQ, board address, type or baud
2407 * base. Also line nunber as such is meaningless but we use it for our
2408 * array index so it is fixed also.
2409 */
2410 if ( (ns.irq != ip2config.irq[pCh->port_index])
2411 || ((int) ns.port != ((int) (pCh->pMyBord->i2eBase)))
2412 || (ns.baud_base != pCh->BaudBase)
2413 || (ns.line != pCh->port_index) ) {
2414 return -EINVAL;
2415 }
2416
2417 old_flags = pCh->flags;
2418 old_baud_divisor = pCh->BaudDivisor;
2419
2420 if ( !capable(CAP_SYS_ADMIN) ) {
2421 if ( ( ns.close_delay != pCh->ClosingDelay ) ||
2422 ( (ns.flags & ~ASYNC_USR_MASK) !=
2423 (pCh->flags & ~ASYNC_USR_MASK) ) ) {
2424 return -EPERM;
2425 }
2426
2427 pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
2428 (ns.flags & ASYNC_USR_MASK);
2429 pCh->BaudDivisor = ns.custom_divisor;
2430 } else {
2431 pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
2432 (ns.flags & ASYNC_FLAGS);
2433 pCh->BaudDivisor = ns.custom_divisor;
2434 pCh->ClosingDelay = ns.close_delay * HZ/100;
2435 pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
2436 }
2437
2438 if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
2439 || (old_baud_divisor != pCh->BaudDivisor) ) {
2440 // Invalidate speed and reset parameters
2441 set_params( pCh, NULL );
2442 }
2443
2444 return 0;
2445}
2446
2447/******************************************************************************/
2448/* Function: ip2_set_termios() */
2449/* Parameters: Pointer to tty structure */
2450/* Pointer to old termios structure */
2451/* Returns: Nothing */
2452/* */
2453/* Description: */
2454/* */
2455/* */
2456/******************************************************************************/
2457static void
Alan Cox606d0992006-12-08 02:38:45 -08002458ip2_set_termios( PTTY tty, struct ktermios *old_termios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459{
2460 i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
2461
2462#ifdef IP2DEBUG_IOCTL
2463 printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
2464#endif
2465
2466 set_params( pCh, old_termios );
2467}
2468
2469/******************************************************************************/
2470/* Function: ip2_set_line_discipline() */
2471/* Parameters: Pointer to tty structure */
2472/* Returns: Nothing */
2473/* */
2474/* Description: Does nothing */
2475/* */
2476/* */
2477/******************************************************************************/
2478static void
2479ip2_set_line_discipline ( PTTY tty )
2480{
2481#ifdef IP2DEBUG_IOCTL
2482 printk (KERN_DEBUG "IP2: set line discipline\n" );
2483#endif
2484
2485 ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
2486
2487}
2488
2489/******************************************************************************/
2490/* Function: SetLine Characteristics() */
2491/* Parameters: Pointer to channel structure */
2492/* Returns: Nothing */
2493/* */
2494/* Description: */
2495/* This routine is called to update the channel structure with the new line */
2496/* characteristics, and send the appropriate commands to the board when they */
2497/* change. */
2498/******************************************************************************/
2499static void
Alan Cox606d0992006-12-08 02:38:45 -08002500set_params( i2ChanStrPtr pCh, struct ktermios *o_tios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501{
2502 tcflag_t cflag, iflag, lflag;
2503 char stop_char, start_char;
Alan Cox606d0992006-12-08 02:38:45 -08002504 struct ktermios dummy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505
2506 lflag = pCh->pTTY->termios->c_lflag;
2507 cflag = pCh->pTTY->termios->c_cflag;
2508 iflag = pCh->pTTY->termios->c_iflag;
2509
2510 if (o_tios == NULL) {
2511 dummy.c_lflag = ~lflag;
2512 dummy.c_cflag = ~cflag;
2513 dummy.c_iflag = ~iflag;
2514 o_tios = &dummy;
2515 }
2516
2517 {
2518 switch ( cflag & CBAUD ) {
2519 case B0:
2520 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
2521 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
2522 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
2523 pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
2524 goto service_it;
2525 break;
2526 case B38400:
2527 /*
2528 * This is the speed that is overloaded with all the other high
2529 * speeds, depending upon the flag settings.
2530 */
2531 if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
2532 pCh->speed = CBR_57600;
2533 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
2534 pCh->speed = CBR_115200;
2535 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
2536 pCh->speed = CBR_C1;
2537 } else {
2538 pCh->speed = CBR_38400;
2539 }
2540 break;
2541 case B50: pCh->speed = CBR_50; break;
2542 case B75: pCh->speed = CBR_75; break;
2543 case B110: pCh->speed = CBR_110; break;
2544 case B134: pCh->speed = CBR_134; break;
2545 case B150: pCh->speed = CBR_150; break;
2546 case B200: pCh->speed = CBR_200; break;
2547 case B300: pCh->speed = CBR_300; break;
2548 case B600: pCh->speed = CBR_600; break;
2549 case B1200: pCh->speed = CBR_1200; break;
2550 case B1800: pCh->speed = CBR_1800; break;
2551 case B2400: pCh->speed = CBR_2400; break;
2552 case B4800: pCh->speed = CBR_4800; break;
2553 case B9600: pCh->speed = CBR_9600; break;
2554 case B19200: pCh->speed = CBR_19200; break;
2555 case B57600: pCh->speed = CBR_57600; break;
2556 case B115200: pCh->speed = CBR_115200; break;
2557 case B153600: pCh->speed = CBR_153600; break;
2558 case B230400: pCh->speed = CBR_230400; break;
2559 case B307200: pCh->speed = CBR_307200; break;
2560 case B460800: pCh->speed = CBR_460800; break;
2561 case B921600: pCh->speed = CBR_921600; break;
2562 default: pCh->speed = CBR_9600; break;
2563 }
2564 if ( pCh->speed == CBR_C1 ) {
2565 // Process the custom speed parameters.
2566 int bps = pCh->BaudBase / pCh->BaudDivisor;
2567 if ( bps == 921600 ) {
2568 pCh->speed = CBR_921600;
2569 } else {
2570 bps = bps/10;
2571 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
2572 }
2573 }
2574 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
2575
2576 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
2577 pCh->dataSetOut |= (I2_DTR | I2_RTS);
2578 }
2579 if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag))
2580 {
2581 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2582 CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
2583 }
2584 if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag))
2585 {
2586 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2587 CMD_SETPAR(
2588 (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
2589 )
2590 );
2591 }
2592 /* byte size and parity */
2593 if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag))
2594 {
2595 int datasize;
2596 switch ( cflag & CSIZE ) {
2597 case CS5: datasize = CSZ_5; break;
2598 case CS6: datasize = CSZ_6; break;
2599 case CS7: datasize = CSZ_7; break;
2600 case CS8: datasize = CSZ_8; break;
2601 default: datasize = CSZ_5; break; /* as per serial.c */
2602 }
2603 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
2604 }
2605 /* Process CTS flow control flag setting */
2606 if ( (cflag & CRTSCTS) ) {
2607 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2608 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
2609 } else {
2610 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2611 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
2612 }
2613 //
2614 // Process XON/XOFF flow control flags settings
2615 //
2616 stop_char = STOP_CHAR(pCh->pTTY);
2617 start_char = START_CHAR(pCh->pTTY);
2618
2619 //////////// can't be \000
2620 if (stop_char == __DISABLED_CHAR )
2621 {
2622 stop_char = ~__DISABLED_CHAR;
2623 }
2624 if (start_char == __DISABLED_CHAR )
2625 {
2626 start_char = ~__DISABLED_CHAR;
2627 }
2628 /////////////////////////////////
2629
2630 if ( o_tios->c_cc[VSTART] != start_char )
2631 {
2632 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
2633 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
2634 }
2635 if ( o_tios->c_cc[VSTOP] != stop_char )
2636 {
2637 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
2638 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
2639 }
2640 if (stop_char == __DISABLED_CHAR )
2641 {
2642 stop_char = ~__DISABLED_CHAR; //TEST123
2643 goto no_xoff;
2644 }
2645 if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF)))
2646 {
2647 if ( iflag & IXOFF ) { // Enable XOFF output flow control
2648 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
2649 } else { // Disable XOFF output flow control
2650no_xoff:
2651 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
2652 }
2653 }
2654 if (start_char == __DISABLED_CHAR )
2655 {
2656 goto no_xon;
2657 }
2658 if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY)))
2659 {
2660 if ( iflag & IXON ) {
2661 if ( iflag & IXANY ) { // Enable XON/XANY output flow control
2662 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
2663 } else { // Enable XON output flow control
2664 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
2665 }
2666 } else { // Disable XON output flow control
2667no_xon:
2668 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
2669 }
2670 }
2671 if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) )
2672 {
2673 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2674 CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
2675 }
2676 if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) )
2677 {
2678 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2679 CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
2680 }
2681
2682 if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR))
2683 ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) )
2684 {
2685 char brkrpt = 0;
2686 char parrpt = 0;
2687
2688 if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
2689 /* Ignore breaks altogether */
2690 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
2691 } else {
2692 if ( iflag & BRKINT ) {
2693 if ( iflag & PARMRK ) {
2694 brkrpt = 0x0a; // exception an inline triple
2695 } else {
2696 brkrpt = 0x1a; // exception and NULL
2697 }
2698 brkrpt |= 0x04; // flush input
2699 } else {
2700 if ( iflag & PARMRK ) {
2701 brkrpt = 0x0b; //POSIX triple \0377 \0 \0
2702 } else {
2703 brkrpt = 0x01; // Null only
2704 }
2705 }
2706 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
2707 }
2708
2709 if (iflag & IGNPAR) {
2710 parrpt = 0x20;
2711 /* would be 2 for not cirrus bug */
2712 /* would be 0x20 cept for cirrus bug */
2713 } else {
2714 if ( iflag & PARMRK ) {
2715 /*
2716 * Replace error characters with 3-byte sequence (\0377,\0,char)
2717 */
2718 parrpt = 0x04 ;
2719 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
2720 } else {
2721 parrpt = 0x03;
2722 }
2723 }
2724 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
2725 }
2726 if (cflag & CLOCAL) {
2727 // Status reporting fails for DCD if this is off
2728 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
2729 pCh->flags &= ~ASYNC_CHECK_CD;
2730 } else {
2731 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
2732 pCh->flags |= ASYNC_CHECK_CD;
2733 }
2734
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735service_it:
2736 i2DrainOutput( pCh, 100 );
2737}
2738
2739/******************************************************************************/
2740/* IPL Device Section */
2741/******************************************************************************/
2742
2743/******************************************************************************/
2744/* Function: ip2_ipl_read() */
2745/* Parameters: Pointer to device inode */
2746/* Pointer to file structure */
2747/* Pointer to data */
2748/* Number of bytes to read */
2749/* Returns: Success or failure */
2750/* */
2751/* Description: Ugly */
2752/* */
2753/* */
2754/******************************************************************************/
2755
2756static
2757ssize_t
2758ip2_ipl_read(struct file *pFile, char __user *pData, size_t count, loff_t *off )
2759{
Josef Sipeka7113a92006-12-08 02:36:55 -08002760 unsigned int minor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 int rc = 0;
2762
2763#ifdef IP2DEBUG_IPL
2764 printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
2765#endif
2766
2767 switch( minor ) {
2768 case 0: // IPL device
2769 rc = -EINVAL;
2770 break;
2771 case 1: // Status dump
2772 rc = -EINVAL;
2773 break;
2774 case 2: // Ping device
2775 rc = -EINVAL;
2776 break;
2777 case 3: // Trace device
2778 rc = DumpTraceBuffer ( pData, count );
2779 break;
2780 case 4: // Trace device
2781 rc = DumpFifoBuffer ( pData, count );
2782 break;
2783 default:
2784 rc = -ENODEV;
2785 break;
2786 }
2787 return rc;
2788}
2789
2790static int
2791DumpFifoBuffer ( char __user *pData, int count )
2792{
2793#ifdef DEBUG_FIFO
2794 int rc;
2795 rc = copy_to_user(pData, DBGBuf, count);
2796
2797 printk(KERN_DEBUG "Last index %d\n", I );
2798
2799 return count;
2800#endif /* DEBUG_FIFO */
2801 return 0;
2802}
2803
2804static int
2805DumpTraceBuffer ( char __user *pData, int count )
2806{
2807#ifdef IP2DEBUG_TRACE
2808 int rc;
2809 int dumpcount;
2810 int chunk;
2811 int *pIndex = (int __user *)pData;
2812
2813 if ( count < (sizeof(int) * 6) ) {
2814 return -EIO;
2815 }
2816 rc = put_user(tracewrap, pIndex );
2817 rc = put_user(TRACEMAX, ++pIndex );
2818 rc = put_user(tracestrip, ++pIndex );
2819 rc = put_user(tracestuff, ++pIndex );
2820 pData += sizeof(int) * 6;
2821 count -= sizeof(int) * 6;
2822
2823 dumpcount = tracestuff - tracestrip;
2824 if ( dumpcount < 0 ) {
2825 dumpcount += TRACEMAX;
2826 }
2827 if ( dumpcount > count ) {
2828 dumpcount = count;
2829 }
2830 chunk = TRACEMAX - tracestrip;
2831 if ( dumpcount > chunk ) {
2832 rc = copy_to_user(pData, &tracebuf[tracestrip],
2833 chunk * sizeof(tracebuf[0]) );
2834 pData += chunk * sizeof(tracebuf[0]);
2835 tracestrip = 0;
2836 chunk = dumpcount - chunk;
2837 } else {
2838 chunk = dumpcount;
2839 }
2840 rc = copy_to_user(pData, &tracebuf[tracestrip],
2841 chunk * sizeof(tracebuf[0]) );
2842 tracestrip += chunk;
2843 tracewrap = 0;
2844
2845 rc = put_user(tracestrip, ++pIndex );
2846 rc = put_user(tracestuff, ++pIndex );
2847
2848 return dumpcount;
2849#else
2850 return 0;
2851#endif
2852}
2853
2854/******************************************************************************/
2855/* Function: ip2_ipl_write() */
2856/* Parameters: */
2857/* Pointer to file structure */
2858/* Pointer to data */
2859/* Number of bytes to write */
2860/* Returns: Success or failure */
2861/* */
2862/* Description: */
2863/* */
2864/* */
2865/******************************************************************************/
2866static ssize_t
2867ip2_ipl_write(struct file *pFile, const char __user *pData, size_t count, loff_t *off)
2868{
2869#ifdef IP2DEBUG_IPL
2870 printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
2871#endif
2872 return 0;
2873}
2874
2875/******************************************************************************/
2876/* Function: ip2_ipl_ioctl() */
2877/* Parameters: Pointer to device inode */
2878/* Pointer to file structure */
2879/* Command */
2880/* Argument */
2881/* Returns: Success or failure */
2882/* */
2883/* Description: */
2884/* */
2885/* */
2886/******************************************************************************/
Alan Cox47be36a2008-07-25 01:48:13 -07002887static long
2888ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889{
Alan Cox47be36a2008-07-25 01:48:13 -07002890 unsigned int iplminor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 int rc = 0;
2892 void __user *argp = (void __user *)arg;
2893 ULONG __user *pIndex = argp;
2894 i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
2895 i2ChanStrPtr pCh;
2896
2897#ifdef IP2DEBUG_IPL
2898 printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
2899#endif
2900
Alan Cox47be36a2008-07-25 01:48:13 -07002901 lock_kernel();
2902
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 switch ( iplminor ) {
2904 case 0: // IPL device
2905 rc = -EINVAL;
2906 break;
2907 case 1: // Status dump
2908 case 5:
2909 case 9:
2910 case 13:
2911 switch ( cmd ) {
2912 case 64: /* Driver - ip2stat */
Alan Cox7d7b93c2008-10-13 10:42:09 +01002913 rc = put_user(-1, pIndex++ );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 rc = put_user(irq_counter, pIndex++ );
2915 rc = put_user(bh_counter, pIndex++ );
2916 break;
2917
2918 case 65: /* Board - ip2stat */
2919 if ( pB ) {
2920 rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002921 rc = put_user(inb(pB->i2eStatus),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 (ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
2923 } else {
2924 rc = -ENODEV;
2925 }
2926 break;
2927
2928 default:
2929 if (cmd < IP2_MAX_PORTS) {
2930 pCh = DevTable[cmd];
2931 if ( pCh )
2932 {
2933 rc = copy_to_user(argp, pCh, sizeof(i2ChanStr));
Dan Carpenter05254a22010-08-12 13:48:59 -07002934 if (rc)
2935 rc = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 } else {
2937 rc = -ENODEV;
2938 }
2939 } else {
2940 rc = -EINVAL;
2941 }
2942 }
2943 break;
2944
2945 case 2: // Ping device
2946 rc = -EINVAL;
2947 break;
2948 case 3: // Trace device
Andrew Mortondef93912006-02-03 03:04:47 -08002949 /*
2950 * akpm: This used to write a whole bunch of function addresses
2951 * to userspace, which generated lots of put_user() warnings.
2952 * I killed it all. Just return "success" and don't do
2953 * anything.
2954 */
2955 if (cmd == 1)
2956 rc = 0;
2957 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 break;
2960
2961 default:
2962 rc = -ENODEV;
2963 break;
2964 }
Alan Cox47be36a2008-07-25 01:48:13 -07002965 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 return rc;
2967}
2968
2969/******************************************************************************/
2970/* Function: ip2_ipl_open() */
2971/* Parameters: Pointer to device inode */
2972/* Pointer to file structure */
2973/* Returns: Success or failure */
2974/* */
2975/* Description: */
2976/* */
2977/* */
2978/******************************************************************************/
2979static int
2980ip2_ipl_open( struct inode *pInode, struct file *pFile )
2981{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
2983#ifdef IP2DEBUG_IPL
2984 printk (KERN_DEBUG "IP2IPL: open\n" );
2985#endif
Jonathan Corbetf2b98572008-05-18 15:32:43 -06002986 cycle_kernel_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 return 0;
2988}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989
2990static int
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002991proc_ip2mem_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992{
2993 i2eBordStrPtr pB;
2994 i2ChanStrPtr pCh;
2995 PTTY tty;
2996 int i;
2997
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
2999#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
3000#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
3001
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003002 seq_printf(m,"\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003
3004 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3005 pB = i2BoardPtrTable[i];
3006 if ( pB ) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003007 seq_printf(m,"board %d:\n",i);
3008 seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
3010 }
3011 }
3012
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003013 seq_printf(m,"#: tty flags, port flags, cflags, iflags\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 for (i=0; i < IP2_MAX_PORTS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 pCh = DevTable[i];
3016 if (pCh) {
3017 tty = pCh->pTTY;
3018 if (tty && tty->count) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003019 seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 tty->termios->c_cflag,tty->termios->c_iflag);
3021
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003022 seq_printf(m,FMTLIN2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003024 seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 }
3026 }
3027 }
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003028 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029}
3030
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003031static int proc_ip2mem_open(struct inode *inode, struct file *file)
3032{
3033 return single_open(file, proc_ip2mem_show, NULL);
3034}
3035
3036static const struct file_operations ip2mem_proc_fops = {
3037 .owner = THIS_MODULE,
3038 .open = proc_ip2mem_open,
3039 .read = seq_read,
3040 .llseek = seq_lseek,
3041 .release = single_release,
3042};
3043
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044/*
3045 * This is the handler for /proc/tty/driver/ip2
3046 *
3047 * This stretch of code has been largely plagerized from at least three
3048 * different sources including ip2mkdev.c and a couple of other drivers.
3049 * The bugs are all mine. :-) =mhw=
3050 */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003051static int ip2_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052{
3053 int i, j, box;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 int boxes = 0;
3055 int ports = 0;
3056 int tports = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 i2eBordStrPtr pB;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003058 char *sep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003060 seq_printf(m, "ip2info: 1.0 driver: %s\n", pcVersion);
3061 seq_printf(m, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
3063 IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
3064
3065 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3066 /* This need to be reset for a board by board count... */
3067 boxes = 0;
3068 pB = i2BoardPtrTable[i];
3069 if( pB ) {
3070 switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED )
3071 {
3072 case POR_ID_FIIEX:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003073 seq_printf(m, "Board %d: EX ports=", i);
3074 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 for( box = 0; box < ABS_MAX_BOXES; ++box )
3076 {
3077 ports = 0;
3078
3079 if( pB->i2eChannelMap[box] != 0 ) ++boxes;
3080 for( j = 0; j < ABS_BIGGEST_BOX; ++j )
3081 {
3082 if( pB->i2eChannelMap[box] & 1<< j ) {
3083 ++ports;
3084 }
3085 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003086 seq_printf(m, "%s%d", sep, ports);
3087 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 tports += ports;
3089 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003090 seq_printf(m, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 break;
3092
3093 case POR_ID_II_4:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003094 seq_printf(m, "Board %d: ISA-4 ports=4 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 tports = ports = 4;
3096 break;
3097
3098 case POR_ID_II_8:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003099 seq_printf(m, "Board %d: ISA-8-std ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 tports = ports = 8;
3101 break;
3102
3103 case POR_ID_II_8R:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003104 seq_printf(m, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 tports = ports = 8;
3106 break;
3107
3108 default:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003109 seq_printf(m, "Board %d: unknown", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 /* Don't try and probe for minor numbers */
3111 tports = ports = 0;
3112 }
3113
3114 } else {
3115 /* Don't try and probe for minor numbers */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003116 seq_printf(m, "Board %d: vacant", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 tports = ports = 0;
3118 }
3119
3120 if( tports ) {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003121 seq_puts(m, " minors=");
3122 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 for ( box = 0; box < ABS_MAX_BOXES; ++box )
3124 {
3125 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
3126 {
3127 if ( pB->i2eChannelMap[box] & (1 << j) )
3128 {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003129 seq_printf(m, "%s%d", sep,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 j + ABS_BIGGEST_BOX *
3131 (box+i*ABS_MAX_BOXES));
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003132 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 }
3134 }
3135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003137 seq_putc(m, '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003139 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003141
3142static int ip2_proc_open(struct inode *inode, struct file *file)
3143{
3144 return single_open(file, ip2_proc_show, NULL);
3145}
3146
3147static const struct file_operations ip2_proc_fops = {
3148 .owner = THIS_MODULE,
3149 .open = ip2_proc_open,
3150 .read = seq_read,
3151 .llseek = seq_lseek,
3152 .release = single_release,
3153};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154
3155/******************************************************************************/
3156/* Function: ip2trace() */
3157/* Parameters: Value to add to trace buffer */
3158/* Returns: Nothing */
3159/* */
3160/* Description: */
3161/* */
3162/* */
3163/******************************************************************************/
3164#ifdef IP2DEBUG_TRACE
3165void
3166ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
3167{
3168 long flags;
3169 unsigned long *pCode = &codes;
3170 union ip2breadcrumb bc;
3171 i2ChanStrPtr pCh;
3172
3173
3174 tracebuf[tracestuff++] = jiffies;
3175 if ( tracestuff == TRACEMAX ) {
3176 tracestuff = 0;
3177 }
3178 if ( tracestuff == tracestrip ) {
3179 if ( ++tracestrip == TRACEMAX ) {
3180 tracestrip = 0;
3181 }
3182 ++tracewrap;
3183 }
3184
3185 bc.hdr.port = 0xff & pn;
3186 bc.hdr.cat = cat;
3187 bc.hdr.codes = (unsigned char)( codes & 0xff );
3188 bc.hdr.label = label;
3189 tracebuf[tracestuff++] = bc.value;
3190
3191 for (;;) {
3192 if ( tracestuff == TRACEMAX ) {
3193 tracestuff = 0;
3194 }
3195 if ( tracestuff == tracestrip ) {
3196 if ( ++tracestrip == TRACEMAX ) {
3197 tracestrip = 0;
3198 }
3199 ++tracewrap;
3200 }
3201
3202 if ( !codes-- )
3203 break;
3204
3205 tracebuf[tracestuff++] = *++pCode;
3206 }
3207}
3208#endif
3209
3210
3211MODULE_LICENSE("GPL");
Chuck Shorteb0e71c2006-07-10 04:43:59 -07003212
3213static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
3214 { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
3215 { }
3216};
3217
3218MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);
Ben Hutchingse6c4ef92010-01-13 23:34:18 +00003219
3220MODULE_FIRMWARE("intelliport2.bin");