blob: 2913d05e825726cd62c22e8196be433542a5b028 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2*
3* (c) 1999 by Computone Corporation
4*
5********************************************************************************
6*
7* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
8* serial I/O controllers.
9*
10* DESCRIPTION: Mainline code for the device driver
11*
12*******************************************************************************/
13// ToDo:
14//
15// Fix the immediate DSS_NOW problem.
16// Work over the channel stats return logic in ip2_ipl_ioctl so they
17// make sense for all 256 possible channels and so the user space
18// utilities will compile and work properly.
19//
20// Done:
21//
22// 1.2.14 /\/\|=mhw=|\/\/
23// Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts.
24// Changed the definition of ip2trace to be more consistent with kernel style
25// Thanks to Andreas Dilger <adilger@turbolabs.com> for these updates
26//
27// 1.2.13 /\/\|=mhw=|\/\/
28// DEVFS: Renamed ttf/{n} to tts/F{n} and cuf/{n} to cua/F{n} to conform
29// to agreed devfs serial device naming convention.
30//
31// 1.2.12 /\/\|=mhw=|\/\/
32// Cleaned up some remove queue cut and paste errors
33//
34// 1.2.11 /\/\|=mhw=|\/\/
35// Clean up potential NULL pointer dereferences
36// Clean up devfs registration
37// Add kernel command line parsing for io and irq
Adrian Bunk9c4b5622006-01-19 18:07:10 +010038// Compile defaults for io and irq are now set in ip2.c not ip2.h!
Linus Torvalds1da177e2005-04-16 15:20:36 -070039// Reworked poll_only hack for explicit parameter setting
40// You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
41// Merged ip2_loadmain and old_ip2_init
42// Converted all instances of interruptible_sleep_on into queue calls
43// Most of these had no race conditions but better to clean up now
44//
45// 1.2.10 /\/\|=mhw=|\/\/
46// Fixed the bottom half interrupt handler and enabled USE_IQI
47// to split the interrupt handler into a formal top-half / bottom-half
48// Fixed timing window on high speed processors that queued messages to
49// the outbound mail fifo faster than the board could handle.
50//
51// 1.2.9
52// Four box EX was barfing on >128k kmalloc, made structure smaller by
53// reducing output buffer size
54//
55// 1.2.8
56// Device file system support (MHW)
57//
58// 1.2.7
59// Fixed
60// Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules
61//
62// 1.2.6
63//Fixes DCD problems
64// DCD was not reported when CLOCAL was set on call to TIOCMGET
65//
66//Enhancements:
67// TIOCMGET requests and waits for status return
68// No DSS interrupts enabled except for DCD when needed
69//
70// For internal use only
71//
72//#define IP2DEBUG_INIT
73//#define IP2DEBUG_OPEN
74//#define IP2DEBUG_WRITE
75//#define IP2DEBUG_READ
76//#define IP2DEBUG_IOCTL
77//#define IP2DEBUG_IPL
78
79//#define IP2DEBUG_TRACE
80//#define DEBUG_FIFO
81
82/************/
83/* Includes */
84/************/
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86#include <linux/ctype.h>
87#include <linux/string.h>
88#include <linux/fcntl.h>
89#include <linux/errno.h>
90#include <linux/module.h>
91#include <linux/signal.h>
92#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070093#include <linux/timer.h>
94#include <linux/interrupt.h>
95#include <linux/pci.h>
96#include <linux/mm.h>
97#include <linux/slab.h>
98#include <linux/major.h>
99#include <linux/wait.h>
100#include <linux/device.h>
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600101#include <linux/smp_lock.h>
David Woodhouse547d8bb2008-06-11 16:57:21 +0100102#include <linux/firmware.h>
103#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105#include <linux/tty.h>
106#include <linux/tty_flip.h>
107#include <linux/termios.h>
108#include <linux/tty_driver.h>
109#include <linux/serial.h>
110#include <linux/ptrace.h>
111#include <linux/ioport.h>
112
113#include <linux/cdk.h>
114#include <linux/comstats.h>
115#include <linux/delay.h>
116#include <linux/bitops.h>
117
118#include <asm/system.h>
119#include <asm/io.h>
120#include <asm/irq.h>
121
122#include <linux/vmalloc.h>
123#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125#include <asm/uaccess.h>
126
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100127#include "ip2types.h"
128#include "ip2trace.h"
129#include "ip2ioctl.h"
130#include "ip2.h"
131#include "i2ellis.h"
132#include "i2lib.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134/*****************
135 * /proc/ip2mem *
136 *****************/
137
138#include <linux/proc_fs.h>
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700139#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700141static const struct file_operations ip2mem_proc_fops;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700142static const struct file_operations ip2_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144/********************/
145/* Type Definitions */
146/********************/
147
148/*************/
149/* Constants */
150/*************/
151
152/* String constants to identify ourselves */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100153static const char pcName[] = "Computone IntelliPort Plus multiport driver";
154static const char pcVersion[] = "1.2.14";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156/* String constants for port names */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100157static const char pcDriver_name[] = "ip2";
158static const char pcIpl[] = "ip2ipl";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160/***********************/
161/* Function Prototypes */
162/***********************/
163
164/* Global module entry functions */
165
166/* Private (static) functions */
167static int ip2_open(PTTY, struct file *);
168static void ip2_close(PTTY, struct file *);
Alan Coxd9e39532006-01-09 20:54:20 -0800169static int ip2_write(PTTY, const unsigned char *, int);
Alan Coxf34d7a52008-04-30 00:54:13 -0700170static int ip2_putchar(PTTY, unsigned char);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static void ip2_flush_chars(PTTY);
172static int ip2_write_room(PTTY);
173static int ip2_chars_in_buf(PTTY);
174static void ip2_flush_buffer(PTTY);
175static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);
Alan Cox606d0992006-12-08 02:38:45 -0800176static void ip2_set_termios(PTTY, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177static void ip2_set_line_discipline(PTTY);
178static void ip2_throttle(PTTY);
179static void ip2_unthrottle(PTTY);
180static void ip2_stop(PTTY);
181static void ip2_start(PTTY);
182static void ip2_hangup(PTTY);
183static int ip2_tiocmget(struct tty_struct *tty, struct file *file);
184static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
185 unsigned int set, unsigned int clear);
186
187static void set_irq(int, int);
David Howellsc4028952006-11-22 14:57:56 +0000188static void ip2_interrupt_bh(struct work_struct *work);
David Howells7d12e782006-10-05 14:55:46 +0100189static irqreturn_t ip2_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void ip2_poll(unsigned long arg);
191static inline void service_all_boards(void);
David Howellsc4028952006-11-22 14:57:56 +0000192static void do_input(struct work_struct *);
193static void do_status(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195static void ip2_wait_until_sent(PTTY,int);
196
Alan Cox606d0992006-12-08 02:38:45 -0800197static void set_params (i2ChanStrPtr, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *);
199static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *);
200
201static ssize_t ip2_ipl_read(struct file *, char __user *, size_t, loff_t *);
202static ssize_t ip2_ipl_write(struct file *, const char __user *, size_t, loff_t *);
Alan Cox47be36a2008-07-25 01:48:13 -0700203static long ip2_ipl_ioctl(struct file *, UINT, ULONG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static int ip2_ipl_open(struct inode *, struct file *);
205
206static int DumpTraceBuffer(char __user *, int);
207static int DumpFifoBuffer( char __user *, int);
208
David Woodhouse547d8bb2008-06-11 16:57:21 +0100209static void ip2_init_board(int, const struct firmware *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210static unsigned short find_eisa_board(int);
211
212/***************/
213/* Static Data */
214/***************/
215
216static struct tty_driver *ip2_tty_driver;
217
218/* Here, then is a table of board pointers which the interrupt routine should
219 * scan through to determine who it must service.
220 */
221static unsigned short i2nBoards; // Number of boards here
222
223static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS];
224
225static i2ChanStrPtr DevTable[IP2_MAX_PORTS];
226//DevTableMem just used to save addresses for kfree
227static void *DevTableMem[IP2_MAX_BOARDS];
228
229/* This is the driver descriptor for the ip2ipl device, which is used to
230 * download the loadware to the boards.
231 */
Arjan van de Ven62322d22006-07-03 00:24:21 -0700232static const struct file_operations ip2_ipl = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 .owner = THIS_MODULE,
234 .read = ip2_ipl_read,
235 .write = ip2_ipl_write,
Alan Cox47be36a2008-07-25 01:48:13 -0700236 .unlocked_ioctl = ip2_ipl_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 .open = ip2_ipl_open,
238};
239
Jiri Slabycf176bc2008-10-13 10:34:36 +0100240static unsigned long irq_counter;
241static unsigned long bh_counter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243// Use immediate queue to service interrupts
244#define USE_IQI
245//#define USE_IQ // PCI&2.2 needs work
246
247/* The timer_list entry for our poll routine. If interrupt operation is not
248 * selected, the board is serviced periodically to see if anything needs doing.
249 */
250#define POLL_TIMEOUT (jiffies + 1)
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700251static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253#ifdef IP2DEBUG_TRACE
254/* Trace (debug) buffer data */
255#define TRACEMAX 1000
256static unsigned long tracebuf[TRACEMAX];
257static int tracestuff;
258static int tracestrip;
259static int tracewrap;
260#endif
261
262/**********/
263/* Macros */
264/**********/
265
Rakib Mullick795877c2009-12-09 12:34:18 -0800266#ifdef IP2DEBUG_OPEN
Alan Cox7d7b93c2008-10-13 10:42:09 +0100267#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
268 tty->name,(pCh->flags), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 tty->count,/*GET_USE_COUNT(module)*/0,s)
270#else
271#define DBG_CNT(s)
272#endif
273
274/********/
275/* Code */
276/********/
277
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100278#include "i2ellis.c" /* Extremely low-level interface services */
279#include "i2cmd.c" /* Standard loadware command definitions */
280#include "i2lib.c" /* High level interface services */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282/* Configuration area for modprobe */
283
284MODULE_AUTHOR("Doug McNash");
285MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
Jiri Slaby47babd42008-10-13 10:34:27 +0100286MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Jiri Slabycf176bc2008-10-13 10:34:36 +0100288static int poll_only;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290static int Eisa_irq;
291static int Eisa_slot;
292
293static int iindx;
294static char rirqs[IP2_MAX_BOARDS];
295static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
296
Jiri Slaby47babd42008-10-13 10:34:27 +0100297/* Note: Add compiled in defaults to these arrays, not to the structure
298 in ip2.h any longer. That structure WILL get overridden
299 by these values, or command line values, or insmod values!!! =mhw=
300*/
301static int io[IP2_MAX_BOARDS];
302static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
303
304MODULE_AUTHOR("Doug McNash");
305MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
306module_param_array(irq, int, NULL, 0);
307MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
308module_param_array(io, int, NULL, 0);
309MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
310module_param(poll_only, bool, 0);
311MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313/* for sysfs class support */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800314static struct class *ip2_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100316/* Some functions to keep track of what irqs we have */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100318static int __init is_valid_irq(int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
320 int *i = Valid_Irqs;
321
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100322 while (*i != 0 && *i != irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 i++;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100324
325 return *i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100328static void __init mark_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
330 rirqs[iindx++] = irq;
331}
332
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100333static int __exit clear_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
335 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100336 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 if (rirqs[i] == irq) {
338 rirqs[i] = 0;
339 return 1;
340 }
341 }
342 return 0;
343}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100345static int have_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100347 /* array init to zeros so 0 irq will not be requested as a side
348 * effect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100350 for (i = 0; i < IP2_MAX_BOARDS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if (rirqs[i] == irq)
352 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return 0;
354}
355
356/******************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357/* Function: cleanup_module() */
358/* Parameters: None */
359/* Returns: Nothing */
360/* */
361/* Description: */
362/* This is a required entry point for an installable module. It has to return */
363/* the device and the driver to a passive state. It should not be necessary */
364/* to reset the board fully, especially as the loadware is downloaded */
365/* externally rather than in the driver. We just want to disable the board */
366/* and clear the loadware to a reset state. To allow this there has to be a */
367/* way to detect whether the board has the loadware running at init time to */
368/* handle subsequent installations of the driver. All memory allocated by the */
369/* driver should be returned since it may be unloaded from memory. */
370/******************************************************************************/
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100371static void __exit ip2_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 int err;
374 int i;
375
Akinobu Mita9d020a22008-10-13 10:35:05 +0100376 del_timer_sync(&PollTimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 /* Reset the boards we have. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100379 for (i = 0; i < IP2_MAX_BOARDS; i++)
380 if (i2BoardPtrTable[i])
381 iiReset(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 /* The following is done at most once, if any boards were installed. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100384 for (i = 0; i < IP2_MAX_BOARDS; i++) {
385 if (i2BoardPtrTable[i]) {
386 iiResetDelay(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 /* free io addresses and Tibet */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100388 release_region(ip2config.addr[i], 8);
tonyj@suse.de07c015e2007-08-07 22:28:44 -0700389 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100390 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
391 4 * i + 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 }
393 /* Disable and remove interrupt handler. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100394 if (ip2config.irq[i] > 0 &&
395 have_requested_irq(ip2config.irq[i])) {
396 free_irq(ip2config.irq[i], (void *)&pcName);
397 clear_requested_irq(ip2config.irq[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 }
399 }
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800400 class_destroy(ip2_class);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100401 err = tty_unregister_driver(ip2_tty_driver);
402 if (err)
403 printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
404 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 put_tty_driver(ip2_tty_driver);
Akinobu Mita68fc4fa2007-07-19 01:47:50 -0700406 unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
Alexey Dobriyanc74c1202008-04-29 01:01:44 -0700407 remove_proc_entry("ip2mem", NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100409 /* free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 for (i = 0; i < IP2_MAX_BOARDS; i++) {
411 void *pB;
412#ifdef CONFIG_PCI
413 if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
414 pci_disable_device(ip2config.pci_dev[i]);
Alan Cox1aff0ec2006-09-30 23:27:59 -0700415 pci_dev_put(ip2config.pci_dev[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 ip2config.pci_dev[i] = NULL;
417 }
418#endif
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100419 pB = i2BoardPtrTable[i];
420 if (pB != NULL) {
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100421 kfree(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 i2BoardPtrTable[i] = NULL;
423 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100424 if (DevTableMem[i] != NULL) {
425 kfree(DevTableMem[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 DevTableMem[i] = NULL;
427 }
428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429}
Jon Schindler83e422b2008-04-30 00:53:53 -0700430module_exit(ip2_cleanup_module);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700432static const struct tty_operations ip2_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 .open = ip2_open,
434 .close = ip2_close,
435 .write = ip2_write,
436 .put_char = ip2_putchar,
437 .flush_chars = ip2_flush_chars,
438 .write_room = ip2_write_room,
439 .chars_in_buffer = ip2_chars_in_buf,
440 .flush_buffer = ip2_flush_buffer,
441 .ioctl = ip2_ioctl,
442 .throttle = ip2_throttle,
443 .unthrottle = ip2_unthrottle,
444 .set_termios = ip2_set_termios,
445 .set_ldisc = ip2_set_line_discipline,
446 .stop = ip2_stop,
447 .start = ip2_start,
448 .hangup = ip2_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 .tiocmget = ip2_tiocmget,
450 .tiocmset = ip2_tiocmset,
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700451 .proc_fops = &ip2_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452};
453
454/******************************************************************************/
455/* Function: ip2_loadmain() */
456/* Parameters: irq, io from command line of insmod et. al. */
457/* pointer to fip firmware and firmware size for boards */
458/* Returns: Success (0) */
459/* */
460/* Description: */
461/* This was the required entry point for all drivers (now in ip2.c) */
462/* It performs all */
463/* initialisation of the devices and driver structures, and registers itself */
464/* with the relevant kernel modules. */
465/******************************************************************************/
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700466/* IRQF_DISABLED - if set blocks all interrupts else only this line */
467/* IRQF_SHARED - for shared irq PCI or maybe EISA only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468/* SA_RANDOM - can be source for cert. random number generators */
469#define IP2_SA_FLAGS 0
470
David Woodhouse547d8bb2008-06-11 16:57:21 +0100471
472static const struct firmware *ip2_request_firmware(void)
473{
474 struct platform_device *pdev;
475 const struct firmware *fw;
476
477 pdev = platform_device_register_simple("ip2", 0, NULL, 0);
478 if (IS_ERR(pdev)) {
479 printk(KERN_ERR "Failed to register platform device for ip2\n");
480 return NULL;
481 }
482 if (request_firmware(&fw, "intelliport2.bin", &pdev->dev)) {
483 printk(KERN_ERR "Failed to load firmware 'intelliport2.bin'\n");
484 fw = NULL;
485 }
486 platform_device_unregister(pdev);
487 return fw;
488}
489
Jiri Slaby47babd42008-10-13 10:34:27 +0100490/******************************************************************************
491 * ip2_setup:
492 * str: kernel command line string
493 *
494 * Can't autoprobe the boards so user must specify configuration on
495 * kernel command line. Sane people build it modular but the others
496 * come here.
497 *
498 * Alternating pairs of io,irq for up to 4 boards.
499 * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
500 *
501 * io=0 => No board
502 * io=1 => PCI
503 * io=2 => EISA
504 * else => ISA I/O address
505 *
506 * irq=0 or invalid for ISA will revert to polling mode
507 *
508 * Any value = -1, do not overwrite compiled in value.
509 *
510 ******************************************************************************/
511static int __init ip2_setup(char *str)
512{
513 int j, ints[10]; /* 4 boards, 2 parameters + 2 */
514 unsigned int i;
515
516 str = get_options(str, ARRAY_SIZE(ints), ints);
517
518 for (i = 0, j = 1; i < 4; i++) {
519 if (j > ints[0])
520 break;
521 if (ints[j] >= 0)
522 io[i] = ints[j];
523 j++;
524 if (j > ints[0])
525 break;
526 if (ints[j] >= 0)
527 irq[i] = ints[j];
528 j++;
529 }
530 return 1;
531}
532__setup("ip2=", ip2_setup);
Jiri Slaby47babd42008-10-13 10:34:27 +0100533
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100534static int __init ip2_loadmain(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535{
536 int i, j, box;
537 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 i2eBordStrPtr pB = NULL;
539 int rc = -1;
David Woodhouse547d8bb2008-06-11 16:57:21 +0100540 const struct firmware *fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Jiri Slaby47babd42008-10-13 10:34:27 +0100542 if (poll_only) {
543 /* Hard lock the interrupts to zero */
544 irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
545 }
546
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100547 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 /* process command line arguments to modprobe or
550 insmod i.e. iop & irqp */
551 /* irqp and iop should ALWAYS be specified now... But we check
552 them individually just to be sure, anyways... */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100553 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Jiri Slaby47babd42008-10-13 10:34:27 +0100554 ip2config.addr[i] = io[i];
555 if (irq[i] >= 0)
556 ip2config.irq[i] = irq[i];
557 else
558 ip2config.irq[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100559 /* This is a little bit of a hack. If poll_only=1 on command
560 line back in ip2.c OR all IRQs on all specified boards are
561 explicitly set to 0, then drop to poll only mode and override
562 PCI or EISA interrupts. This superceeds the old hack of
563 triggering if all interrupts were zero (like da default).
564 Still a hack but less prone to random acts of terrorism.
565
566 What we really should do, now that the IRQ default is set
567 to -1, is to use 0 as a hard coded, do not probe.
568
569 /\/\|=mhw=|\/\/
570 */
Jiri Slaby47babd42008-10-13 10:34:27 +0100571 poll_only |= irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 }
573 poll_only = !poll_only;
574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 /* Announce our presence */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100576 printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
579 if (!ip2_tty_driver)
580 return -ENOMEM;
581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 /* Initialise all the boards we can find (up to the maximum). */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100583 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
584 switch (ip2config.addr[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 case 0: /* skip this slot even if card is present */
586 break;
587 default: /* ISA */
588 /* ISA address must be specified */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100589 if (ip2config.addr[i] < 0x100 ||
590 ip2config.addr[i] > 0x3f8) {
591 printk(KERN_ERR "IP2: Bad ISA board %d "
592 "address %x\n", i,
593 ip2config.addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 ip2config.addr[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100595 break;
596 }
597 ip2config.type[i] = ISA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100599 /* Check for valid irq argument, set for polling if
600 * invalid */
601 if (ip2config.irq[i] &&
602 !is_valid_irq(ip2config.irq[i])) {
603 printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
604 ip2config.irq[i]);
605 /* 0 is polling and is valid in that sense */
606 ip2config.irq[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 }
608 break;
609 case PCI:
610#ifdef CONFIG_PCI
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100611 {
Rakib Mullick795877c2009-12-09 12:34:18 -0800612 struct pci_dev *pdev = NULL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100613 u32 addr;
614 int status;
Andrew Mortonad4a5bb2007-07-31 00:39:41 -0700615
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100616 pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
617 PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
618 if (pdev == NULL) {
619 ip2config.addr[i] = 0;
620 printk(KERN_ERR "IP2: PCI board %d not "
621 "found\n", i);
622 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100624
625 if (pci_enable_device(pdev)) {
626 dev_err(&pdev->dev, "can't enable device\n");
Rakib Mullick795877c2009-12-09 12:34:18 -0800627 goto out;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100628 }
629 ip2config.type[i] = PCI;
630 ip2config.pci_dev[i] = pci_dev_get(pdev);
631 status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
632 &addr);
633 if (addr & 1)
634 ip2config.addr[i] = (USHORT)(addr & 0xfffe);
635 else
636 dev_err(&pdev->dev, "I/O address error\n");
637
638 ip2config.irq[i] = pdev->irq;
Rakib Mullick795877c2009-12-09 12:34:18 -0800639out:
640 pci_dev_put(pdev);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642#else
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100643 printk(KERN_ERR "IP2: PCI card specified but PCI "
644 "support not enabled.\n");
645 printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
646 "defined!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647#endif /* CONFIG_PCI */
648 break;
649 case EISA:
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100650 ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
651 if (ip2config.addr[i] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 /* Eisa_irq set as side effect, boo */
653 ip2config.type[i] = EISA;
654 }
655 ip2config.irq[i] = Eisa_irq;
656 break;
657 } /* switch */
658 } /* for */
Alan Cox1aff0ec2006-09-30 23:27:59 -0700659
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100660 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
661 if (ip2config.addr[i]) {
Mariusz Kozlowski978550b2007-10-16 23:26:45 -0700662 pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
663 if (pB) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 i2BoardPtrTable[i] = pB;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100665 iiSetAddress(pB, ip2config.addr[i],
666 ii2DelayTimer);
667 iiReset(pB);
668 } else
669 printk(KERN_ERR "IP2: board memory allocation "
670 "error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 }
672 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100673 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
674 pB = i2BoardPtrTable[i];
675 if (pB != NULL) {
676 iiResetDelay(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 break;
678 }
679 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100680 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100681 /* We don't want to request the firmware unless we have at
682 least one board */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100683 if (i2BoardPtrTable[i] != NULL) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100684 if (!fw)
685 fw = ip2_request_firmware();
686 if (!fw)
687 break;
688 ip2_init_board(i, fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
690 }
David Woodhouse547d8bb2008-06-11 16:57:21 +0100691 if (fw)
692 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100694 ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
696 ip2_tty_driver->owner = THIS_MODULE;
697 ip2_tty_driver->name = "ttyF";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 ip2_tty_driver->driver_name = pcDriver_name;
699 ip2_tty_driver->major = IP2_TTY_MAJOR;
700 ip2_tty_driver->minor_start = 0;
701 ip2_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
702 ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL;
703 ip2_tty_driver->init_termios = tty_std_termios;
704 ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100705 ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW |
706 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 tty_set_operations(ip2_tty_driver, &ip2_ops);
708
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100709 ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100711 err = tty_register_driver(ip2_tty_driver);
712 if (err) {
713 printk(KERN_ERR "IP2: failed to register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 put_tty_driver(ip2_tty_driver);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100715 return err; /* leaking resources */
716 }
717
718 err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
719 if (err) {
720 printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
721 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 } else {
723 /* create the sysfs class */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800724 ip2_class = class_create(THIS_MODULE, "ip2");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 if (IS_ERR(ip2_class)) {
726 err = PTR_ERR(ip2_class);
727 goto out_chrdev;
728 }
729 }
730 /* Register the read_procmem thing */
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700731 if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 printk(KERN_ERR "IP2: failed to register read_procmem\n");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100733 return -EIO; /* leaking resources */
734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100736 ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
737 /* Register the interrupt handler or poll handler, depending upon the
738 * specified interrupt.
739 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100741 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
742 if (ip2config.addr[i] == 0)
743 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100745 pB = i2BoardPtrTable[i];
746 if (pB != NULL) {
Greg Kroah-Hartman03457cd2008-07-21 20:03:34 -0700747 device_create(ip2_class, NULL,
748 MKDEV(IP2_IPL_MAJOR, 4 * i),
749 NULL, "ipl%d", i);
750 device_create(ip2_class, NULL,
751 MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
752 NULL, "stat%d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100754 for (box = 0; box < ABS_MAX_BOXES; box++)
755 for (j = 0; j < ABS_BIGGEST_BOX; j++)
756 if (pB->i2eChannelMap[box] & (1 << j))
757 tty_register_device(
758 ip2_tty_driver,
759 j + ABS_BIGGEST_BOX *
760 (box+i*ABS_MAX_BOXES),
761 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100763
764 if (poll_only) {
765 /* Poll only forces driver to only use polling and
766 to ignore the probed PCI or EISA interrupts. */
767 ip2config.irq[i] = CIR_POLL;
768 }
769 if (ip2config.irq[i] == CIR_POLL) {
770retry:
Akinobu Mita9d020a22008-10-13 10:35:05 +0100771 if (!timer_pending(&PollTimer)) {
772 mod_timer(&PollTimer, POLL_TIMEOUT);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100773 printk(KERN_INFO "IP2: polling\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100775 } else {
776 if (have_requested_irq(ip2config.irq[i]))
777 continue;
778 rc = request_irq(ip2config.irq[i], ip2_interrupt,
779 IP2_SA_FLAGS |
780 (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
781 pcName, i2BoardPtrTable[i]);
782 if (rc) {
783 printk(KERN_ERR "IP2: request_irq failed: "
784 "error %d\n", rc);
785 ip2config.irq[i] = CIR_POLL;
786 printk(KERN_INFO "IP2: Polling %ld/sec.\n",
787 (POLL_TIMEOUT - jiffies));
788 goto retry;
789 }
790 mark_requested_irq(ip2config.irq[i]);
791 /* Initialise the interrupt handler bottom half
792 * (aka slih). */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
794 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100795
796 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
797 if (i2BoardPtrTable[i]) {
798 /* set and enable board interrupt */
799 set_irq(i, ip2config.irq[i]);
800 }
801 }
802
803 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
804
805 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807out_chrdev:
808 unregister_chrdev(IP2_IPL_MAJOR, "ip2");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100809 /* unregister and put tty here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return err;
811}
Jiri Slaby47babd42008-10-13 10:34:27 +0100812module_init(ip2_loadmain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814/******************************************************************************/
815/* Function: ip2_init_board() */
816/* Parameters: Index of board in configuration structure */
817/* Returns: Success (0) */
818/* */
819/* Description: */
820/* This function initializes the specified board. The loadware is copied to */
821/* the board, the channel structures are initialized, and the board details */
822/* are reported on the console. */
823/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700824static void
David Woodhouse547d8bb2008-06-11 16:57:21 +0100825ip2_init_board(int boardnum, const struct firmware *fw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826{
827 int i;
828 int nports = 0, nboxes = 0;
829 i2ChanStrPtr pCh;
830 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
831
832 if ( !iiInitialize ( pB ) ) {
833 printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
834 pB->i2eBase, pB->i2eError );
835 goto err_initialize;
836 }
837 printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
838 ip2config.addr[boardnum], ip2config.irq[boardnum] );
839
840 if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
841 printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
842 goto err_initialize;
843 }
844
David Woodhouse547d8bb2008-06-11 16:57:21 +0100845 if ( iiDownloadAll ( pB, (loadHdrStrPtr)fw->data, 1, fw->size )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 != II_DOWN_GOOD ) {
847 printk ( KERN_ERR "IP2: failed to download loadware\n" );
848 goto err_release_region;
849 } else {
850 printk ( KERN_INFO "IP2: fv=%d.%d.%d lv=%d.%d.%d\n",
851 pB->i2ePom.e.porVersion,
852 pB->i2ePom.e.porRevision,
853 pB->i2ePom.e.porSubRev, pB->i2eLVersion,
854 pB->i2eLRevision, pB->i2eLSub );
855 }
856
857 switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
858
859 default:
860 printk( KERN_ERR "IP2: Unknown board type, ID = %x\n",
861 pB->i2ePom.e.porID );
862 nports = 0;
863 goto err_release_region;
864 break;
865
866 case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
867 printk ( KERN_INFO "IP2: ISA-4\n" );
868 nports = 4;
869 break;
870
871 case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
872 printk ( KERN_INFO "IP2: ISA-8 std\n" );
873 nports = 8;
874 break;
875
876 case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
877 printk ( KERN_INFO "IP2: ISA-8 RJ11\n" );
878 nports = 8;
879 break;
880
881 case POR_ID_FIIEX: /* IntelliPort IIEX */
882 {
883 int portnum = IP2_PORTS_PER_BOARD * boardnum;
884 int box;
885
886 for( box = 0; box < ABS_MAX_BOXES; ++box ) {
887 if ( pB->i2eChannelMap[box] != 0 ) {
888 ++nboxes;
889 }
890 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
891 if ( pB->i2eChannelMap[box] & 1<< i ) {
892 ++nports;
893 }
894 }
895 }
896 DevTableMem[boardnum] = pCh =
897 kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
898 if ( !pCh ) {
899 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
900 goto err_release_region;
901 }
902 if ( !i2InitChannels( pB, nports, pCh ) ) {
903 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
904 kfree ( pCh );
905 goto err_release_region;
906 }
907 pB->i2eChannelPtr = &DevTable[portnum];
908 pB->i2eChannelCnt = ABS_MOST_PORTS;
909
910 for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
911 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
912 if ( pB->i2eChannelMap[box] & (1 << i) ) {
913 DevTable[portnum + i] = pCh;
914 pCh->port_index = portnum + i;
915 pCh++;
916 }
917 }
918 }
919 printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit\n",
920 nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
921 }
922 goto ex_exit;
923 }
924 DevTableMem[boardnum] = pCh =
925 kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
926 if ( !pCh ) {
927 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
928 goto err_release_region;
929 }
930 pB->i2eChannelPtr = pCh;
931 pB->i2eChannelCnt = nports;
932 if ( !i2InitChannels( pB, nports, pCh ) ) {
933 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
934 kfree ( pCh );
935 goto err_release_region;
936 }
937 pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
938
939 for( i = 0; i < pB->i2eChannelCnt; ++i ) {
940 DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
941 pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
942 pCh++;
943 }
944ex_exit:
David Howellsc4028952006-11-22 14:57:56 +0000945 INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 return;
947
948err_release_region:
949 release_region(ip2config.addr[boardnum], 8);
950err_initialize:
951 kfree ( pB );
952 i2BoardPtrTable[boardnum] = NULL;
953 return;
954}
955
956/******************************************************************************/
957/* Function: find_eisa_board ( int start_slot ) */
958/* Parameters: First slot to check */
959/* Returns: Address of EISA IntelliPort II controller */
960/* */
961/* Description: */
962/* This function searches for an EISA IntelliPort controller, starting */
963/* from the specified slot number. If the motherboard is not identified as an */
964/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
965/* it returns the base address of the controller. */
966/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700967static unsigned short
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968find_eisa_board( int start_slot )
969{
970 int i, j;
971 unsigned int idm = 0;
972 unsigned int idp = 0;
973 unsigned int base = 0;
974 unsigned int value;
975 int setup_address;
976 int setup_irq;
977 int ismine = 0;
978
979 /*
980 * First a check for an EISA motherboard, which we do by comparing the
981 * EISA ID registers for the system board and the first couple of slots.
982 * No slot ID should match the system board ID, but on an ISA or PCI
983 * machine the odds are that an empty bus will return similar values for
984 * each slot.
985 */
986 i = 0x0c80;
987 value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
988 for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
989 j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
990 if ( value == j )
991 return 0;
992 }
993
994 /*
995 * OK, so we are inclined to believe that this is an EISA machine. Find
996 * an IntelliPort controller.
997 */
998 for( i = start_slot; i < 16; i++ ) {
999 base = i << 12;
1000 idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
1001 idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
1002 ismine = 0;
1003 if ( idm == 0x0e8e ) {
1004 if ( idp == 0x0281 || idp == 0x0218 ) {
1005 ismine = 1;
1006 } else if ( idp == 0x0282 || idp == 0x0283 ) {
1007 ismine = 3; /* Can do edge-trigger */
1008 }
1009 if ( ismine ) {
1010 Eisa_slot = i;
1011 break;
1012 }
1013 }
1014 }
1015 if ( !ismine )
1016 return 0;
1017
1018 /* It's some sort of EISA card, but at what address is it configured? */
1019
1020 setup_address = base + 0xc88;
1021 value = inb(base + 0xc86);
1022 setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
1023
1024 if ( (ismine & 2) && !(value & 0x10) ) {
1025 ismine = 1; /* Could be edging, but not */
1026 }
1027
1028 if ( Eisa_irq == 0 ) {
1029 Eisa_irq = setup_irq;
1030 } else if ( Eisa_irq != setup_irq ) {
1031 printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
1032 }
1033
1034#ifdef IP2DEBUG_INIT
1035printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
1036 base >> 12, idm, idp, setup_address);
1037 if ( Eisa_irq ) {
1038 printk(KERN_DEBUG ", Interrupt %d %s\n",
1039 setup_irq, (ismine & 2) ? "(edge)" : "(level)");
1040 } else {
1041 printk(KERN_DEBUG ", (polled)\n");
1042 }
1043#endif
1044 return setup_address;
1045}
1046
1047/******************************************************************************/
1048/* Function: set_irq() */
1049/* Parameters: index to board in board table */
1050/* IRQ to use */
1051/* Returns: Success (0) */
1052/* */
1053/* Description: */
1054/******************************************************************************/
1055static void
1056set_irq( int boardnum, int boardIrq )
1057{
1058 unsigned char tempCommand[16];
1059 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
1060 unsigned long flags;
1061
1062 /*
1063 * Notify the boards they may generate interrupts. This is done by
1064 * sending an in-line command to channel 0 on each board. This is why
1065 * the channels have to be defined already. For each board, if the
1066 * interrupt has never been defined, we must do so NOW, directly, since
1067 * board will not send flow control or even give an interrupt until this
1068 * is done. If polling we must send 0 as the interrupt parameter.
1069 */
1070
1071 // We will get an interrupt here at the end of this function
1072
1073 iiDisableMailIrq(pB);
1074
1075 /* We build up the entire packet header. */
1076 CHANNEL_OF(tempCommand) = 0;
1077 PTYPE_OF(tempCommand) = PTYPE_INLINE;
1078 CMD_COUNT_OF(tempCommand) = 2;
1079 (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
1080 (CMD_OF(tempCommand))[1] = boardIrq;
1081 /*
1082 * Write to FIFO; don't bother to adjust fifo capacity for this, since
1083 * board will respond almost immediately after SendMail hit.
1084 */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001085 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001087 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 pB->i2eUsingIrq = boardIrq;
1089 pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
1090
1091 /* Need to update number of boards before you enable mailbox int */
1092 ++i2nBoards;
1093
1094 CHANNEL_OF(tempCommand) = 0;
1095 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1096 CMD_COUNT_OF(tempCommand) = 6;
1097 (CMD_OF(tempCommand))[0] = 88; // SILO
1098 (CMD_OF(tempCommand))[1] = 64; // chars
1099 (CMD_OF(tempCommand))[2] = 32; // ms
1100
1101 (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK
1102 (CMD_OF(tempCommand))[4] = 64; // chars
1103
1104 (CMD_OF(tempCommand))[5] = 87; // HW_TEST
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001105 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 iiWriteBuf(pB, tempCommand, 8);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001107 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
1109 CHANNEL_OF(tempCommand) = 0;
1110 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1111 CMD_COUNT_OF(tempCommand) = 1;
1112 (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */
1113 iiWriteBuf(pB, tempCommand, 3);
1114
1115#ifdef XXX
1116 // enable heartbeat for test porpoises
1117 CHANNEL_OF(tempCommand) = 0;
1118 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1119 CMD_COUNT_OF(tempCommand) = 2;
1120 (CMD_OF(tempCommand))[0] = 44; /* get ping */
1121 (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001122 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001124 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125#endif
1126
1127 iiEnableMailIrq(pB);
1128 iiSendPendingMail(pB);
1129}
1130
1131/******************************************************************************/
1132/* Interrupt Handler Section */
1133/******************************************************************************/
1134
1135static inline void
1136service_all_boards(void)
1137{
1138 int i;
1139 i2eBordStrPtr pB;
1140
1141 /* Service every board on the list */
1142 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
1143 pB = i2BoardPtrTable[i];
1144 if ( pB ) {
1145 i2ServiceBoard( pB );
1146 }
1147 }
1148}
1149
1150
1151/******************************************************************************/
David Howellsc4028952006-11-22 14:57:56 +00001152/* Function: ip2_interrupt_bh(work) */
1153/* Parameters: work - pointer to the board structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154/* Returns: Nothing */
1155/* */
1156/* Description: */
1157/* Service the board in a bottom half interrupt handler and then */
1158/* reenable the board's interrupts if it has an IRQ number */
1159/* */
1160/******************************************************************************/
1161static void
David Howellsc4028952006-11-22 14:57:56 +00001162ip2_interrupt_bh(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163{
David Howellsc4028952006-11-22 14:57:56 +00001164 i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165// pB better well be set or we have a problem! We can only get
1166// here from the IMMEDIATE queue. Here, we process the boards.
1167// Checking pB doesn't cost much and it saves us from the sanity checkers.
1168
1169 bh_counter++;
1170
1171 if ( pB ) {
1172 i2ServiceBoard( pB );
1173 if( pB->i2eUsingIrq ) {
1174// Re-enable his interrupts
1175 iiEnableMailIrq(pB);
1176 }
1177 }
1178}
1179
1180
1181/******************************************************************************/
David Howells7d12e782006-10-05 14:55:46 +01001182/* Function: ip2_interrupt(int irq, void *dev_id) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183/* Parameters: irq - interrupt number */
1184/* pointer to optional device ID structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185/* Returns: Nothing */
1186/* */
1187/* Description: */
1188/* */
1189/* Our task here is simply to identify each board which needs servicing. */
1190/* If we are queuing then, queue it to be serviced, and disable its irq */
1191/* mask otherwise process the board directly. */
1192/* */
1193/* We could queue by IRQ but that just complicates things on both ends */
1194/* with very little gain in performance (how many instructions does */
1195/* it take to iterate on the immediate queue). */
1196/* */
1197/* */
1198/******************************************************************************/
Jeff Garzikf3518e42007-10-19 15:24:59 -04001199static void
1200ip2_irq_work(i2eBordStrPtr pB)
1201{
1202#ifdef USE_IQI
1203 if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
1204// Disable his interrupt (will be enabled when serviced)
1205// This is mostly to protect from reentrancy.
1206 iiDisableMailIrq(pB);
1207
1208// Park the board on the immediate queue for processing.
1209 schedule_work(&pB->tqueue_interrupt);
1210
1211// Make sure the immediate queue is flagged to fire.
1212 }
1213#else
1214
1215// We are using immediate servicing here. This sucks and can
1216// cause all sorts of havoc with ppp and others. The failsafe
1217// check on iiSendPendingMail could also throw a hairball.
1218
1219 i2ServiceBoard( pB );
1220
1221#endif /* USE_IQI */
1222}
1223
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001224static void
1225ip2_polled_interrupt(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226{
1227 int i;
1228 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001230 ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
1232 /* Service just the boards on the list using this irq */
1233 for( i = 0; i < i2nBoards; ++i ) {
1234 pB = i2BoardPtrTable[i];
1235
1236// Only process those boards which match our IRQ.
1237// IRQ = 0 for polled boards, we won't poll "IRQ" boards
1238
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001239 if (pB && pB->i2eUsingIrq == 0)
Jeff Garzikf3518e42007-10-19 15:24:59 -04001240 ip2_irq_work(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 }
1242
1243 ++irq_counter;
1244
1245 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001246}
1247
1248static irqreturn_t
1249ip2_interrupt(int irq, void *dev_id)
1250{
1251 i2eBordStrPtr pB = dev_id;
1252
1253 ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, pB->i2eUsingIrq );
1254
1255 ip2_irq_work(pB);
1256
1257 ++irq_counter;
1258
1259 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1260 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261}
1262
1263/******************************************************************************/
1264/* Function: ip2_poll(unsigned long arg) */
1265/* Parameters: ? */
1266/* Returns: Nothing */
1267/* */
1268/* Description: */
1269/* This function calls the library routine i2ServiceBoard for each board in */
1270/* the board table. This is used instead of the interrupt routine when polled */
1271/* mode is specified. */
1272/******************************************************************************/
1273static void
1274ip2_poll(unsigned long arg)
1275{
1276 ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
1279 // It will NOT poll boards handled by hard interrupts.
Joe Perches8dfba4d2008-02-03 17:11:42 +02001280 // The issue of queued BH interrupts is handled in ip2_interrupt().
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001281 ip2_polled_interrupt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Akinobu Mita9d020a22008-10-13 10:35:05 +01001283 mod_timer(&PollTimer, POLL_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
1285 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1286}
1287
David Howellsc4028952006-11-22 14:57:56 +00001288static void do_input(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
David Howellsc4028952006-11-22 14:57:56 +00001290 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 unsigned long flags;
1292
1293 ip2trace(CHANN, ITRC_INPUT, 21, 0 );
1294
1295 // Data input
1296 if ( pCh->pTTY != NULL ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001297 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001299 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 i2Input( pCh );
1301 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001302 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 } else {
1304 ip2trace(CHANN, ITRC_INPUT, 22, 0 );
1305
1306 i2InputFlush( pCh );
1307 }
1308}
1309
1310// code duplicated from n_tty (ldisc)
1311static inline void isig(int sig, struct tty_struct *tty, int flush)
1312{
Alan Coxa352def2008-07-16 21:53:12 +01001313 /* FIXME: This is completely bogus */
Eric W. Biedermanab521dc2007-02-12 00:53:00 -08001314 if (tty->pgrp)
1315 kill_pgrp(tty->pgrp, sig, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 if (flush || !L_NOFLSH(tty)) {
Alan Coxc65c9bc2009-06-11 12:50:12 +01001317 if ( tty->ldisc->ops->flush_buffer )
1318 tty->ldisc->ops->flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 i2InputFlush( tty->driver_data );
1320 }
1321}
1322
David Howellsc4028952006-11-22 14:57:56 +00001323static void do_status(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324{
David Howellsc4028952006-11-22 14:57:56 +00001325 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 int status;
1327
1328 status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
1329
1330 ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
1331
1332 if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
1333 if ( (status & I2_BRK) ) {
1334 // code duplicated from n_tty (ldisc)
1335 if (I_IGNBRK(pCh->pTTY))
1336 goto skip_this;
1337 if (I_BRKINT(pCh->pTTY)) {
1338 isig(SIGINT, pCh->pTTY, 1);
1339 goto skip_this;
1340 }
1341 wake_up_interruptible(&pCh->pTTY->read_wait);
1342 }
1343#ifdef NEVER_HAPPENS_AS_SETUP_XXX
1344 // and can't work because we don't know the_char
1345 // as the_char is reported on a separate path
1346 // The intelligent board does this stuff as setup
1347 {
1348 char brkf = TTY_NORMAL;
1349 unsigned char brkc = '\0';
1350 unsigned char tmp;
1351 if ( (status & I2_BRK) ) {
1352 brkf = TTY_BREAK;
1353 brkc = '\0';
1354 }
1355 else if (status & I2_PAR) {
1356 brkf = TTY_PARITY;
1357 brkc = the_char;
1358 } else if (status & I2_FRA) {
1359 brkf = TTY_FRAME;
1360 brkc = the_char;
1361 } else if (status & I2_OVR) {
1362 brkf = TTY_OVERRUN;
1363 brkc = the_char;
1364 }
1365 tmp = pCh->pTTY->real_raw;
1366 pCh->pTTY->real_raw = 0;
Alan Coxa352def2008-07-16 21:53:12 +01001367 pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 pCh->pTTY->real_raw = tmp;
1369 }
1370#endif /* NEVER_HAPPENS_AS_SETUP_XXX */
1371 }
1372skip_this:
1373
1374 if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
1375 wake_up_interruptible(&pCh->delta_msr_wait);
1376
1377 if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
1378 if ( status & I2_DCD ) {
1379 if ( pCh->wopen ) {
1380 wake_up_interruptible ( &pCh->open_wait );
1381 }
1382 } else {
1383 if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
1384 tty_hangup( pCh->pTTY );
1385 }
1386 }
1387 }
1388 }
1389
1390 ip2trace (CHANN, ITRC_STATUS, 26, 0 );
1391}
1392
1393/******************************************************************************/
1394/* Device Open/Close/Ioctl Entry Point Section */
1395/******************************************************************************/
1396
1397/******************************************************************************/
1398/* Function: open_sanity_check() */
1399/* Parameters: Pointer to tty structure */
1400/* Pointer to file structure */
1401/* Returns: Success or failure */
1402/* */
1403/* Description: */
1404/* Verifies the structure magic numbers and cross links. */
1405/******************************************************************************/
1406#ifdef IP2DEBUG_OPEN
1407static void
1408open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
1409{
1410 if ( pBrd->i2eValid != I2E_MAGIC ) {
1411 printk(KERN_ERR "IP2: invalid board structure\n" );
1412 } else if ( pBrd != pCh->pMyBord ) {
1413 printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
1414 pCh->pMyBord );
1415 } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
1416 printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
1417 } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
1418 } else {
1419 printk(KERN_INFO "IP2: all pointers check out!\n" );
1420 }
1421}
1422#endif
1423
1424
1425/******************************************************************************/
1426/* Function: ip2_open() */
1427/* Parameters: Pointer to tty structure */
1428/* Pointer to file structure */
1429/* Returns: Success or failure */
1430/* */
1431/* Description: (MANDATORY) */
1432/* A successful device open has to run a gauntlet of checks before it */
1433/* completes. After some sanity checking and pointer setup, the function */
1434/* blocks until all conditions are satisfied. It then initialises the port to */
1435/* the default characteristics and returns. */
1436/******************************************************************************/
1437static int
1438ip2_open( PTTY tty, struct file *pFile )
1439{
1440 wait_queue_t wait;
1441 int rc = 0;
1442 int do_clocal = 0;
1443 i2ChanStrPtr pCh = DevTable[tty->index];
1444
1445 ip2trace (tty->index, ITRC_OPEN, ITRC_ENTER, 0 );
1446
1447 if ( pCh == NULL ) {
1448 return -ENODEV;
1449 }
1450 /* Setup pointer links in device and tty structures */
1451 pCh->pTTY = tty;
1452 tty->driver_data = pCh;
1453
1454#ifdef IP2DEBUG_OPEN
1455 printk(KERN_DEBUG \
1456 "IP2:open(tty=%p,pFile=%p):dev=%s,ch=%d,idx=%d\n",
1457 tty, pFile, tty->name, pCh->infl.hd.i2sChannel, pCh->port_index);
1458 open_sanity_check ( pCh, pCh->pMyBord );
1459#endif
1460
1461 i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP);
1462 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1463 serviceOutgoingFifo( pCh->pMyBord );
1464
1465 /* Block here until the port is ready (per serial and istallion) */
1466 /*
1467 * 1. If the port is in the middle of closing wait for the completion
1468 * and then return the appropriate error.
1469 */
1470 init_waitqueue_entry(&wait, current);
1471 add_wait_queue(&pCh->close_wait, &wait);
1472 set_current_state( TASK_INTERRUPTIBLE );
1473
1474 if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
1475 if ( pCh->flags & ASYNC_CLOSING ) {
1476 schedule();
1477 }
1478 if ( tty_hung_up_p(pFile) ) {
1479 set_current_state( TASK_RUNNING );
1480 remove_wait_queue(&pCh->close_wait, &wait);
1481 return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
1482 }
1483 }
1484 set_current_state( TASK_RUNNING );
1485 remove_wait_queue(&pCh->close_wait, &wait);
1486
1487 /*
1488 * 3. Handle a non-blocking open of a normal port.
1489 */
1490 if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
1491 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1492 goto noblock;
1493 }
1494 /*
1495 * 4. Now loop waiting for the port to be free and carrier present
1496 * (if required).
1497 */
1498 if ( tty->termios->c_cflag & CLOCAL )
1499 do_clocal = 1;
1500
1501#ifdef IP2DEBUG_OPEN
1502 printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
1503#endif
1504
1505 ++pCh->wopen;
1506
1507 init_waitqueue_entry(&wait, current);
1508 add_wait_queue(&pCh->open_wait, &wait);
1509
1510 for(;;) {
1511 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1512 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1513 set_current_state( TASK_INTERRUPTIBLE );
1514 serviceOutgoingFifo( pCh->pMyBord );
1515 if ( tty_hung_up_p(pFile) ) {
1516 set_current_state( TASK_RUNNING );
1517 remove_wait_queue(&pCh->open_wait, &wait);
1518 return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
1519 }
1520 if (!(pCh->flags & ASYNC_CLOSING) &&
1521 (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
1522 rc = 0;
1523 break;
1524 }
1525
1526#ifdef IP2DEBUG_OPEN
1527 printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
1528 (pCh->flags & ASYNC_CLOSING)?"True":"False");
1529 printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
1530#endif
1531 ip2trace (CHANN, ITRC_OPEN, 3, 2, 0,
1532 (pCh->flags & ASYNC_CLOSING) );
1533 /* check for signal */
1534 if (signal_pending(current)) {
1535 rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
1536 break;
1537 }
1538 schedule();
1539 }
1540 set_current_state( TASK_RUNNING );
1541 remove_wait_queue(&pCh->open_wait, &wait);
1542
1543 --pCh->wopen; //why count?
1544
1545 ip2trace (CHANN, ITRC_OPEN, 4, 0 );
1546
1547 if (rc != 0 ) {
1548 return rc;
1549 }
1550 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1551
1552noblock:
1553
1554 /* first open - Assign termios structure to port */
1555 if ( tty->count == 1 ) {
1556 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1557 /* Now we must send the termios settings to the loadware */
1558 set_params( pCh, NULL );
1559 }
1560
1561 /*
1562 * Now set any i2lib options. These may go away if the i2lib code ends
1563 * up rolled into the mainline.
1564 */
1565 pCh->channelOptions |= CO_NBLOCK_WRITE;
1566
1567#ifdef IP2DEBUG_OPEN
1568 printk (KERN_DEBUG "IP2: open completed\n" );
1569#endif
1570 serviceOutgoingFifo( pCh->pMyBord );
1571
1572 ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
1573
1574 return 0;
1575}
1576
1577/******************************************************************************/
1578/* Function: ip2_close() */
1579/* Parameters: Pointer to tty structure */
1580/* Pointer to file structure */
1581/* Returns: Nothing */
1582/* */
1583/* Description: */
1584/* */
1585/* */
1586/******************************************************************************/
1587static void
1588ip2_close( PTTY tty, struct file *pFile )
1589{
1590 i2ChanStrPtr pCh = tty->driver_data;
1591
1592 if ( !pCh ) {
1593 return;
1594 }
1595
1596 ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
1597
1598#ifdef IP2DEBUG_OPEN
1599 printk(KERN_DEBUG "IP2:close %s:\n",tty->name);
1600#endif
1601
1602 if ( tty_hung_up_p ( pFile ) ) {
1603
1604 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
1605
1606 return;
1607 }
1608 if ( tty->count > 1 ) { /* not the last close */
1609
1610 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
1611
1612 return;
1613 }
1614 pCh->flags |= ASYNC_CLOSING; // last close actually
1615
1616 tty->closing = 1;
1617
1618 if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
1619 /*
1620 * Before we drop DTR, make sure the transmitter has completely drained.
1621 * This uses an timeout, after which the close
1622 * completes.
1623 */
1624 ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
1625 }
1626 /*
1627 * At this point we stop accepting input. Here we flush the channel
1628 * input buffer which will allow the board to send up more data. Any
1629 * additional input is tossed at interrupt/poll time.
1630 */
1631 i2InputFlush( pCh );
1632
1633 /* disable DSS reporting */
1634 i2QueueCommands(PTYPE_INLINE, pCh, 100, 4,
1635 CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1636 if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
1637 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
1638 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1639 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1640 }
1641
1642 serviceOutgoingFifo ( pCh->pMyBord );
1643
Alan Coxf34d7a52008-04-30 00:54:13 -07001644 tty_ldisc_flush(tty);
Alan Coxa6fc8192008-04-30 00:54:18 -07001645 tty_driver_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 tty->closing = 0;
1647
1648 pCh->pTTY = NULL;
1649
1650 if (pCh->wopen) {
1651 if (pCh->ClosingDelay) {
1652 msleep_interruptible(jiffies_to_msecs(pCh->ClosingDelay));
1653 }
1654 wake_up_interruptible(&pCh->open_wait);
1655 }
1656
1657 pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1658 wake_up_interruptible(&pCh->close_wait);
1659
1660#ifdef IP2DEBUG_OPEN
1661 DBG_CNT("ip2_close: after wakeups--");
1662#endif
1663
1664
1665 ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
1666
1667 return;
1668}
1669
1670/******************************************************************************/
1671/* Function: ip2_hangup() */
1672/* Parameters: Pointer to tty structure */
1673/* Returns: Nothing */
1674/* */
1675/* Description: */
1676/* */
1677/* */
1678/******************************************************************************/
1679static void
1680ip2_hangup ( PTTY tty )
1681{
1682 i2ChanStrPtr pCh = tty->driver_data;
1683
1684 if( !pCh ) {
1685 return;
1686 }
1687
1688 ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
1689
1690 ip2_flush_buffer(tty);
1691
1692 /* disable DSS reporting */
1693
1694 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
1695 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1696 if ( (tty->termios->c_cflag & HUPCL) ) {
1697 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
1698 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1699 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1700 }
1701 i2QueueCommands(PTYPE_INLINE, pCh, 1, 3,
1702 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1703 serviceOutgoingFifo ( pCh->pMyBord );
1704
1705 wake_up_interruptible ( &pCh->delta_msr_wait );
1706
1707 pCh->flags &= ~ASYNC_NORMAL_ACTIVE;
1708 pCh->pTTY = NULL;
1709 wake_up_interruptible ( &pCh->open_wait );
1710
1711 ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
1712}
1713
1714/******************************************************************************/
1715/******************************************************************************/
1716/* Device Output Section */
1717/******************************************************************************/
1718/******************************************************************************/
1719
1720/******************************************************************************/
1721/* Function: ip2_write() */
1722/* Parameters: Pointer to tty structure */
1723/* Flag denoting data is in user (1) or kernel (0) space */
1724/* Pointer to data */
1725/* Number of bytes to write */
1726/* Returns: Number of bytes actually written */
1727/* */
1728/* Description: (MANDATORY) */
1729/* */
1730/* */
1731/******************************************************************************/
1732static int
Alan Coxd9e39532006-01-09 20:54:20 -08001733ip2_write( PTTY tty, const unsigned char *pData, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734{
1735 i2ChanStrPtr pCh = tty->driver_data;
1736 int bytesSent = 0;
1737 unsigned long flags;
1738
1739 ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
1740
1741 /* Flush out any buffered data left over from ip2_putchar() calls. */
1742 ip2_flush_chars( tty );
1743
1744 /* This is the actual move bit. Make sure it does what we need!!!!! */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001745 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Al Virof061c582006-10-11 17:45:47 +01001746 bytesSent = i2Output( pCh, pData, count);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001747 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748
1749 ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
1750
1751 return bytesSent > 0 ? bytesSent : 0;
1752}
1753
1754/******************************************************************************/
1755/* Function: ip2_putchar() */
1756/* Parameters: Pointer to tty structure */
1757/* Character to write */
1758/* Returns: Nothing */
1759/* */
1760/* Description: */
1761/* */
1762/* */
1763/******************************************************************************/
Alan Coxf34d7a52008-04-30 00:54:13 -07001764static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765ip2_putchar( PTTY tty, unsigned char ch )
1766{
1767 i2ChanStrPtr pCh = tty->driver_data;
1768 unsigned long flags;
1769
1770// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
1771
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001772 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
1774 if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001775 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 ip2_flush_chars( tty );
1777 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001778 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Alan Coxf34d7a52008-04-30 00:54:13 -07001779 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
1781// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
1782}
1783
1784/******************************************************************************/
1785/* Function: ip2_flush_chars() */
1786/* Parameters: Pointer to tty structure */
1787/* Returns: Nothing */
1788/* */
1789/* Description: */
1790/* */
1791/******************************************************************************/
1792static void
1793ip2_flush_chars( PTTY tty )
1794{
1795 int strip;
1796 i2ChanStrPtr pCh = tty->driver_data;
1797 unsigned long flags;
1798
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001799 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 if ( pCh->Pbuf_stuff ) {
1801
1802// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
1803
1804 //
1805 // We may need to restart i2Output if it does not fullfill this request
1806 //
Al Virof061c582006-10-11 17:45:47 +01001807 strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 if ( strip != pCh->Pbuf_stuff ) {
1809 memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
1810 }
1811 pCh->Pbuf_stuff -= strip;
1812 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001813 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814}
1815
1816/******************************************************************************/
1817/* Function: ip2_write_room() */
1818/* Parameters: Pointer to tty structure */
1819/* Returns: Number of bytes that the driver can accept */
1820/* */
1821/* Description: */
1822/* */
1823/******************************************************************************/
1824static int
1825ip2_write_room ( PTTY tty )
1826{
1827 int bytesFree;
1828 i2ChanStrPtr pCh = tty->driver_data;
1829 unsigned long flags;
1830
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001831 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001833 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
1835 ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
1836
1837 return ((bytesFree > 0) ? bytesFree : 0);
1838}
1839
1840/******************************************************************************/
1841/* Function: ip2_chars_in_buf() */
1842/* Parameters: Pointer to tty structure */
1843/* Returns: Number of bytes queued for transmission */
1844/* */
1845/* Description: */
1846/* */
1847/* */
1848/******************************************************************************/
1849static int
1850ip2_chars_in_buf ( PTTY tty )
1851{
1852 i2ChanStrPtr pCh = tty->driver_data;
1853 int rc;
1854 unsigned long flags;
1855
1856 ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
1857
1858#ifdef IP2DEBUG_WRITE
1859 printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
1860 pCh->Obuf_char_count + pCh->Pbuf_stuff,
1861 pCh->Obuf_char_count, pCh->Pbuf_stuff );
1862#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001863 read_lock_irqsave(&pCh->Obuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 rc = pCh->Obuf_char_count;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001865 read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
1866 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 rc += pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001868 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 return rc;
1870}
1871
1872/******************************************************************************/
1873/* Function: ip2_flush_buffer() */
1874/* Parameters: Pointer to tty structure */
1875/* Returns: Nothing */
1876/* */
1877/* Description: */
1878/* */
1879/* */
1880/******************************************************************************/
1881static void
1882ip2_flush_buffer( PTTY tty )
1883{
1884 i2ChanStrPtr pCh = tty->driver_data;
1885 unsigned long flags;
1886
1887 ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
1888
1889#ifdef IP2DEBUG_WRITE
1890 printk (KERN_DEBUG "IP2: flush buffer\n" );
1891#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001892 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 pCh->Pbuf_stuff = 0;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001894 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 i2FlushOutput( pCh );
1896 ip2_owake(tty);
1897
1898 ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
1899
1900}
1901
1902/******************************************************************************/
1903/* Function: ip2_wait_until_sent() */
1904/* Parameters: Pointer to tty structure */
1905/* Timeout for wait. */
1906/* Returns: Nothing */
1907/* */
1908/* Description: */
1909/* This function is used in place of the normal tty_wait_until_sent, which */
1910/* only waits for the driver buffers to be empty (or rather, those buffers */
1911/* reported by chars_in_buffer) which doesn't work for IP2 due to the */
1912/* indeterminate number of bytes buffered on the board. */
1913/******************************************************************************/
1914static void
1915ip2_wait_until_sent ( PTTY tty, int timeout )
1916{
1917 int i = jiffies;
1918 i2ChanStrPtr pCh = tty->driver_data;
1919
1920 tty_wait_until_sent(tty, timeout );
1921 if ( (i = timeout - (jiffies -i)) > 0)
1922 i2DrainOutput( pCh, i );
1923}
1924
1925/******************************************************************************/
1926/******************************************************************************/
1927/* Device Input Section */
1928/******************************************************************************/
1929/******************************************************************************/
1930
1931/******************************************************************************/
1932/* Function: ip2_throttle() */
1933/* Parameters: Pointer to tty structure */
1934/* Returns: Nothing */
1935/* */
1936/* Description: */
1937/* */
1938/* */
1939/******************************************************************************/
1940static void
1941ip2_throttle ( PTTY tty )
1942{
1943 i2ChanStrPtr pCh = tty->driver_data;
1944
1945#ifdef IP2DEBUG_READ
1946 printk (KERN_DEBUG "IP2: throttle\n" );
1947#endif
1948 /*
1949 * Signal the poll/interrupt handlers not to forward incoming data to
1950 * the line discipline. This will cause the buffers to fill up in the
1951 * library and thus cause the library routines to send the flow control
1952 * stuff.
1953 */
1954 pCh->throttled = 1;
1955}
1956
1957/******************************************************************************/
1958/* Function: ip2_unthrottle() */
1959/* Parameters: Pointer to tty structure */
1960/* Returns: Nothing */
1961/* */
1962/* Description: */
1963/* */
1964/* */
1965/******************************************************************************/
1966static void
1967ip2_unthrottle ( PTTY tty )
1968{
1969 i2ChanStrPtr pCh = tty->driver_data;
1970 unsigned long flags;
1971
1972#ifdef IP2DEBUG_READ
1973 printk (KERN_DEBUG "IP2: unthrottle\n" );
1974#endif
1975
1976 /* Pass incoming data up to the line discipline again. */
1977 pCh->throttled = 0;
1978 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
1979 serviceOutgoingFifo( pCh->pMyBord );
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001980 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001982 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983#ifdef IP2DEBUG_READ
1984 printk (KERN_DEBUG "i2Input called from unthrottle\n" );
1985#endif
1986 i2Input( pCh );
1987 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001988 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989}
1990
1991static void
1992ip2_start ( PTTY tty )
1993{
1994 i2ChanStrPtr pCh = DevTable[tty->index];
1995
1996 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
1997 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
1998 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
1999#ifdef IP2DEBUG_WRITE
2000 printk (KERN_DEBUG "IP2: start tx\n" );
2001#endif
2002}
2003
2004static void
2005ip2_stop ( PTTY tty )
2006{
2007 i2ChanStrPtr pCh = DevTable[tty->index];
2008
2009 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
2010#ifdef IP2DEBUG_WRITE
2011 printk (KERN_DEBUG "IP2: stop tx\n" );
2012#endif
2013}
2014
2015/******************************************************************************/
2016/* Device Ioctl Section */
2017/******************************************************************************/
2018
2019static int ip2_tiocmget(struct tty_struct *tty, struct file *file)
2020{
2021 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002022#ifdef ENABLE_DSSNOW
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 wait_queue_t wait;
Alan Coxd9e39532006-01-09 20:54:20 -08002024#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
2026 if (pCh == NULL)
2027 return -ENODEV;
2028
2029/*
2030 FIXME - the following code is causing a NULL pointer dereference in
2031 2.3.51 in an interrupt handler. It's suppose to prompt the board
2032 to return the DSS signal status immediately. Why doesn't it do
2033 the same thing in 2.2.14?
2034*/
2035
2036/* This thing is still busted in the 1.2.12 driver on 2.4.x
2037 and even hoses the serial console so the oops can be trapped.
2038 /\/\|=mhw=|\/\/ */
2039
2040#ifdef ENABLE_DSSNOW
2041 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
2042
2043 init_waitqueue_entry(&wait, current);
2044 add_wait_queue(&pCh->dss_now_wait, &wait);
2045 set_current_state( TASK_INTERRUPTIBLE );
2046
2047 serviceOutgoingFifo( pCh->pMyBord );
2048
2049 schedule();
2050
2051 set_current_state( TASK_RUNNING );
2052 remove_wait_queue(&pCh->dss_now_wait, &wait);
2053
2054 if (signal_pending(current)) {
2055 return -EINTR;
2056 }
2057#endif
2058 return ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
2059 | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
2060 | ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0)
2061 | ((pCh->dataSetIn & I2_RI) ? TIOCM_RNG : 0)
2062 | ((pCh->dataSetIn & I2_DSR) ? TIOCM_DSR : 0)
2063 | ((pCh->dataSetIn & I2_CTS) ? TIOCM_CTS : 0);
2064}
2065
2066static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
2067 unsigned int set, unsigned int clear)
2068{
2069 i2ChanStrPtr pCh = DevTable[tty->index];
2070
2071 if (pCh == NULL)
2072 return -ENODEV;
2073
2074 if (set & TIOCM_RTS) {
2075 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2076 pCh->dataSetOut |= I2_RTS;
2077 }
2078 if (set & TIOCM_DTR) {
2079 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2080 pCh->dataSetOut |= I2_DTR;
2081 }
2082
2083 if (clear & TIOCM_RTS) {
2084 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2085 pCh->dataSetOut &= ~I2_RTS;
2086 }
2087 if (clear & TIOCM_DTR) {
2088 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2089 pCh->dataSetOut &= ~I2_DTR;
2090 }
2091 serviceOutgoingFifo( pCh->pMyBord );
2092 return 0;
2093}
2094
2095/******************************************************************************/
2096/* Function: ip2_ioctl() */
2097/* Parameters: Pointer to tty structure */
2098/* Pointer to file structure */
2099/* Command */
2100/* Argument */
2101/* Returns: Success or failure */
2102/* */
2103/* Description: */
2104/* */
2105/* */
2106/******************************************************************************/
2107static int
2108ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
2109{
2110 wait_queue_t wait;
2111 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002112 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 struct async_icount cprev, cnow; /* kernel counter temps */
2114 struct serial_icounter_struct __user *p_cuser;
2115 int rc = 0;
2116 unsigned long flags;
2117 void __user *argp = (void __user *)arg;
2118
Alan Coxd9e39532006-01-09 20:54:20 -08002119 if ( pCh == NULL )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 return -ENODEV;
Alan Coxd9e39532006-01-09 20:54:20 -08002121
2122 pB = pCh->pMyBord;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
2124 ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
2125
2126#ifdef IP2DEBUG_IOCTL
2127 printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
2128#endif
2129
2130 switch(cmd) {
2131 case TIOCGSERIAL:
2132
2133 ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
2134
2135 rc = get_serial_info(pCh, argp);
2136 if (rc)
2137 return rc;
2138 break;
2139
2140 case TIOCSSERIAL:
2141
2142 ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
2143
2144 rc = set_serial_info(pCh, argp);
2145 if (rc)
2146 return rc;
2147 break;
2148
2149 case TCXONC:
2150 rc = tty_check_change(tty);
2151 if (rc)
2152 return rc;
2153 switch (arg) {
2154 case TCOOFF:
2155 //return -ENOIOCTLCMD;
2156 break;
2157 case TCOON:
2158 //return -ENOIOCTLCMD;
2159 break;
2160 case TCIOFF:
2161 if (STOP_CHAR(tty) != __DISABLED_CHAR) {
2162 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2163 CMD_XMIT_NOW(STOP_CHAR(tty)));
2164 }
2165 break;
2166 case TCION:
2167 if (START_CHAR(tty) != __DISABLED_CHAR) {
2168 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2169 CMD_XMIT_NOW(START_CHAR(tty)));
2170 }
2171 break;
2172 default:
2173 return -EINVAL;
2174 }
2175 return 0;
2176
2177 case TCSBRK: /* SVID version: non-zero arg --> no break */
2178 rc = tty_check_change(tty);
2179
2180 ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
2181
2182 if (!rc) {
2183 ip2_wait_until_sent(tty,0);
2184 if (!arg) {
2185 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
2186 serviceOutgoingFifo( pCh->pMyBord );
2187 }
2188 }
2189 break;
2190
2191 case TCSBRKP: /* support for POSIX tcsendbreak() */
2192 rc = tty_check_change(tty);
2193
2194 ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
2195
2196 if (!rc) {
2197 ip2_wait_until_sent(tty,0);
2198 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2199 CMD_SEND_BRK(arg ? arg*100 : 250));
2200 serviceOutgoingFifo ( pCh->pMyBord );
2201 }
2202 break;
2203
2204 case TIOCGSOFTCAR:
2205
2206 ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
2207
2208 rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
2209 if (rc)
2210 return rc;
2211 break;
2212
2213 case TIOCSSOFTCAR:
2214
2215 ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
2216
2217 rc = get_user(arg,(unsigned long __user *) argp);
2218 if (rc)
2219 return rc;
2220 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
2221 | (arg ? CLOCAL : 0));
2222
2223 break;
2224
2225 /*
2226 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
2227 * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
2228 * for masking). Caller should use TIOCGICOUNT to see which one it was
2229 */
2230 case TIOCMIWAIT:
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002231 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 cprev = pCh->icount; /* note the counters on entry */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002233 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
2235 CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
2236 init_waitqueue_entry(&wait, current);
2237 add_wait_queue(&pCh->delta_msr_wait, &wait);
2238 set_current_state( TASK_INTERRUPTIBLE );
2239
2240 serviceOutgoingFifo( pCh->pMyBord );
2241 for(;;) {
2242 ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
2243
2244 schedule();
2245
2246 ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
2247
2248 /* see if a signal did it */
2249 if (signal_pending(current)) {
2250 rc = -ERESTARTSYS;
2251 break;
2252 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002253 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 cnow = pCh->icount; /* atomic copy */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002255 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2257 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2258 rc = -EIO; /* no change => rc */
2259 break;
2260 }
2261 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2262 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2263 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2264 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2265 rc = 0;
2266 break;
2267 }
2268 cprev = cnow;
2269 }
2270 set_current_state( TASK_RUNNING );
2271 remove_wait_queue(&pCh->delta_msr_wait, &wait);
2272
2273 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3,
2274 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
2275 if ( ! (pCh->flags & ASYNC_CHECK_CD)) {
2276 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP);
2277 }
2278 serviceOutgoingFifo( pCh->pMyBord );
2279 return rc;
2280 break;
2281
2282 /*
2283 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2284 * Return: write counters to the user passed counter struct
2285 * NB: both 1->0 and 0->1 transitions are counted except for RI where
2286 * only 0->1 is counted. The controller is quite capable of counting
2287 * both, but this done to preserve compatibility with the standard
2288 * serial driver.
2289 */
2290 case TIOCGICOUNT:
2291 ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
2292
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002293 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 cnow = pCh->icount;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002295 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 p_cuser = argp;
2297 rc = put_user(cnow.cts, &p_cuser->cts);
2298 rc = put_user(cnow.dsr, &p_cuser->dsr);
2299 rc = put_user(cnow.rng, &p_cuser->rng);
2300 rc = put_user(cnow.dcd, &p_cuser->dcd);
2301 rc = put_user(cnow.rx, &p_cuser->rx);
2302 rc = put_user(cnow.tx, &p_cuser->tx);
2303 rc = put_user(cnow.frame, &p_cuser->frame);
2304 rc = put_user(cnow.overrun, &p_cuser->overrun);
2305 rc = put_user(cnow.parity, &p_cuser->parity);
2306 rc = put_user(cnow.brk, &p_cuser->brk);
2307 rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
2308 break;
2309
2310 /*
2311 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
2312 * will be passed to the line discipline for it to handle.
2313 */
2314 case TIOCSERCONFIG:
2315 case TIOCSERGWILD:
2316 case TIOCSERGETLSR:
2317 case TIOCSERSWILD:
2318 case TIOCSERGSTRUCT:
2319 case TIOCSERGETMULTI:
2320 case TIOCSERSETMULTI:
2321
2322 default:
2323 ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
2324
2325 rc = -ENOIOCTLCMD;
2326 break;
2327 }
2328
2329 ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
2330
2331 return rc;
2332}
2333
2334/******************************************************************************/
2335/* Function: GetSerialInfo() */
2336/* Parameters: Pointer to channel structure */
2337/* Pointer to old termios structure */
2338/* Returns: Nothing */
2339/* */
2340/* Description: */
2341/* This is to support the setserial command, and requires processing of the */
2342/* standard Linux serial structure. */
2343/******************************************************************************/
2344static int
2345get_serial_info ( i2ChanStrPtr pCh, struct serial_struct __user *retinfo )
2346{
2347 struct serial_struct tmp;
2348
2349 memset ( &tmp, 0, sizeof(tmp) );
2350 tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
2351 if (BID_HAS_654(tmp.type)) {
2352 tmp.type = PORT_16650;
2353 } else {
2354 tmp.type = PORT_CIRRUS;
2355 }
2356 tmp.line = pCh->port_index;
2357 tmp.port = pCh->pMyBord->i2eBase;
2358 tmp.irq = ip2config.irq[pCh->port_index/64];
2359 tmp.flags = pCh->flags;
2360 tmp.baud_base = pCh->BaudBase;
2361 tmp.close_delay = pCh->ClosingDelay;
2362 tmp.closing_wait = pCh->ClosingWaitTime;
2363 tmp.custom_divisor = pCh->BaudDivisor;
2364 return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
2365}
2366
2367/******************************************************************************/
2368/* Function: SetSerialInfo() */
2369/* Parameters: Pointer to channel structure */
2370/* Pointer to old termios structure */
2371/* Returns: Nothing */
2372/* */
2373/* Description: */
2374/* This function provides support for setserial, which uses the TIOCSSERIAL */
2375/* ioctl. Not all setserial parameters are relevant. If the user attempts to */
2376/* change the IRQ, address or type of the port the ioctl fails. */
2377/******************************************************************************/
2378static int
2379set_serial_info( i2ChanStrPtr pCh, struct serial_struct __user *new_info )
2380{
2381 struct serial_struct ns;
2382 int old_flags, old_baud_divisor;
2383
2384 if (copy_from_user(&ns, new_info, sizeof (ns)))
2385 return -EFAULT;
2386
2387 /*
2388 * We don't allow setserial to change IRQ, board address, type or baud
2389 * base. Also line nunber as such is meaningless but we use it for our
2390 * array index so it is fixed also.
2391 */
2392 if ( (ns.irq != ip2config.irq[pCh->port_index])
2393 || ((int) ns.port != ((int) (pCh->pMyBord->i2eBase)))
2394 || (ns.baud_base != pCh->BaudBase)
2395 || (ns.line != pCh->port_index) ) {
2396 return -EINVAL;
2397 }
2398
2399 old_flags = pCh->flags;
2400 old_baud_divisor = pCh->BaudDivisor;
2401
2402 if ( !capable(CAP_SYS_ADMIN) ) {
2403 if ( ( ns.close_delay != pCh->ClosingDelay ) ||
2404 ( (ns.flags & ~ASYNC_USR_MASK) !=
2405 (pCh->flags & ~ASYNC_USR_MASK) ) ) {
2406 return -EPERM;
2407 }
2408
2409 pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
2410 (ns.flags & ASYNC_USR_MASK);
2411 pCh->BaudDivisor = ns.custom_divisor;
2412 } else {
2413 pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
2414 (ns.flags & ASYNC_FLAGS);
2415 pCh->BaudDivisor = ns.custom_divisor;
2416 pCh->ClosingDelay = ns.close_delay * HZ/100;
2417 pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
2418 }
2419
2420 if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
2421 || (old_baud_divisor != pCh->BaudDivisor) ) {
2422 // Invalidate speed and reset parameters
2423 set_params( pCh, NULL );
2424 }
2425
2426 return 0;
2427}
2428
2429/******************************************************************************/
2430/* Function: ip2_set_termios() */
2431/* Parameters: Pointer to tty structure */
2432/* Pointer to old termios structure */
2433/* Returns: Nothing */
2434/* */
2435/* Description: */
2436/* */
2437/* */
2438/******************************************************************************/
2439static void
Alan Cox606d0992006-12-08 02:38:45 -08002440ip2_set_termios( PTTY tty, struct ktermios *old_termios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441{
2442 i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
2443
2444#ifdef IP2DEBUG_IOCTL
2445 printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
2446#endif
2447
2448 set_params( pCh, old_termios );
2449}
2450
2451/******************************************************************************/
2452/* Function: ip2_set_line_discipline() */
2453/* Parameters: Pointer to tty structure */
2454/* Returns: Nothing */
2455/* */
2456/* Description: Does nothing */
2457/* */
2458/* */
2459/******************************************************************************/
2460static void
2461ip2_set_line_discipline ( PTTY tty )
2462{
2463#ifdef IP2DEBUG_IOCTL
2464 printk (KERN_DEBUG "IP2: set line discipline\n" );
2465#endif
2466
2467 ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
2468
2469}
2470
2471/******************************************************************************/
2472/* Function: SetLine Characteristics() */
2473/* Parameters: Pointer to channel structure */
2474/* Returns: Nothing */
2475/* */
2476/* Description: */
2477/* This routine is called to update the channel structure with the new line */
2478/* characteristics, and send the appropriate commands to the board when they */
2479/* change. */
2480/******************************************************************************/
2481static void
Alan Cox606d0992006-12-08 02:38:45 -08002482set_params( i2ChanStrPtr pCh, struct ktermios *o_tios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483{
2484 tcflag_t cflag, iflag, lflag;
2485 char stop_char, start_char;
Alan Cox606d0992006-12-08 02:38:45 -08002486 struct ktermios dummy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
2488 lflag = pCh->pTTY->termios->c_lflag;
2489 cflag = pCh->pTTY->termios->c_cflag;
2490 iflag = pCh->pTTY->termios->c_iflag;
2491
2492 if (o_tios == NULL) {
2493 dummy.c_lflag = ~lflag;
2494 dummy.c_cflag = ~cflag;
2495 dummy.c_iflag = ~iflag;
2496 o_tios = &dummy;
2497 }
2498
2499 {
2500 switch ( cflag & CBAUD ) {
2501 case B0:
2502 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
2503 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
2504 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
2505 pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
2506 goto service_it;
2507 break;
2508 case B38400:
2509 /*
2510 * This is the speed that is overloaded with all the other high
2511 * speeds, depending upon the flag settings.
2512 */
2513 if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
2514 pCh->speed = CBR_57600;
2515 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
2516 pCh->speed = CBR_115200;
2517 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
2518 pCh->speed = CBR_C1;
2519 } else {
2520 pCh->speed = CBR_38400;
2521 }
2522 break;
2523 case B50: pCh->speed = CBR_50; break;
2524 case B75: pCh->speed = CBR_75; break;
2525 case B110: pCh->speed = CBR_110; break;
2526 case B134: pCh->speed = CBR_134; break;
2527 case B150: pCh->speed = CBR_150; break;
2528 case B200: pCh->speed = CBR_200; break;
2529 case B300: pCh->speed = CBR_300; break;
2530 case B600: pCh->speed = CBR_600; break;
2531 case B1200: pCh->speed = CBR_1200; break;
2532 case B1800: pCh->speed = CBR_1800; break;
2533 case B2400: pCh->speed = CBR_2400; break;
2534 case B4800: pCh->speed = CBR_4800; break;
2535 case B9600: pCh->speed = CBR_9600; break;
2536 case B19200: pCh->speed = CBR_19200; break;
2537 case B57600: pCh->speed = CBR_57600; break;
2538 case B115200: pCh->speed = CBR_115200; break;
2539 case B153600: pCh->speed = CBR_153600; break;
2540 case B230400: pCh->speed = CBR_230400; break;
2541 case B307200: pCh->speed = CBR_307200; break;
2542 case B460800: pCh->speed = CBR_460800; break;
2543 case B921600: pCh->speed = CBR_921600; break;
2544 default: pCh->speed = CBR_9600; break;
2545 }
2546 if ( pCh->speed == CBR_C1 ) {
2547 // Process the custom speed parameters.
2548 int bps = pCh->BaudBase / pCh->BaudDivisor;
2549 if ( bps == 921600 ) {
2550 pCh->speed = CBR_921600;
2551 } else {
2552 bps = bps/10;
2553 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
2554 }
2555 }
2556 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
2557
2558 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
2559 pCh->dataSetOut |= (I2_DTR | I2_RTS);
2560 }
2561 if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag))
2562 {
2563 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2564 CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
2565 }
2566 if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag))
2567 {
2568 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2569 CMD_SETPAR(
2570 (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
2571 )
2572 );
2573 }
2574 /* byte size and parity */
2575 if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag))
2576 {
2577 int datasize;
2578 switch ( cflag & CSIZE ) {
2579 case CS5: datasize = CSZ_5; break;
2580 case CS6: datasize = CSZ_6; break;
2581 case CS7: datasize = CSZ_7; break;
2582 case CS8: datasize = CSZ_8; break;
2583 default: datasize = CSZ_5; break; /* as per serial.c */
2584 }
2585 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
2586 }
2587 /* Process CTS flow control flag setting */
2588 if ( (cflag & CRTSCTS) ) {
2589 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2590 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
2591 } else {
2592 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2593 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
2594 }
2595 //
2596 // Process XON/XOFF flow control flags settings
2597 //
2598 stop_char = STOP_CHAR(pCh->pTTY);
2599 start_char = START_CHAR(pCh->pTTY);
2600
2601 //////////// can't be \000
2602 if (stop_char == __DISABLED_CHAR )
2603 {
2604 stop_char = ~__DISABLED_CHAR;
2605 }
2606 if (start_char == __DISABLED_CHAR )
2607 {
2608 start_char = ~__DISABLED_CHAR;
2609 }
2610 /////////////////////////////////
2611
2612 if ( o_tios->c_cc[VSTART] != start_char )
2613 {
2614 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
2615 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
2616 }
2617 if ( o_tios->c_cc[VSTOP] != stop_char )
2618 {
2619 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
2620 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
2621 }
2622 if (stop_char == __DISABLED_CHAR )
2623 {
2624 stop_char = ~__DISABLED_CHAR; //TEST123
2625 goto no_xoff;
2626 }
2627 if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF)))
2628 {
2629 if ( iflag & IXOFF ) { // Enable XOFF output flow control
2630 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
2631 } else { // Disable XOFF output flow control
2632no_xoff:
2633 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
2634 }
2635 }
2636 if (start_char == __DISABLED_CHAR )
2637 {
2638 goto no_xon;
2639 }
2640 if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY)))
2641 {
2642 if ( iflag & IXON ) {
2643 if ( iflag & IXANY ) { // Enable XON/XANY output flow control
2644 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
2645 } else { // Enable XON output flow control
2646 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
2647 }
2648 } else { // Disable XON output flow control
2649no_xon:
2650 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
2651 }
2652 }
2653 if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) )
2654 {
2655 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2656 CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
2657 }
2658 if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) )
2659 {
2660 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2661 CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
2662 }
2663
2664 if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR))
2665 ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) )
2666 {
2667 char brkrpt = 0;
2668 char parrpt = 0;
2669
2670 if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
2671 /* Ignore breaks altogether */
2672 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
2673 } else {
2674 if ( iflag & BRKINT ) {
2675 if ( iflag & PARMRK ) {
2676 brkrpt = 0x0a; // exception an inline triple
2677 } else {
2678 brkrpt = 0x1a; // exception and NULL
2679 }
2680 brkrpt |= 0x04; // flush input
2681 } else {
2682 if ( iflag & PARMRK ) {
2683 brkrpt = 0x0b; //POSIX triple \0377 \0 \0
2684 } else {
2685 brkrpt = 0x01; // Null only
2686 }
2687 }
2688 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
2689 }
2690
2691 if (iflag & IGNPAR) {
2692 parrpt = 0x20;
2693 /* would be 2 for not cirrus bug */
2694 /* would be 0x20 cept for cirrus bug */
2695 } else {
2696 if ( iflag & PARMRK ) {
2697 /*
2698 * Replace error characters with 3-byte sequence (\0377,\0,char)
2699 */
2700 parrpt = 0x04 ;
2701 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
2702 } else {
2703 parrpt = 0x03;
2704 }
2705 }
2706 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
2707 }
2708 if (cflag & CLOCAL) {
2709 // Status reporting fails for DCD if this is off
2710 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
2711 pCh->flags &= ~ASYNC_CHECK_CD;
2712 } else {
2713 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
2714 pCh->flags |= ASYNC_CHECK_CD;
2715 }
2716
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717service_it:
2718 i2DrainOutput( pCh, 100 );
2719}
2720
2721/******************************************************************************/
2722/* IPL Device Section */
2723/******************************************************************************/
2724
2725/******************************************************************************/
2726/* Function: ip2_ipl_read() */
2727/* Parameters: Pointer to device inode */
2728/* Pointer to file structure */
2729/* Pointer to data */
2730/* Number of bytes to read */
2731/* Returns: Success or failure */
2732/* */
2733/* Description: Ugly */
2734/* */
2735/* */
2736/******************************************************************************/
2737
2738static
2739ssize_t
2740ip2_ipl_read(struct file *pFile, char __user *pData, size_t count, loff_t *off )
2741{
Josef Sipeka7113a92006-12-08 02:36:55 -08002742 unsigned int minor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 int rc = 0;
2744
2745#ifdef IP2DEBUG_IPL
2746 printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
2747#endif
2748
2749 switch( minor ) {
2750 case 0: // IPL device
2751 rc = -EINVAL;
2752 break;
2753 case 1: // Status dump
2754 rc = -EINVAL;
2755 break;
2756 case 2: // Ping device
2757 rc = -EINVAL;
2758 break;
2759 case 3: // Trace device
2760 rc = DumpTraceBuffer ( pData, count );
2761 break;
2762 case 4: // Trace device
2763 rc = DumpFifoBuffer ( pData, count );
2764 break;
2765 default:
2766 rc = -ENODEV;
2767 break;
2768 }
2769 return rc;
2770}
2771
2772static int
2773DumpFifoBuffer ( char __user *pData, int count )
2774{
2775#ifdef DEBUG_FIFO
2776 int rc;
2777 rc = copy_to_user(pData, DBGBuf, count);
2778
2779 printk(KERN_DEBUG "Last index %d\n", I );
2780
2781 return count;
2782#endif /* DEBUG_FIFO */
2783 return 0;
2784}
2785
2786static int
2787DumpTraceBuffer ( char __user *pData, int count )
2788{
2789#ifdef IP2DEBUG_TRACE
2790 int rc;
2791 int dumpcount;
2792 int chunk;
2793 int *pIndex = (int __user *)pData;
2794
2795 if ( count < (sizeof(int) * 6) ) {
2796 return -EIO;
2797 }
2798 rc = put_user(tracewrap, pIndex );
2799 rc = put_user(TRACEMAX, ++pIndex );
2800 rc = put_user(tracestrip, ++pIndex );
2801 rc = put_user(tracestuff, ++pIndex );
2802 pData += sizeof(int) * 6;
2803 count -= sizeof(int) * 6;
2804
2805 dumpcount = tracestuff - tracestrip;
2806 if ( dumpcount < 0 ) {
2807 dumpcount += TRACEMAX;
2808 }
2809 if ( dumpcount > count ) {
2810 dumpcount = count;
2811 }
2812 chunk = TRACEMAX - tracestrip;
2813 if ( dumpcount > chunk ) {
2814 rc = copy_to_user(pData, &tracebuf[tracestrip],
2815 chunk * sizeof(tracebuf[0]) );
2816 pData += chunk * sizeof(tracebuf[0]);
2817 tracestrip = 0;
2818 chunk = dumpcount - chunk;
2819 } else {
2820 chunk = dumpcount;
2821 }
2822 rc = copy_to_user(pData, &tracebuf[tracestrip],
2823 chunk * sizeof(tracebuf[0]) );
2824 tracestrip += chunk;
2825 tracewrap = 0;
2826
2827 rc = put_user(tracestrip, ++pIndex );
2828 rc = put_user(tracestuff, ++pIndex );
2829
2830 return dumpcount;
2831#else
2832 return 0;
2833#endif
2834}
2835
2836/******************************************************************************/
2837/* Function: ip2_ipl_write() */
2838/* Parameters: */
2839/* Pointer to file structure */
2840/* Pointer to data */
2841/* Number of bytes to write */
2842/* Returns: Success or failure */
2843/* */
2844/* Description: */
2845/* */
2846/* */
2847/******************************************************************************/
2848static ssize_t
2849ip2_ipl_write(struct file *pFile, const char __user *pData, size_t count, loff_t *off)
2850{
2851#ifdef IP2DEBUG_IPL
2852 printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
2853#endif
2854 return 0;
2855}
2856
2857/******************************************************************************/
2858/* Function: ip2_ipl_ioctl() */
2859/* Parameters: Pointer to device inode */
2860/* Pointer to file structure */
2861/* Command */
2862/* Argument */
2863/* Returns: Success or failure */
2864/* */
2865/* Description: */
2866/* */
2867/* */
2868/******************************************************************************/
Alan Cox47be36a2008-07-25 01:48:13 -07002869static long
2870ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871{
Alan Cox47be36a2008-07-25 01:48:13 -07002872 unsigned int iplminor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 int rc = 0;
2874 void __user *argp = (void __user *)arg;
2875 ULONG __user *pIndex = argp;
2876 i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
2877 i2ChanStrPtr pCh;
2878
2879#ifdef IP2DEBUG_IPL
2880 printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
2881#endif
2882
Alan Cox47be36a2008-07-25 01:48:13 -07002883 lock_kernel();
2884
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 switch ( iplminor ) {
2886 case 0: // IPL device
2887 rc = -EINVAL;
2888 break;
2889 case 1: // Status dump
2890 case 5:
2891 case 9:
2892 case 13:
2893 switch ( cmd ) {
2894 case 64: /* Driver - ip2stat */
Alan Cox7d7b93c2008-10-13 10:42:09 +01002895 rc = put_user(-1, pIndex++ );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 rc = put_user(irq_counter, pIndex++ );
2897 rc = put_user(bh_counter, pIndex++ );
2898 break;
2899
2900 case 65: /* Board - ip2stat */
2901 if ( pB ) {
2902 rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002903 rc = put_user(inb(pB->i2eStatus),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 (ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
2905 } else {
2906 rc = -ENODEV;
2907 }
2908 break;
2909
2910 default:
2911 if (cmd < IP2_MAX_PORTS) {
2912 pCh = DevTable[cmd];
2913 if ( pCh )
2914 {
2915 rc = copy_to_user(argp, pCh, sizeof(i2ChanStr));
2916 } else {
2917 rc = -ENODEV;
2918 }
2919 } else {
2920 rc = -EINVAL;
2921 }
2922 }
2923 break;
2924
2925 case 2: // Ping device
2926 rc = -EINVAL;
2927 break;
2928 case 3: // Trace device
Andrew Mortondef93912006-02-03 03:04:47 -08002929 /*
2930 * akpm: This used to write a whole bunch of function addresses
2931 * to userspace, which generated lots of put_user() warnings.
2932 * I killed it all. Just return "success" and don't do
2933 * anything.
2934 */
2935 if (cmd == 1)
2936 rc = 0;
2937 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 break;
2940
2941 default:
2942 rc = -ENODEV;
2943 break;
2944 }
Alan Cox47be36a2008-07-25 01:48:13 -07002945 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 return rc;
2947}
2948
2949/******************************************************************************/
2950/* Function: ip2_ipl_open() */
2951/* Parameters: Pointer to device inode */
2952/* Pointer to file structure */
2953/* Returns: Success or failure */
2954/* */
2955/* Description: */
2956/* */
2957/* */
2958/******************************************************************************/
2959static int
2960ip2_ipl_open( struct inode *pInode, struct file *pFile )
2961{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
2963#ifdef IP2DEBUG_IPL
2964 printk (KERN_DEBUG "IP2IPL: open\n" );
2965#endif
Jonathan Corbetf2b98572008-05-18 15:32:43 -06002966 cycle_kernel_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 return 0;
2968}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969
2970static int
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002971proc_ip2mem_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972{
2973 i2eBordStrPtr pB;
2974 i2ChanStrPtr pCh;
2975 PTTY tty;
2976 int i;
2977
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
2979#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
2980#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
2981
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002982 seq_printf(m,"\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983
2984 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
2985 pB = i2BoardPtrTable[i];
2986 if ( pB ) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002987 seq_printf(m,"board %d:\n",i);
2988 seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
2990 }
2991 }
2992
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002993 seq_printf(m,"#: tty flags, port flags, cflags, iflags\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 for (i=0; i < IP2_MAX_PORTS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 pCh = DevTable[i];
2996 if (pCh) {
2997 tty = pCh->pTTY;
2998 if (tty && tty->count) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002999 seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 tty->termios->c_cflag,tty->termios->c_iflag);
3001
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003002 seq_printf(m,FMTLIN2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003004 seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 }
3006 }
3007 }
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003008 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009}
3010
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003011static int proc_ip2mem_open(struct inode *inode, struct file *file)
3012{
3013 return single_open(file, proc_ip2mem_show, NULL);
3014}
3015
3016static const struct file_operations ip2mem_proc_fops = {
3017 .owner = THIS_MODULE,
3018 .open = proc_ip2mem_open,
3019 .read = seq_read,
3020 .llseek = seq_lseek,
3021 .release = single_release,
3022};
3023
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024/*
3025 * This is the handler for /proc/tty/driver/ip2
3026 *
3027 * This stretch of code has been largely plagerized from at least three
3028 * different sources including ip2mkdev.c and a couple of other drivers.
3029 * The bugs are all mine. :-) =mhw=
3030 */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003031static int ip2_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032{
3033 int i, j, box;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 int boxes = 0;
3035 int ports = 0;
3036 int tports = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 i2eBordStrPtr pB;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003038 char *sep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003040 seq_printf(m, "ip2info: 1.0 driver: %s\n", pcVersion);
3041 seq_printf(m, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
3043 IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
3044
3045 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3046 /* This need to be reset for a board by board count... */
3047 boxes = 0;
3048 pB = i2BoardPtrTable[i];
3049 if( pB ) {
3050 switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED )
3051 {
3052 case POR_ID_FIIEX:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003053 seq_printf(m, "Board %d: EX ports=", i);
3054 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 for( box = 0; box < ABS_MAX_BOXES; ++box )
3056 {
3057 ports = 0;
3058
3059 if( pB->i2eChannelMap[box] != 0 ) ++boxes;
3060 for( j = 0; j < ABS_BIGGEST_BOX; ++j )
3061 {
3062 if( pB->i2eChannelMap[box] & 1<< j ) {
3063 ++ports;
3064 }
3065 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003066 seq_printf(m, "%s%d", sep, ports);
3067 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 tports += ports;
3069 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003070 seq_printf(m, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 break;
3072
3073 case POR_ID_II_4:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003074 seq_printf(m, "Board %d: ISA-4 ports=4 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 tports = ports = 4;
3076 break;
3077
3078 case POR_ID_II_8:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003079 seq_printf(m, "Board %d: ISA-8-std ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 tports = ports = 8;
3081 break;
3082
3083 case POR_ID_II_8R:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003084 seq_printf(m, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 tports = ports = 8;
3086 break;
3087
3088 default:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003089 seq_printf(m, "Board %d: unknown", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 /* Don't try and probe for minor numbers */
3091 tports = ports = 0;
3092 }
3093
3094 } else {
3095 /* Don't try and probe for minor numbers */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003096 seq_printf(m, "Board %d: vacant", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 tports = ports = 0;
3098 }
3099
3100 if( tports ) {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003101 seq_puts(m, " minors=");
3102 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 for ( box = 0; box < ABS_MAX_BOXES; ++box )
3104 {
3105 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
3106 {
3107 if ( pB->i2eChannelMap[box] & (1 << j) )
3108 {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003109 seq_printf(m, "%s%d", sep,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 j + ABS_BIGGEST_BOX *
3111 (box+i*ABS_MAX_BOXES));
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003112 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 }
3114 }
3115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003117 seq_putc(m, '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003119 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003121
3122static int ip2_proc_open(struct inode *inode, struct file *file)
3123{
3124 return single_open(file, ip2_proc_show, NULL);
3125}
3126
3127static const struct file_operations ip2_proc_fops = {
3128 .owner = THIS_MODULE,
3129 .open = ip2_proc_open,
3130 .read = seq_read,
3131 .llseek = seq_lseek,
3132 .release = single_release,
3133};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134
3135/******************************************************************************/
3136/* Function: ip2trace() */
3137/* Parameters: Value to add to trace buffer */
3138/* Returns: Nothing */
3139/* */
3140/* Description: */
3141/* */
3142/* */
3143/******************************************************************************/
3144#ifdef IP2DEBUG_TRACE
3145void
3146ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
3147{
3148 long flags;
3149 unsigned long *pCode = &codes;
3150 union ip2breadcrumb bc;
3151 i2ChanStrPtr pCh;
3152
3153
3154 tracebuf[tracestuff++] = jiffies;
3155 if ( tracestuff == TRACEMAX ) {
3156 tracestuff = 0;
3157 }
3158 if ( tracestuff == tracestrip ) {
3159 if ( ++tracestrip == TRACEMAX ) {
3160 tracestrip = 0;
3161 }
3162 ++tracewrap;
3163 }
3164
3165 bc.hdr.port = 0xff & pn;
3166 bc.hdr.cat = cat;
3167 bc.hdr.codes = (unsigned char)( codes & 0xff );
3168 bc.hdr.label = label;
3169 tracebuf[tracestuff++] = bc.value;
3170
3171 for (;;) {
3172 if ( tracestuff == TRACEMAX ) {
3173 tracestuff = 0;
3174 }
3175 if ( tracestuff == tracestrip ) {
3176 if ( ++tracestrip == TRACEMAX ) {
3177 tracestrip = 0;
3178 }
3179 ++tracewrap;
3180 }
3181
3182 if ( !codes-- )
3183 break;
3184
3185 tracebuf[tracestuff++] = *++pCode;
3186 }
3187}
3188#endif
3189
3190
3191MODULE_LICENSE("GPL");
Chuck Shorteb0e71c2006-07-10 04:43:59 -07003192
3193static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
3194 { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
3195 { }
3196};
3197
3198MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);