blob: 39269d19a02d2b489e7184d99f522df2d6de361f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2*
3* (c) 1999 by Computone Corporation
4*
5********************************************************************************
6*
7* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
8* serial I/O controllers.
9*
10* DESCRIPTION: Mainline code for the device driver
11*
12*******************************************************************************/
13// ToDo:
14//
15// Fix the immediate DSS_NOW problem.
16// Work over the channel stats return logic in ip2_ipl_ioctl so they
17// make sense for all 256 possible channels and so the user space
18// utilities will compile and work properly.
19//
20// Done:
21//
22// 1.2.14 /\/\|=mhw=|\/\/
23// Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts.
24// Changed the definition of ip2trace to be more consistent with kernel style
25// Thanks to Andreas Dilger <adilger@turbolabs.com> for these updates
26//
27// 1.2.13 /\/\|=mhw=|\/\/
28// DEVFS: Renamed ttf/{n} to tts/F{n} and cuf/{n} to cua/F{n} to conform
29// to agreed devfs serial device naming convention.
30//
31// 1.2.12 /\/\|=mhw=|\/\/
32// Cleaned up some remove queue cut and paste errors
33//
34// 1.2.11 /\/\|=mhw=|\/\/
35// Clean up potential NULL pointer dereferences
36// Clean up devfs registration
37// Add kernel command line parsing for io and irq
Adrian Bunk9c4b5622006-01-19 18:07:10 +010038// Compile defaults for io and irq are now set in ip2.c not ip2.h!
Linus Torvalds1da177e2005-04-16 15:20:36 -070039// Reworked poll_only hack for explicit parameter setting
40// You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
41// Merged ip2_loadmain and old_ip2_init
42// Converted all instances of interruptible_sleep_on into queue calls
43// Most of these had no race conditions but better to clean up now
44//
45// 1.2.10 /\/\|=mhw=|\/\/
46// Fixed the bottom half interrupt handler and enabled USE_IQI
47// to split the interrupt handler into a formal top-half / bottom-half
48// Fixed timing window on high speed processors that queued messages to
49// the outbound mail fifo faster than the board could handle.
50//
51// 1.2.9
52// Four box EX was barfing on >128k kmalloc, made structure smaller by
53// reducing output buffer size
54//
55// 1.2.8
56// Device file system support (MHW)
57//
58// 1.2.7
59// Fixed
60// Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules
61//
62// 1.2.6
63//Fixes DCD problems
64// DCD was not reported when CLOCAL was set on call to TIOCMGET
65//
66//Enhancements:
67// TIOCMGET requests and waits for status return
68// No DSS interrupts enabled except for DCD when needed
69//
70// For internal use only
71//
72//#define IP2DEBUG_INIT
73//#define IP2DEBUG_OPEN
74//#define IP2DEBUG_WRITE
75//#define IP2DEBUG_READ
76//#define IP2DEBUG_IOCTL
77//#define IP2DEBUG_IPL
78
79//#define IP2DEBUG_TRACE
80//#define DEBUG_FIFO
81
82/************/
83/* Includes */
84/************/
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86#include <linux/ctype.h>
87#include <linux/string.h>
88#include <linux/fcntl.h>
89#include <linux/errno.h>
90#include <linux/module.h>
91#include <linux/signal.h>
92#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070093#include <linux/timer.h>
94#include <linux/interrupt.h>
95#include <linux/pci.h>
96#include <linux/mm.h>
97#include <linux/slab.h>
98#include <linux/major.h>
99#include <linux/wait.h>
100#include <linux/device.h>
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600101#include <linux/smp_lock.h>
David Woodhouse547d8bb2008-06-11 16:57:21 +0100102#include <linux/firmware.h>
103#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105#include <linux/tty.h>
106#include <linux/tty_flip.h>
107#include <linux/termios.h>
108#include <linux/tty_driver.h>
109#include <linux/serial.h>
110#include <linux/ptrace.h>
111#include <linux/ioport.h>
112
113#include <linux/cdk.h>
114#include <linux/comstats.h>
115#include <linux/delay.h>
116#include <linux/bitops.h>
117
118#include <asm/system.h>
119#include <asm/io.h>
120#include <asm/irq.h>
121
122#include <linux/vmalloc.h>
123#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125#include <asm/uaccess.h>
126
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100127#include "ip2types.h"
128#include "ip2trace.h"
129#include "ip2ioctl.h"
130#include "ip2.h"
131#include "i2ellis.h"
132#include "i2lib.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134/*****************
135 * /proc/ip2mem *
136 *****************/
137
138#include <linux/proc_fs.h>
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700139#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700141static const struct file_operations ip2mem_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
143
144/********************/
145/* Type Definitions */
146/********************/
147
148/*************/
149/* Constants */
150/*************/
151
152/* String constants to identify ourselves */
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 -0700252static char TimerOn;
253
254#ifdef IP2DEBUG_TRACE
255/* Trace (debug) buffer data */
256#define TRACEMAX 1000
257static unsigned long tracebuf[TRACEMAX];
258static int tracestuff;
259static int tracestrip;
260static int tracewrap;
261#endif
262
263/**********/
264/* Macros */
265/**********/
266
267#if defined(MODULE) && defined(IP2DEBUG_OPEN)
268#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
269 tty->name,(pCh->flags),ip2_tty_driver->refcount, \
270 tty->count,/*GET_USE_COUNT(module)*/0,s)
271#else
272#define DBG_CNT(s)
273#endif
274
275/********/
276/* Code */
277/********/
278
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100279#include "i2ellis.c" /* Extremely low-level interface services */
280#include "i2cmd.c" /* Standard loadware command definitions */
281#include "i2lib.c" /* High level interface services */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
283/* Configuration area for modprobe */
284
285MODULE_AUTHOR("Doug McNash");
286MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
Jiri Slaby47babd42008-10-13 10:34:27 +0100287MODULE_LICENSE("GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Jiri Slabycf176bc2008-10-13 10:34:36 +0100289static int poll_only;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291static int Eisa_irq;
292static int Eisa_slot;
293
294static int iindx;
295static char rirqs[IP2_MAX_BOARDS];
296static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
297
Jiri Slaby47babd42008-10-13 10:34:27 +0100298/* Note: Add compiled in defaults to these arrays, not to the structure
299 in ip2.h any longer. That structure WILL get overridden
300 by these values, or command line values, or insmod values!!! =mhw=
301*/
302static int io[IP2_MAX_BOARDS];
303static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
304
305MODULE_AUTHOR("Doug McNash");
306MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
307module_param_array(irq, int, NULL, 0);
308MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
309module_param_array(io, int, NULL, 0);
310MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
311module_param(poll_only, bool, 0);
312MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314/* for sysfs class support */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800315static struct class *ip2_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100317/* Some functions to keep track of what irqs we have */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100319static int __init is_valid_irq(int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 int *i = Valid_Irqs;
322
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100323 while (*i != 0 && *i != irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 i++;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100325
326 return *i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100329static void __init mark_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
331 rirqs[iindx++] = irq;
332}
333
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100334static int __exit clear_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
336 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100337 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 if (rirqs[i] == irq) {
339 rirqs[i] = 0;
340 return 1;
341 }
342 }
343 return 0;
344}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100346static int have_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100348 /* array init to zeros so 0 irq will not be requested as a side
349 * effect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100351 for (i = 0; i < IP2_MAX_BOARDS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 if (rirqs[i] == irq)
353 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 return 0;
355}
356
357/******************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358/* Function: cleanup_module() */
359/* Parameters: None */
360/* Returns: Nothing */
361/* */
362/* Description: */
363/* This is a required entry point for an installable module. It has to return */
364/* the device and the driver to a passive state. It should not be necessary */
365/* to reset the board fully, especially as the loadware is downloaded */
366/* externally rather than in the driver. We just want to disable the board */
367/* and clear the loadware to a reset state. To allow this there has to be a */
368/* way to detect whether the board has the loadware running at init time to */
369/* handle subsequent installations of the driver. All memory allocated by the */
370/* driver should be returned since it may be unloaded from memory. */
371/******************************************************************************/
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100372static void __exit ip2_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374 int err;
375 int i;
376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 /* Stop poll timer if we had one. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100378 if (TimerOn) {
379 del_timer(&PollTimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 TimerOn = 0;
381 }
382
383 /* Reset the boards we have. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100384 for (i = 0; i < IP2_MAX_BOARDS; i++)
385 if (i2BoardPtrTable[i])
386 iiReset(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
388 /* The following is done at most once, if any boards were installed. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100389 for (i = 0; i < IP2_MAX_BOARDS; i++) {
390 if (i2BoardPtrTable[i]) {
391 iiResetDelay(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 /* free io addresses and Tibet */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100393 release_region(ip2config.addr[i], 8);
tonyj@suse.de07c015e2007-08-07 22:28:44 -0700394 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100395 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
396 4 * i + 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 }
398 /* Disable and remove interrupt handler. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100399 if (ip2config.irq[i] > 0 &&
400 have_requested_irq(ip2config.irq[i])) {
401 free_irq(ip2config.irq[i], (void *)&pcName);
402 clear_requested_irq(ip2config.irq[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 }
404 }
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800405 class_destroy(ip2_class);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100406 err = tty_unregister_driver(ip2_tty_driver);
407 if (err)
408 printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
409 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 put_tty_driver(ip2_tty_driver);
Akinobu Mita68fc4fa2007-07-19 01:47:50 -0700411 unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
Alexey Dobriyanc74c1202008-04-29 01:01:44 -0700412 remove_proc_entry("ip2mem", NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100414 /* free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 for (i = 0; i < IP2_MAX_BOARDS; i++) {
416 void *pB;
417#ifdef CONFIG_PCI
418 if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
419 pci_disable_device(ip2config.pci_dev[i]);
Alan Cox1aff0ec2006-09-30 23:27:59 -0700420 pci_dev_put(ip2config.pci_dev[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 ip2config.pci_dev[i] = NULL;
422 }
423#endif
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100424 pB = i2BoardPtrTable[i];
425 if (pB != NULL) {
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100426 kfree(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 i2BoardPtrTable[i] = NULL;
428 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100429 if (DevTableMem[i] != NULL) {
430 kfree(DevTableMem[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 DevTableMem[i] = NULL;
432 }
433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
Jon Schindler83e422b2008-04-30 00:53:53 -0700435module_exit(ip2_cleanup_module);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700437static const struct tty_operations ip2_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 .open = ip2_open,
439 .close = ip2_close,
440 .write = ip2_write,
441 .put_char = ip2_putchar,
442 .flush_chars = ip2_flush_chars,
443 .write_room = ip2_write_room,
444 .chars_in_buffer = ip2_chars_in_buf,
445 .flush_buffer = ip2_flush_buffer,
446 .ioctl = ip2_ioctl,
447 .throttle = ip2_throttle,
448 .unthrottle = ip2_unthrottle,
449 .set_termios = ip2_set_termios,
450 .set_ldisc = ip2_set_line_discipline,
451 .stop = ip2_stop,
452 .start = ip2_start,
453 .hangup = ip2_hangup,
454 .read_proc = ip2_read_proc,
455 .tiocmget = ip2_tiocmget,
456 .tiocmset = ip2_tiocmset,
457};
458
459/******************************************************************************/
460/* Function: ip2_loadmain() */
461/* Parameters: irq, io from command line of insmod et. al. */
462/* pointer to fip firmware and firmware size for boards */
463/* Returns: Success (0) */
464/* */
465/* Description: */
466/* This was the required entry point for all drivers (now in ip2.c) */
467/* It performs all */
468/* initialisation of the devices and driver structures, and registers itself */
469/* with the relevant kernel modules. */
470/******************************************************************************/
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700471/* IRQF_DISABLED - if set blocks all interrupts else only this line */
472/* IRQF_SHARED - for shared irq PCI or maybe EISA only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473/* SA_RANDOM - can be source for cert. random number generators */
474#define IP2_SA_FLAGS 0
475
David Woodhouse547d8bb2008-06-11 16:57:21 +0100476
477static const struct firmware *ip2_request_firmware(void)
478{
479 struct platform_device *pdev;
480 const struct firmware *fw;
481
482 pdev = platform_device_register_simple("ip2", 0, NULL, 0);
483 if (IS_ERR(pdev)) {
484 printk(KERN_ERR "Failed to register platform device for ip2\n");
485 return NULL;
486 }
487 if (request_firmware(&fw, "intelliport2.bin", &pdev->dev)) {
488 printk(KERN_ERR "Failed to load firmware 'intelliport2.bin'\n");
489 fw = NULL;
490 }
491 platform_device_unregister(pdev);
492 return fw;
493}
494
Jiri Slaby47babd42008-10-13 10:34:27 +0100495#ifndef MODULE
496/******************************************************************************
497 * ip2_setup:
498 * str: kernel command line string
499 *
500 * Can't autoprobe the boards so user must specify configuration on
501 * kernel command line. Sane people build it modular but the others
502 * come here.
503 *
504 * Alternating pairs of io,irq for up to 4 boards.
505 * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
506 *
507 * io=0 => No board
508 * io=1 => PCI
509 * io=2 => EISA
510 * else => ISA I/O address
511 *
512 * irq=0 or invalid for ISA will revert to polling mode
513 *
514 * Any value = -1, do not overwrite compiled in value.
515 *
516 ******************************************************************************/
517static int __init ip2_setup(char *str)
518{
519 int j, ints[10]; /* 4 boards, 2 parameters + 2 */
520 unsigned int i;
521
522 str = get_options(str, ARRAY_SIZE(ints), ints);
523
524 for (i = 0, j = 1; i < 4; i++) {
525 if (j > ints[0])
526 break;
527 if (ints[j] >= 0)
528 io[i] = ints[j];
529 j++;
530 if (j > ints[0])
531 break;
532 if (ints[j] >= 0)
533 irq[i] = ints[j];
534 j++;
535 }
536 return 1;
537}
538__setup("ip2=", ip2_setup);
539#endif /* !MODULE */
540
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100541static int __init ip2_loadmain(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
543 int i, j, box;
544 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 i2eBordStrPtr pB = NULL;
546 int rc = -1;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100547 struct pci_dev *pdev = NULL;
David Woodhouse547d8bb2008-06-11 16:57:21 +0100548 const struct firmware *fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Jiri Slaby47babd42008-10-13 10:34:27 +0100550 if (poll_only) {
551 /* Hard lock the interrupts to zero */
552 irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
553 }
554
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100555 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
557 /* process command line arguments to modprobe or
558 insmod i.e. iop & irqp */
559 /* irqp and iop should ALWAYS be specified now... But we check
560 them individually just to be sure, anyways... */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100561 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Jiri Slaby47babd42008-10-13 10:34:27 +0100562 ip2config.addr[i] = io[i];
563 if (irq[i] >= 0)
564 ip2config.irq[i] = irq[i];
565 else
566 ip2config.irq[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100567 /* This is a little bit of a hack. If poll_only=1 on command
568 line back in ip2.c OR all IRQs on all specified boards are
569 explicitly set to 0, then drop to poll only mode and override
570 PCI or EISA interrupts. This superceeds the old hack of
571 triggering if all interrupts were zero (like da default).
572 Still a hack but less prone to random acts of terrorism.
573
574 What we really should do, now that the IRQ default is set
575 to -1, is to use 0 as a hard coded, do not probe.
576
577 /\/\|=mhw=|\/\/
578 */
Jiri Slaby47babd42008-10-13 10:34:27 +0100579 poll_only |= irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 }
581 poll_only = !poll_only;
582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 /* Announce our presence */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100584 printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
586 ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
587 if (!ip2_tty_driver)
588 return -ENOMEM;
589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 /* Initialise all the boards we can find (up to the maximum). */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100591 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
592 switch (ip2config.addr[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 case 0: /* skip this slot even if card is present */
594 break;
595 default: /* ISA */
596 /* ISA address must be specified */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100597 if (ip2config.addr[i] < 0x100 ||
598 ip2config.addr[i] > 0x3f8) {
599 printk(KERN_ERR "IP2: Bad ISA board %d "
600 "address %x\n", i,
601 ip2config.addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 ip2config.addr[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100603 break;
604 }
605 ip2config.type[i] = ISA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100607 /* Check for valid irq argument, set for polling if
608 * invalid */
609 if (ip2config.irq[i] &&
610 !is_valid_irq(ip2config.irq[i])) {
611 printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
612 ip2config.irq[i]);
613 /* 0 is polling and is valid in that sense */
614 ip2config.irq[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
616 break;
617 case PCI:
618#ifdef CONFIG_PCI
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100619 {
620 u32 addr;
621 int status;
Andrew Mortonad4a5bb2007-07-31 00:39:41 -0700622
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100623 pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
624 PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
625 if (pdev == NULL) {
626 ip2config.addr[i] = 0;
627 printk(KERN_ERR "IP2: PCI board %d not "
628 "found\n", i);
629 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100631
632 if (pci_enable_device(pdev)) {
633 dev_err(&pdev->dev, "can't enable device\n");
634 break;
635 }
636 ip2config.type[i] = PCI;
637 ip2config.pci_dev[i] = pci_dev_get(pdev);
638 status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
639 &addr);
640 if (addr & 1)
641 ip2config.addr[i] = (USHORT)(addr & 0xfffe);
642 else
643 dev_err(&pdev->dev, "I/O address error\n");
644
645 ip2config.irq[i] = pdev->irq;
646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647#else
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100648 printk(KERN_ERR "IP2: PCI card specified but PCI "
649 "support not enabled.\n");
650 printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
651 "defined!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652#endif /* CONFIG_PCI */
653 break;
654 case EISA:
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100655 ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
656 if (ip2config.addr[i] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 /* Eisa_irq set as side effect, boo */
658 ip2config.type[i] = EISA;
659 }
660 ip2config.irq[i] = Eisa_irq;
661 break;
662 } /* switch */
663 } /* for */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100664 pci_dev_put(pdev);
Alan Cox1aff0ec2006-09-30 23:27:59 -0700665
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100666 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
667 if (ip2config.addr[i]) {
Mariusz Kozlowski978550b2007-10-16 23:26:45 -0700668 pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
669 if (pB) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 i2BoardPtrTable[i] = pB;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100671 iiSetAddress(pB, ip2config.addr[i],
672 ii2DelayTimer);
673 iiReset(pB);
674 } else
675 printk(KERN_ERR "IP2: board memory allocation "
676 "error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
678 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100679 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
680 pB = i2BoardPtrTable[i];
681 if (pB != NULL) {
682 iiResetDelay(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 break;
684 }
685 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100686 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100687 /* We don't want to request the firmware unless we have at
688 least one board */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100689 if (i2BoardPtrTable[i] != NULL) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100690 if (!fw)
691 fw = ip2_request_firmware();
692 if (!fw)
693 break;
694 ip2_init_board(i, fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
696 }
David Woodhouse547d8bb2008-06-11 16:57:21 +0100697 if (fw)
698 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100700 ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 ip2_tty_driver->owner = THIS_MODULE;
703 ip2_tty_driver->name = "ttyF";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 ip2_tty_driver->driver_name = pcDriver_name;
705 ip2_tty_driver->major = IP2_TTY_MAJOR;
706 ip2_tty_driver->minor_start = 0;
707 ip2_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
708 ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL;
709 ip2_tty_driver->init_termios = tty_std_termios;
710 ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100711 ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW |
712 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 tty_set_operations(ip2_tty_driver, &ip2_ops);
714
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100715 ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100717 err = tty_register_driver(ip2_tty_driver);
718 if (err) {
719 printk(KERN_ERR "IP2: failed to register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 put_tty_driver(ip2_tty_driver);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100721 return err; /* leaking resources */
722 }
723
724 err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
725 if (err) {
726 printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
727 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 } else {
729 /* create the sysfs class */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800730 ip2_class = class_create(THIS_MODULE, "ip2");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 if (IS_ERR(ip2_class)) {
732 err = PTR_ERR(ip2_class);
733 goto out_chrdev;
734 }
735 }
736 /* Register the read_procmem thing */
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700737 if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 printk(KERN_ERR "IP2: failed to register read_procmem\n");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100739 return -EIO; /* leaking resources */
740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100742 ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
743 /* Register the interrupt handler or poll handler, depending upon the
744 * specified interrupt.
745 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100747 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
748 if (ip2config.addr[i] == 0)
749 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100751 pB = i2BoardPtrTable[i];
752 if (pB != NULL) {
753 device_create_drvdata(ip2_class, NULL,
754 MKDEV(IP2_IPL_MAJOR, 4 * i),
755 NULL, "ipl%d", i);
756 device_create_drvdata(ip2_class, NULL,
757 MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
758 NULL, "stat%d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100760 for (box = 0; box < ABS_MAX_BOXES; box++)
761 for (j = 0; j < ABS_BIGGEST_BOX; j++)
762 if (pB->i2eChannelMap[box] & (1 << j))
763 tty_register_device(
764 ip2_tty_driver,
765 j + ABS_BIGGEST_BOX *
766 (box+i*ABS_MAX_BOXES),
767 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100769
770 if (poll_only) {
771 /* Poll only forces driver to only use polling and
772 to ignore the probed PCI or EISA interrupts. */
773 ip2config.irq[i] = CIR_POLL;
774 }
775 if (ip2config.irq[i] == CIR_POLL) {
776retry:
777 if (!TimerOn) {
778 PollTimer.expires = POLL_TIMEOUT;
779 add_timer(&PollTimer);
780 TimerOn = 1;
781 printk(KERN_INFO "IP2: polling\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100783 } else {
784 if (have_requested_irq(ip2config.irq[i]))
785 continue;
786 rc = request_irq(ip2config.irq[i], ip2_interrupt,
787 IP2_SA_FLAGS |
788 (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
789 pcName, i2BoardPtrTable[i]);
790 if (rc) {
791 printk(KERN_ERR "IP2: request_irq failed: "
792 "error %d\n", rc);
793 ip2config.irq[i] = CIR_POLL;
794 printk(KERN_INFO "IP2: Polling %ld/sec.\n",
795 (POLL_TIMEOUT - jiffies));
796 goto retry;
797 }
798 mark_requested_irq(ip2config.irq[i]);
799 /* Initialise the interrupt handler bottom half
800 * (aka slih). */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 }
802 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100803
804 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
805 if (i2BoardPtrTable[i]) {
806 /* set and enable board interrupt */
807 set_irq(i, ip2config.irq[i]);
808 }
809 }
810
811 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
812
813 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815out_chrdev:
816 unregister_chrdev(IP2_IPL_MAJOR, "ip2");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100817 /* unregister and put tty here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 return err;
819}
Jiri Slaby47babd42008-10-13 10:34:27 +0100820module_init(ip2_loadmain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822/******************************************************************************/
823/* Function: ip2_init_board() */
824/* Parameters: Index of board in configuration structure */
825/* Returns: Success (0) */
826/* */
827/* Description: */
828/* This function initializes the specified board. The loadware is copied to */
829/* the board, the channel structures are initialized, and the board details */
830/* are reported on the console. */
831/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700832static void
David Woodhouse547d8bb2008-06-11 16:57:21 +0100833ip2_init_board(int boardnum, const struct firmware *fw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 int i;
836 int nports = 0, nboxes = 0;
837 i2ChanStrPtr pCh;
838 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
839
840 if ( !iiInitialize ( pB ) ) {
841 printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
842 pB->i2eBase, pB->i2eError );
843 goto err_initialize;
844 }
845 printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
846 ip2config.addr[boardnum], ip2config.irq[boardnum] );
847
848 if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
849 printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
850 goto err_initialize;
851 }
852
David Woodhouse547d8bb2008-06-11 16:57:21 +0100853 if ( iiDownloadAll ( pB, (loadHdrStrPtr)fw->data, 1, fw->size )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 != II_DOWN_GOOD ) {
855 printk ( KERN_ERR "IP2: failed to download loadware\n" );
856 goto err_release_region;
857 } else {
858 printk ( KERN_INFO "IP2: fv=%d.%d.%d lv=%d.%d.%d\n",
859 pB->i2ePom.e.porVersion,
860 pB->i2ePom.e.porRevision,
861 pB->i2ePom.e.porSubRev, pB->i2eLVersion,
862 pB->i2eLRevision, pB->i2eLSub );
863 }
864
865 switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
866
867 default:
868 printk( KERN_ERR "IP2: Unknown board type, ID = %x\n",
869 pB->i2ePom.e.porID );
870 nports = 0;
871 goto err_release_region;
872 break;
873
874 case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
875 printk ( KERN_INFO "IP2: ISA-4\n" );
876 nports = 4;
877 break;
878
879 case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
880 printk ( KERN_INFO "IP2: ISA-8 std\n" );
881 nports = 8;
882 break;
883
884 case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
885 printk ( KERN_INFO "IP2: ISA-8 RJ11\n" );
886 nports = 8;
887 break;
888
889 case POR_ID_FIIEX: /* IntelliPort IIEX */
890 {
891 int portnum = IP2_PORTS_PER_BOARD * boardnum;
892 int box;
893
894 for( box = 0; box < ABS_MAX_BOXES; ++box ) {
895 if ( pB->i2eChannelMap[box] != 0 ) {
896 ++nboxes;
897 }
898 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
899 if ( pB->i2eChannelMap[box] & 1<< i ) {
900 ++nports;
901 }
902 }
903 }
904 DevTableMem[boardnum] = pCh =
905 kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
906 if ( !pCh ) {
907 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
908 goto err_release_region;
909 }
910 if ( !i2InitChannels( pB, nports, pCh ) ) {
911 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
912 kfree ( pCh );
913 goto err_release_region;
914 }
915 pB->i2eChannelPtr = &DevTable[portnum];
916 pB->i2eChannelCnt = ABS_MOST_PORTS;
917
918 for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
919 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
920 if ( pB->i2eChannelMap[box] & (1 << i) ) {
921 DevTable[portnum + i] = pCh;
922 pCh->port_index = portnum + i;
923 pCh++;
924 }
925 }
926 }
927 printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit\n",
928 nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
929 }
930 goto ex_exit;
931 }
932 DevTableMem[boardnum] = pCh =
933 kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
934 if ( !pCh ) {
935 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
936 goto err_release_region;
937 }
938 pB->i2eChannelPtr = pCh;
939 pB->i2eChannelCnt = nports;
940 if ( !i2InitChannels( pB, nports, pCh ) ) {
941 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
942 kfree ( pCh );
943 goto err_release_region;
944 }
945 pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
946
947 for( i = 0; i < pB->i2eChannelCnt; ++i ) {
948 DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
949 pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
950 pCh++;
951 }
952ex_exit:
David Howellsc4028952006-11-22 14:57:56 +0000953 INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 return;
955
956err_release_region:
957 release_region(ip2config.addr[boardnum], 8);
958err_initialize:
959 kfree ( pB );
960 i2BoardPtrTable[boardnum] = NULL;
961 return;
962}
963
964/******************************************************************************/
965/* Function: find_eisa_board ( int start_slot ) */
966/* Parameters: First slot to check */
967/* Returns: Address of EISA IntelliPort II controller */
968/* */
969/* Description: */
970/* This function searches for an EISA IntelliPort controller, starting */
971/* from the specified slot number. If the motherboard is not identified as an */
972/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
973/* it returns the base address of the controller. */
974/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700975static unsigned short
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976find_eisa_board( int start_slot )
977{
978 int i, j;
979 unsigned int idm = 0;
980 unsigned int idp = 0;
981 unsigned int base = 0;
982 unsigned int value;
983 int setup_address;
984 int setup_irq;
985 int ismine = 0;
986
987 /*
988 * First a check for an EISA motherboard, which we do by comparing the
989 * EISA ID registers for the system board and the first couple of slots.
990 * No slot ID should match the system board ID, but on an ISA or PCI
991 * machine the odds are that an empty bus will return similar values for
992 * each slot.
993 */
994 i = 0x0c80;
995 value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
996 for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
997 j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
998 if ( value == j )
999 return 0;
1000 }
1001
1002 /*
1003 * OK, so we are inclined to believe that this is an EISA machine. Find
1004 * an IntelliPort controller.
1005 */
1006 for( i = start_slot; i < 16; i++ ) {
1007 base = i << 12;
1008 idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
1009 idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
1010 ismine = 0;
1011 if ( idm == 0x0e8e ) {
1012 if ( idp == 0x0281 || idp == 0x0218 ) {
1013 ismine = 1;
1014 } else if ( idp == 0x0282 || idp == 0x0283 ) {
1015 ismine = 3; /* Can do edge-trigger */
1016 }
1017 if ( ismine ) {
1018 Eisa_slot = i;
1019 break;
1020 }
1021 }
1022 }
1023 if ( !ismine )
1024 return 0;
1025
1026 /* It's some sort of EISA card, but at what address is it configured? */
1027
1028 setup_address = base + 0xc88;
1029 value = inb(base + 0xc86);
1030 setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
1031
1032 if ( (ismine & 2) && !(value & 0x10) ) {
1033 ismine = 1; /* Could be edging, but not */
1034 }
1035
1036 if ( Eisa_irq == 0 ) {
1037 Eisa_irq = setup_irq;
1038 } else if ( Eisa_irq != setup_irq ) {
1039 printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
1040 }
1041
1042#ifdef IP2DEBUG_INIT
1043printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
1044 base >> 12, idm, idp, setup_address);
1045 if ( Eisa_irq ) {
1046 printk(KERN_DEBUG ", Interrupt %d %s\n",
1047 setup_irq, (ismine & 2) ? "(edge)" : "(level)");
1048 } else {
1049 printk(KERN_DEBUG ", (polled)\n");
1050 }
1051#endif
1052 return setup_address;
1053}
1054
1055/******************************************************************************/
1056/* Function: set_irq() */
1057/* Parameters: index to board in board table */
1058/* IRQ to use */
1059/* Returns: Success (0) */
1060/* */
1061/* Description: */
1062/******************************************************************************/
1063static void
1064set_irq( int boardnum, int boardIrq )
1065{
1066 unsigned char tempCommand[16];
1067 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
1068 unsigned long flags;
1069
1070 /*
1071 * Notify the boards they may generate interrupts. This is done by
1072 * sending an in-line command to channel 0 on each board. This is why
1073 * the channels have to be defined already. For each board, if the
1074 * interrupt has never been defined, we must do so NOW, directly, since
1075 * board will not send flow control or even give an interrupt until this
1076 * is done. If polling we must send 0 as the interrupt parameter.
1077 */
1078
1079 // We will get an interrupt here at the end of this function
1080
1081 iiDisableMailIrq(pB);
1082
1083 /* We build up the entire packet header. */
1084 CHANNEL_OF(tempCommand) = 0;
1085 PTYPE_OF(tempCommand) = PTYPE_INLINE;
1086 CMD_COUNT_OF(tempCommand) = 2;
1087 (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
1088 (CMD_OF(tempCommand))[1] = boardIrq;
1089 /*
1090 * Write to FIFO; don't bother to adjust fifo capacity for this, since
1091 * board will respond almost immediately after SendMail hit.
1092 */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001093 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001095 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 pB->i2eUsingIrq = boardIrq;
1097 pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
1098
1099 /* Need to update number of boards before you enable mailbox int */
1100 ++i2nBoards;
1101
1102 CHANNEL_OF(tempCommand) = 0;
1103 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1104 CMD_COUNT_OF(tempCommand) = 6;
1105 (CMD_OF(tempCommand))[0] = 88; // SILO
1106 (CMD_OF(tempCommand))[1] = 64; // chars
1107 (CMD_OF(tempCommand))[2] = 32; // ms
1108
1109 (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK
1110 (CMD_OF(tempCommand))[4] = 64; // chars
1111
1112 (CMD_OF(tempCommand))[5] = 87; // HW_TEST
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001113 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 iiWriteBuf(pB, tempCommand, 8);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001115 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
1117 CHANNEL_OF(tempCommand) = 0;
1118 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1119 CMD_COUNT_OF(tempCommand) = 1;
1120 (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */
1121 iiWriteBuf(pB, tempCommand, 3);
1122
1123#ifdef XXX
1124 // enable heartbeat for test porpoises
1125 CHANNEL_OF(tempCommand) = 0;
1126 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1127 CMD_COUNT_OF(tempCommand) = 2;
1128 (CMD_OF(tempCommand))[0] = 44; /* get ping */
1129 (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001130 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001132 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133#endif
1134
1135 iiEnableMailIrq(pB);
1136 iiSendPendingMail(pB);
1137}
1138
1139/******************************************************************************/
1140/* Interrupt Handler Section */
1141/******************************************************************************/
1142
1143static inline void
1144service_all_boards(void)
1145{
1146 int i;
1147 i2eBordStrPtr pB;
1148
1149 /* Service every board on the list */
1150 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
1151 pB = i2BoardPtrTable[i];
1152 if ( pB ) {
1153 i2ServiceBoard( pB );
1154 }
1155 }
1156}
1157
1158
1159/******************************************************************************/
David Howellsc4028952006-11-22 14:57:56 +00001160/* Function: ip2_interrupt_bh(work) */
1161/* Parameters: work - pointer to the board structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162/* Returns: Nothing */
1163/* */
1164/* Description: */
1165/* Service the board in a bottom half interrupt handler and then */
1166/* reenable the board's interrupts if it has an IRQ number */
1167/* */
1168/******************************************************************************/
1169static void
David Howellsc4028952006-11-22 14:57:56 +00001170ip2_interrupt_bh(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171{
David Howellsc4028952006-11-22 14:57:56 +00001172 i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173// pB better well be set or we have a problem! We can only get
1174// here from the IMMEDIATE queue. Here, we process the boards.
1175// Checking pB doesn't cost much and it saves us from the sanity checkers.
1176
1177 bh_counter++;
1178
1179 if ( pB ) {
1180 i2ServiceBoard( pB );
1181 if( pB->i2eUsingIrq ) {
1182// Re-enable his interrupts
1183 iiEnableMailIrq(pB);
1184 }
1185 }
1186}
1187
1188
1189/******************************************************************************/
David Howells7d12e782006-10-05 14:55:46 +01001190/* Function: ip2_interrupt(int irq, void *dev_id) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191/* Parameters: irq - interrupt number */
1192/* pointer to optional device ID structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193/* Returns: Nothing */
1194/* */
1195/* Description: */
1196/* */
1197/* Our task here is simply to identify each board which needs servicing. */
1198/* If we are queuing then, queue it to be serviced, and disable its irq */
1199/* mask otherwise process the board directly. */
1200/* */
1201/* We could queue by IRQ but that just complicates things on both ends */
1202/* with very little gain in performance (how many instructions does */
1203/* it take to iterate on the immediate queue). */
1204/* */
1205/* */
1206/******************************************************************************/
Jeff Garzikf3518e42007-10-19 15:24:59 -04001207static void
1208ip2_irq_work(i2eBordStrPtr pB)
1209{
1210#ifdef USE_IQI
1211 if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
1212// Disable his interrupt (will be enabled when serviced)
1213// This is mostly to protect from reentrancy.
1214 iiDisableMailIrq(pB);
1215
1216// Park the board on the immediate queue for processing.
1217 schedule_work(&pB->tqueue_interrupt);
1218
1219// Make sure the immediate queue is flagged to fire.
1220 }
1221#else
1222
1223// We are using immediate servicing here. This sucks and can
1224// cause all sorts of havoc with ppp and others. The failsafe
1225// check on iiSendPendingMail could also throw a hairball.
1226
1227 i2ServiceBoard( pB );
1228
1229#endif /* USE_IQI */
1230}
1231
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001232static void
1233ip2_polled_interrupt(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234{
1235 int i;
1236 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001238 ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
1240 /* Service just the boards on the list using this irq */
1241 for( i = 0; i < i2nBoards; ++i ) {
1242 pB = i2BoardPtrTable[i];
1243
1244// Only process those boards which match our IRQ.
1245// IRQ = 0 for polled boards, we won't poll "IRQ" boards
1246
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001247 if (pB && pB->i2eUsingIrq == 0)
Jeff Garzikf3518e42007-10-19 15:24:59 -04001248 ip2_irq_work(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 }
1250
1251 ++irq_counter;
1252
1253 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001254}
1255
1256static irqreturn_t
1257ip2_interrupt(int irq, void *dev_id)
1258{
1259 i2eBordStrPtr pB = dev_id;
1260
1261 ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, pB->i2eUsingIrq );
1262
1263 ip2_irq_work(pB);
1264
1265 ++irq_counter;
1266
1267 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1268 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269}
1270
1271/******************************************************************************/
1272/* Function: ip2_poll(unsigned long arg) */
1273/* Parameters: ? */
1274/* Returns: Nothing */
1275/* */
1276/* Description: */
1277/* This function calls the library routine i2ServiceBoard for each board in */
1278/* the board table. This is used instead of the interrupt routine when polled */
1279/* mode is specified. */
1280/******************************************************************************/
1281static void
1282ip2_poll(unsigned long arg)
1283{
1284 ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
1285
1286 TimerOn = 0; // it's the truth but not checked in service
1287
1288 // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
1289 // It will NOT poll boards handled by hard interrupts.
Joe Perches8dfba4d2008-02-03 17:11:42 +02001290 // The issue of queued BH interrupts is handled in ip2_interrupt().
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001291 ip2_polled_interrupt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
1293 PollTimer.expires = POLL_TIMEOUT;
1294 add_timer( &PollTimer );
1295 TimerOn = 1;
1296
1297 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1298}
1299
David Howellsc4028952006-11-22 14:57:56 +00001300static void do_input(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301{
David Howellsc4028952006-11-22 14:57:56 +00001302 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 unsigned long flags;
1304
1305 ip2trace(CHANN, ITRC_INPUT, 21, 0 );
1306
1307 // Data input
1308 if ( pCh->pTTY != NULL ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001309 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001311 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 i2Input( pCh );
1313 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001314 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 } else {
1316 ip2trace(CHANN, ITRC_INPUT, 22, 0 );
1317
1318 i2InputFlush( pCh );
1319 }
1320}
1321
1322// code duplicated from n_tty (ldisc)
1323static inline void isig(int sig, struct tty_struct *tty, int flush)
1324{
Alan Coxa352def2008-07-16 21:53:12 +01001325 /* FIXME: This is completely bogus */
Eric W. Biedermanab521dc2007-02-12 00:53:00 -08001326 if (tty->pgrp)
1327 kill_pgrp(tty->pgrp, sig, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (flush || !L_NOFLSH(tty)) {
Alan Coxa352def2008-07-16 21:53:12 +01001329 if ( tty->ldisc.ops->flush_buffer )
1330 tty->ldisc.ops->flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 i2InputFlush( tty->driver_data );
1332 }
1333}
1334
David Howellsc4028952006-11-22 14:57:56 +00001335static void do_status(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336{
David Howellsc4028952006-11-22 14:57:56 +00001337 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 int status;
1339
1340 status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
1341
1342 ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
1343
1344 if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
1345 if ( (status & I2_BRK) ) {
1346 // code duplicated from n_tty (ldisc)
1347 if (I_IGNBRK(pCh->pTTY))
1348 goto skip_this;
1349 if (I_BRKINT(pCh->pTTY)) {
1350 isig(SIGINT, pCh->pTTY, 1);
1351 goto skip_this;
1352 }
1353 wake_up_interruptible(&pCh->pTTY->read_wait);
1354 }
1355#ifdef NEVER_HAPPENS_AS_SETUP_XXX
1356 // and can't work because we don't know the_char
1357 // as the_char is reported on a separate path
1358 // The intelligent board does this stuff as setup
1359 {
1360 char brkf = TTY_NORMAL;
1361 unsigned char brkc = '\0';
1362 unsigned char tmp;
1363 if ( (status & I2_BRK) ) {
1364 brkf = TTY_BREAK;
1365 brkc = '\0';
1366 }
1367 else if (status & I2_PAR) {
1368 brkf = TTY_PARITY;
1369 brkc = the_char;
1370 } else if (status & I2_FRA) {
1371 brkf = TTY_FRAME;
1372 brkc = the_char;
1373 } else if (status & I2_OVR) {
1374 brkf = TTY_OVERRUN;
1375 brkc = the_char;
1376 }
1377 tmp = pCh->pTTY->real_raw;
1378 pCh->pTTY->real_raw = 0;
Alan Coxa352def2008-07-16 21:53:12 +01001379 pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 pCh->pTTY->real_raw = tmp;
1381 }
1382#endif /* NEVER_HAPPENS_AS_SETUP_XXX */
1383 }
1384skip_this:
1385
1386 if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
1387 wake_up_interruptible(&pCh->delta_msr_wait);
1388
1389 if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
1390 if ( status & I2_DCD ) {
1391 if ( pCh->wopen ) {
1392 wake_up_interruptible ( &pCh->open_wait );
1393 }
1394 } else {
1395 if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
1396 tty_hangup( pCh->pTTY );
1397 }
1398 }
1399 }
1400 }
1401
1402 ip2trace (CHANN, ITRC_STATUS, 26, 0 );
1403}
1404
1405/******************************************************************************/
1406/* Device Open/Close/Ioctl Entry Point Section */
1407/******************************************************************************/
1408
1409/******************************************************************************/
1410/* Function: open_sanity_check() */
1411/* Parameters: Pointer to tty structure */
1412/* Pointer to file structure */
1413/* Returns: Success or failure */
1414/* */
1415/* Description: */
1416/* Verifies the structure magic numbers and cross links. */
1417/******************************************************************************/
1418#ifdef IP2DEBUG_OPEN
1419static void
1420open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
1421{
1422 if ( pBrd->i2eValid != I2E_MAGIC ) {
1423 printk(KERN_ERR "IP2: invalid board structure\n" );
1424 } else if ( pBrd != pCh->pMyBord ) {
1425 printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
1426 pCh->pMyBord );
1427 } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
1428 printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
1429 } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
1430 } else {
1431 printk(KERN_INFO "IP2: all pointers check out!\n" );
1432 }
1433}
1434#endif
1435
1436
1437/******************************************************************************/
1438/* Function: ip2_open() */
1439/* Parameters: Pointer to tty structure */
1440/* Pointer to file structure */
1441/* Returns: Success or failure */
1442/* */
1443/* Description: (MANDATORY) */
1444/* A successful device open has to run a gauntlet of checks before it */
1445/* completes. After some sanity checking and pointer setup, the function */
1446/* blocks until all conditions are satisfied. It then initialises the port to */
1447/* the default characteristics and returns. */
1448/******************************************************************************/
1449static int
1450ip2_open( PTTY tty, struct file *pFile )
1451{
1452 wait_queue_t wait;
1453 int rc = 0;
1454 int do_clocal = 0;
1455 i2ChanStrPtr pCh = DevTable[tty->index];
1456
1457 ip2trace (tty->index, ITRC_OPEN, ITRC_ENTER, 0 );
1458
1459 if ( pCh == NULL ) {
1460 return -ENODEV;
1461 }
1462 /* Setup pointer links in device and tty structures */
1463 pCh->pTTY = tty;
1464 tty->driver_data = pCh;
1465
1466#ifdef IP2DEBUG_OPEN
1467 printk(KERN_DEBUG \
1468 "IP2:open(tty=%p,pFile=%p):dev=%s,ch=%d,idx=%d\n",
1469 tty, pFile, tty->name, pCh->infl.hd.i2sChannel, pCh->port_index);
1470 open_sanity_check ( pCh, pCh->pMyBord );
1471#endif
1472
1473 i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP);
1474 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1475 serviceOutgoingFifo( pCh->pMyBord );
1476
1477 /* Block here until the port is ready (per serial and istallion) */
1478 /*
1479 * 1. If the port is in the middle of closing wait for the completion
1480 * and then return the appropriate error.
1481 */
1482 init_waitqueue_entry(&wait, current);
1483 add_wait_queue(&pCh->close_wait, &wait);
1484 set_current_state( TASK_INTERRUPTIBLE );
1485
1486 if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
1487 if ( pCh->flags & ASYNC_CLOSING ) {
1488 schedule();
1489 }
1490 if ( tty_hung_up_p(pFile) ) {
1491 set_current_state( TASK_RUNNING );
1492 remove_wait_queue(&pCh->close_wait, &wait);
1493 return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
1494 }
1495 }
1496 set_current_state( TASK_RUNNING );
1497 remove_wait_queue(&pCh->close_wait, &wait);
1498
1499 /*
1500 * 3. Handle a non-blocking open of a normal port.
1501 */
1502 if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
1503 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1504 goto noblock;
1505 }
1506 /*
1507 * 4. Now loop waiting for the port to be free and carrier present
1508 * (if required).
1509 */
1510 if ( tty->termios->c_cflag & CLOCAL )
1511 do_clocal = 1;
1512
1513#ifdef IP2DEBUG_OPEN
1514 printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
1515#endif
1516
1517 ++pCh->wopen;
1518
1519 init_waitqueue_entry(&wait, current);
1520 add_wait_queue(&pCh->open_wait, &wait);
1521
1522 for(;;) {
1523 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1524 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1525 set_current_state( TASK_INTERRUPTIBLE );
1526 serviceOutgoingFifo( pCh->pMyBord );
1527 if ( tty_hung_up_p(pFile) ) {
1528 set_current_state( TASK_RUNNING );
1529 remove_wait_queue(&pCh->open_wait, &wait);
1530 return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
1531 }
1532 if (!(pCh->flags & ASYNC_CLOSING) &&
1533 (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
1534 rc = 0;
1535 break;
1536 }
1537
1538#ifdef IP2DEBUG_OPEN
1539 printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
1540 (pCh->flags & ASYNC_CLOSING)?"True":"False");
1541 printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
1542#endif
1543 ip2trace (CHANN, ITRC_OPEN, 3, 2, 0,
1544 (pCh->flags & ASYNC_CLOSING) );
1545 /* check for signal */
1546 if (signal_pending(current)) {
1547 rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
1548 break;
1549 }
1550 schedule();
1551 }
1552 set_current_state( TASK_RUNNING );
1553 remove_wait_queue(&pCh->open_wait, &wait);
1554
1555 --pCh->wopen; //why count?
1556
1557 ip2trace (CHANN, ITRC_OPEN, 4, 0 );
1558
1559 if (rc != 0 ) {
1560 return rc;
1561 }
1562 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1563
1564noblock:
1565
1566 /* first open - Assign termios structure to port */
1567 if ( tty->count == 1 ) {
1568 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1569 /* Now we must send the termios settings to the loadware */
1570 set_params( pCh, NULL );
1571 }
1572
1573 /*
1574 * Now set any i2lib options. These may go away if the i2lib code ends
1575 * up rolled into the mainline.
1576 */
1577 pCh->channelOptions |= CO_NBLOCK_WRITE;
1578
1579#ifdef IP2DEBUG_OPEN
1580 printk (KERN_DEBUG "IP2: open completed\n" );
1581#endif
1582 serviceOutgoingFifo( pCh->pMyBord );
1583
1584 ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
1585
1586 return 0;
1587}
1588
1589/******************************************************************************/
1590/* Function: ip2_close() */
1591/* Parameters: Pointer to tty structure */
1592/* Pointer to file structure */
1593/* Returns: Nothing */
1594/* */
1595/* Description: */
1596/* */
1597/* */
1598/******************************************************************************/
1599static void
1600ip2_close( PTTY tty, struct file *pFile )
1601{
1602 i2ChanStrPtr pCh = tty->driver_data;
1603
1604 if ( !pCh ) {
1605 return;
1606 }
1607
1608 ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
1609
1610#ifdef IP2DEBUG_OPEN
1611 printk(KERN_DEBUG "IP2:close %s:\n",tty->name);
1612#endif
1613
1614 if ( tty_hung_up_p ( pFile ) ) {
1615
1616 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
1617
1618 return;
1619 }
1620 if ( tty->count > 1 ) { /* not the last close */
1621
1622 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
1623
1624 return;
1625 }
1626 pCh->flags |= ASYNC_CLOSING; // last close actually
1627
1628 tty->closing = 1;
1629
1630 if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
1631 /*
1632 * Before we drop DTR, make sure the transmitter has completely drained.
1633 * This uses an timeout, after which the close
1634 * completes.
1635 */
1636 ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
1637 }
1638 /*
1639 * At this point we stop accepting input. Here we flush the channel
1640 * input buffer which will allow the board to send up more data. Any
1641 * additional input is tossed at interrupt/poll time.
1642 */
1643 i2InputFlush( pCh );
1644
1645 /* disable DSS reporting */
1646 i2QueueCommands(PTYPE_INLINE, pCh, 100, 4,
1647 CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1648 if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
1649 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
1650 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1651 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1652 }
1653
1654 serviceOutgoingFifo ( pCh->pMyBord );
1655
Alan Coxf34d7a52008-04-30 00:54:13 -07001656 tty_ldisc_flush(tty);
Alan Coxa6fc8192008-04-30 00:54:18 -07001657 tty_driver_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 tty->closing = 0;
1659
1660 pCh->pTTY = NULL;
1661
1662 if (pCh->wopen) {
1663 if (pCh->ClosingDelay) {
1664 msleep_interruptible(jiffies_to_msecs(pCh->ClosingDelay));
1665 }
1666 wake_up_interruptible(&pCh->open_wait);
1667 }
1668
1669 pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1670 wake_up_interruptible(&pCh->close_wait);
1671
1672#ifdef IP2DEBUG_OPEN
1673 DBG_CNT("ip2_close: after wakeups--");
1674#endif
1675
1676
1677 ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
1678
1679 return;
1680}
1681
1682/******************************************************************************/
1683/* Function: ip2_hangup() */
1684/* Parameters: Pointer to tty structure */
1685/* Returns: Nothing */
1686/* */
1687/* Description: */
1688/* */
1689/* */
1690/******************************************************************************/
1691static void
1692ip2_hangup ( PTTY tty )
1693{
1694 i2ChanStrPtr pCh = tty->driver_data;
1695
1696 if( !pCh ) {
1697 return;
1698 }
1699
1700 ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
1701
1702 ip2_flush_buffer(tty);
1703
1704 /* disable DSS reporting */
1705
1706 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
1707 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1708 if ( (tty->termios->c_cflag & HUPCL) ) {
1709 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
1710 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1711 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1712 }
1713 i2QueueCommands(PTYPE_INLINE, pCh, 1, 3,
1714 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1715 serviceOutgoingFifo ( pCh->pMyBord );
1716
1717 wake_up_interruptible ( &pCh->delta_msr_wait );
1718
1719 pCh->flags &= ~ASYNC_NORMAL_ACTIVE;
1720 pCh->pTTY = NULL;
1721 wake_up_interruptible ( &pCh->open_wait );
1722
1723 ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
1724}
1725
1726/******************************************************************************/
1727/******************************************************************************/
1728/* Device Output Section */
1729/******************************************************************************/
1730/******************************************************************************/
1731
1732/******************************************************************************/
1733/* Function: ip2_write() */
1734/* Parameters: Pointer to tty structure */
1735/* Flag denoting data is in user (1) or kernel (0) space */
1736/* Pointer to data */
1737/* Number of bytes to write */
1738/* Returns: Number of bytes actually written */
1739/* */
1740/* Description: (MANDATORY) */
1741/* */
1742/* */
1743/******************************************************************************/
1744static int
Alan Coxd9e39532006-01-09 20:54:20 -08001745ip2_write( PTTY tty, const unsigned char *pData, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746{
1747 i2ChanStrPtr pCh = tty->driver_data;
1748 int bytesSent = 0;
1749 unsigned long flags;
1750
1751 ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
1752
1753 /* Flush out any buffered data left over from ip2_putchar() calls. */
1754 ip2_flush_chars( tty );
1755
1756 /* This is the actual move bit. Make sure it does what we need!!!!! */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001757 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Al Virof061c582006-10-11 17:45:47 +01001758 bytesSent = i2Output( pCh, pData, count);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001759 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
1761 ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
1762
1763 return bytesSent > 0 ? bytesSent : 0;
1764}
1765
1766/******************************************************************************/
1767/* Function: ip2_putchar() */
1768/* Parameters: Pointer to tty structure */
1769/* Character to write */
1770/* Returns: Nothing */
1771/* */
1772/* Description: */
1773/* */
1774/* */
1775/******************************************************************************/
Alan Coxf34d7a52008-04-30 00:54:13 -07001776static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777ip2_putchar( PTTY tty, unsigned char ch )
1778{
1779 i2ChanStrPtr pCh = tty->driver_data;
1780 unsigned long flags;
1781
1782// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
1783
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001784 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
1786 if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001787 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 ip2_flush_chars( tty );
1789 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001790 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Alan Coxf34d7a52008-04-30 00:54:13 -07001791 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
1793// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
1794}
1795
1796/******************************************************************************/
1797/* Function: ip2_flush_chars() */
1798/* Parameters: Pointer to tty structure */
1799/* Returns: Nothing */
1800/* */
1801/* Description: */
1802/* */
1803/******************************************************************************/
1804static void
1805ip2_flush_chars( PTTY tty )
1806{
1807 int strip;
1808 i2ChanStrPtr pCh = tty->driver_data;
1809 unsigned long flags;
1810
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001811 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 if ( pCh->Pbuf_stuff ) {
1813
1814// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
1815
1816 //
1817 // We may need to restart i2Output if it does not fullfill this request
1818 //
Al Virof061c582006-10-11 17:45:47 +01001819 strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 if ( strip != pCh->Pbuf_stuff ) {
1821 memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
1822 }
1823 pCh->Pbuf_stuff -= strip;
1824 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001825 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826}
1827
1828/******************************************************************************/
1829/* Function: ip2_write_room() */
1830/* Parameters: Pointer to tty structure */
1831/* Returns: Number of bytes that the driver can accept */
1832/* */
1833/* Description: */
1834/* */
1835/******************************************************************************/
1836static int
1837ip2_write_room ( PTTY tty )
1838{
1839 int bytesFree;
1840 i2ChanStrPtr pCh = tty->driver_data;
1841 unsigned long flags;
1842
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001843 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001845 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
1847 ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
1848
1849 return ((bytesFree > 0) ? bytesFree : 0);
1850}
1851
1852/******************************************************************************/
1853/* Function: ip2_chars_in_buf() */
1854/* Parameters: Pointer to tty structure */
1855/* Returns: Number of bytes queued for transmission */
1856/* */
1857/* Description: */
1858/* */
1859/* */
1860/******************************************************************************/
1861static int
1862ip2_chars_in_buf ( PTTY tty )
1863{
1864 i2ChanStrPtr pCh = tty->driver_data;
1865 int rc;
1866 unsigned long flags;
1867
1868 ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
1869
1870#ifdef IP2DEBUG_WRITE
1871 printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
1872 pCh->Obuf_char_count + pCh->Pbuf_stuff,
1873 pCh->Obuf_char_count, pCh->Pbuf_stuff );
1874#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001875 read_lock_irqsave(&pCh->Obuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 rc = pCh->Obuf_char_count;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001877 read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
1878 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 rc += pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001880 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 return rc;
1882}
1883
1884/******************************************************************************/
1885/* Function: ip2_flush_buffer() */
1886/* Parameters: Pointer to tty structure */
1887/* Returns: Nothing */
1888/* */
1889/* Description: */
1890/* */
1891/* */
1892/******************************************************************************/
1893static void
1894ip2_flush_buffer( PTTY tty )
1895{
1896 i2ChanStrPtr pCh = tty->driver_data;
1897 unsigned long flags;
1898
1899 ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
1900
1901#ifdef IP2DEBUG_WRITE
1902 printk (KERN_DEBUG "IP2: flush buffer\n" );
1903#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001904 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 pCh->Pbuf_stuff = 0;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001906 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 i2FlushOutput( pCh );
1908 ip2_owake(tty);
1909
1910 ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
1911
1912}
1913
1914/******************************************************************************/
1915/* Function: ip2_wait_until_sent() */
1916/* Parameters: Pointer to tty structure */
1917/* Timeout for wait. */
1918/* Returns: Nothing */
1919/* */
1920/* Description: */
1921/* This function is used in place of the normal tty_wait_until_sent, which */
1922/* only waits for the driver buffers to be empty (or rather, those buffers */
1923/* reported by chars_in_buffer) which doesn't work for IP2 due to the */
1924/* indeterminate number of bytes buffered on the board. */
1925/******************************************************************************/
1926static void
1927ip2_wait_until_sent ( PTTY tty, int timeout )
1928{
1929 int i = jiffies;
1930 i2ChanStrPtr pCh = tty->driver_data;
1931
1932 tty_wait_until_sent(tty, timeout );
1933 if ( (i = timeout - (jiffies -i)) > 0)
1934 i2DrainOutput( pCh, i );
1935}
1936
1937/******************************************************************************/
1938/******************************************************************************/
1939/* Device Input Section */
1940/******************************************************************************/
1941/******************************************************************************/
1942
1943/******************************************************************************/
1944/* Function: ip2_throttle() */
1945/* Parameters: Pointer to tty structure */
1946/* Returns: Nothing */
1947/* */
1948/* Description: */
1949/* */
1950/* */
1951/******************************************************************************/
1952static void
1953ip2_throttle ( PTTY tty )
1954{
1955 i2ChanStrPtr pCh = tty->driver_data;
1956
1957#ifdef IP2DEBUG_READ
1958 printk (KERN_DEBUG "IP2: throttle\n" );
1959#endif
1960 /*
1961 * Signal the poll/interrupt handlers not to forward incoming data to
1962 * the line discipline. This will cause the buffers to fill up in the
1963 * library and thus cause the library routines to send the flow control
1964 * stuff.
1965 */
1966 pCh->throttled = 1;
1967}
1968
1969/******************************************************************************/
1970/* Function: ip2_unthrottle() */
1971/* Parameters: Pointer to tty structure */
1972/* Returns: Nothing */
1973/* */
1974/* Description: */
1975/* */
1976/* */
1977/******************************************************************************/
1978static void
1979ip2_unthrottle ( PTTY tty )
1980{
1981 i2ChanStrPtr pCh = tty->driver_data;
1982 unsigned long flags;
1983
1984#ifdef IP2DEBUG_READ
1985 printk (KERN_DEBUG "IP2: unthrottle\n" );
1986#endif
1987
1988 /* Pass incoming data up to the line discipline again. */
1989 pCh->throttled = 0;
1990 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
1991 serviceOutgoingFifo( pCh->pMyBord );
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001992 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001994 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995#ifdef IP2DEBUG_READ
1996 printk (KERN_DEBUG "i2Input called from unthrottle\n" );
1997#endif
1998 i2Input( pCh );
1999 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002000 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001}
2002
2003static void
2004ip2_start ( PTTY tty )
2005{
2006 i2ChanStrPtr pCh = DevTable[tty->index];
2007
2008 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
2009 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
2010 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
2011#ifdef IP2DEBUG_WRITE
2012 printk (KERN_DEBUG "IP2: start tx\n" );
2013#endif
2014}
2015
2016static void
2017ip2_stop ( PTTY tty )
2018{
2019 i2ChanStrPtr pCh = DevTable[tty->index];
2020
2021 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
2022#ifdef IP2DEBUG_WRITE
2023 printk (KERN_DEBUG "IP2: stop tx\n" );
2024#endif
2025}
2026
2027/******************************************************************************/
2028/* Device Ioctl Section */
2029/******************************************************************************/
2030
2031static int ip2_tiocmget(struct tty_struct *tty, struct file *file)
2032{
2033 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002034#ifdef ENABLE_DSSNOW
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 wait_queue_t wait;
Alan Coxd9e39532006-01-09 20:54:20 -08002036#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037
2038 if (pCh == NULL)
2039 return -ENODEV;
2040
2041/*
2042 FIXME - the following code is causing a NULL pointer dereference in
2043 2.3.51 in an interrupt handler. It's suppose to prompt the board
2044 to return the DSS signal status immediately. Why doesn't it do
2045 the same thing in 2.2.14?
2046*/
2047
2048/* This thing is still busted in the 1.2.12 driver on 2.4.x
2049 and even hoses the serial console so the oops can be trapped.
2050 /\/\|=mhw=|\/\/ */
2051
2052#ifdef ENABLE_DSSNOW
2053 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
2054
2055 init_waitqueue_entry(&wait, current);
2056 add_wait_queue(&pCh->dss_now_wait, &wait);
2057 set_current_state( TASK_INTERRUPTIBLE );
2058
2059 serviceOutgoingFifo( pCh->pMyBord );
2060
2061 schedule();
2062
2063 set_current_state( TASK_RUNNING );
2064 remove_wait_queue(&pCh->dss_now_wait, &wait);
2065
2066 if (signal_pending(current)) {
2067 return -EINTR;
2068 }
2069#endif
2070 return ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
2071 | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
2072 | ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0)
2073 | ((pCh->dataSetIn & I2_RI) ? TIOCM_RNG : 0)
2074 | ((pCh->dataSetIn & I2_DSR) ? TIOCM_DSR : 0)
2075 | ((pCh->dataSetIn & I2_CTS) ? TIOCM_CTS : 0);
2076}
2077
2078static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
2079 unsigned int set, unsigned int clear)
2080{
2081 i2ChanStrPtr pCh = DevTable[tty->index];
2082
2083 if (pCh == NULL)
2084 return -ENODEV;
2085
2086 if (set & TIOCM_RTS) {
2087 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2088 pCh->dataSetOut |= I2_RTS;
2089 }
2090 if (set & TIOCM_DTR) {
2091 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2092 pCh->dataSetOut |= I2_DTR;
2093 }
2094
2095 if (clear & TIOCM_RTS) {
2096 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2097 pCh->dataSetOut &= ~I2_RTS;
2098 }
2099 if (clear & TIOCM_DTR) {
2100 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2101 pCh->dataSetOut &= ~I2_DTR;
2102 }
2103 serviceOutgoingFifo( pCh->pMyBord );
2104 return 0;
2105}
2106
2107/******************************************************************************/
2108/* Function: ip2_ioctl() */
2109/* Parameters: Pointer to tty structure */
2110/* Pointer to file structure */
2111/* Command */
2112/* Argument */
2113/* Returns: Success or failure */
2114/* */
2115/* Description: */
2116/* */
2117/* */
2118/******************************************************************************/
2119static int
2120ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
2121{
2122 wait_queue_t wait;
2123 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002124 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 struct async_icount cprev, cnow; /* kernel counter temps */
2126 struct serial_icounter_struct __user *p_cuser;
2127 int rc = 0;
2128 unsigned long flags;
2129 void __user *argp = (void __user *)arg;
2130
Alan Coxd9e39532006-01-09 20:54:20 -08002131 if ( pCh == NULL )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 return -ENODEV;
Alan Coxd9e39532006-01-09 20:54:20 -08002133
2134 pB = pCh->pMyBord;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
2136 ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
2137
2138#ifdef IP2DEBUG_IOCTL
2139 printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
2140#endif
2141
2142 switch(cmd) {
2143 case TIOCGSERIAL:
2144
2145 ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
2146
2147 rc = get_serial_info(pCh, argp);
2148 if (rc)
2149 return rc;
2150 break;
2151
2152 case TIOCSSERIAL:
2153
2154 ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
2155
2156 rc = set_serial_info(pCh, argp);
2157 if (rc)
2158 return rc;
2159 break;
2160
2161 case TCXONC:
2162 rc = tty_check_change(tty);
2163 if (rc)
2164 return rc;
2165 switch (arg) {
2166 case TCOOFF:
2167 //return -ENOIOCTLCMD;
2168 break;
2169 case TCOON:
2170 //return -ENOIOCTLCMD;
2171 break;
2172 case TCIOFF:
2173 if (STOP_CHAR(tty) != __DISABLED_CHAR) {
2174 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2175 CMD_XMIT_NOW(STOP_CHAR(tty)));
2176 }
2177 break;
2178 case TCION:
2179 if (START_CHAR(tty) != __DISABLED_CHAR) {
2180 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2181 CMD_XMIT_NOW(START_CHAR(tty)));
2182 }
2183 break;
2184 default:
2185 return -EINVAL;
2186 }
2187 return 0;
2188
2189 case TCSBRK: /* SVID version: non-zero arg --> no break */
2190 rc = tty_check_change(tty);
2191
2192 ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
2193
2194 if (!rc) {
2195 ip2_wait_until_sent(tty,0);
2196 if (!arg) {
2197 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
2198 serviceOutgoingFifo( pCh->pMyBord );
2199 }
2200 }
2201 break;
2202
2203 case TCSBRKP: /* support for POSIX tcsendbreak() */
2204 rc = tty_check_change(tty);
2205
2206 ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
2207
2208 if (!rc) {
2209 ip2_wait_until_sent(tty,0);
2210 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2211 CMD_SEND_BRK(arg ? arg*100 : 250));
2212 serviceOutgoingFifo ( pCh->pMyBord );
2213 }
2214 break;
2215
2216 case TIOCGSOFTCAR:
2217
2218 ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
2219
2220 rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
2221 if (rc)
2222 return rc;
2223 break;
2224
2225 case TIOCSSOFTCAR:
2226
2227 ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
2228
2229 rc = get_user(arg,(unsigned long __user *) argp);
2230 if (rc)
2231 return rc;
2232 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
2233 | (arg ? CLOCAL : 0));
2234
2235 break;
2236
2237 /*
2238 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
2239 * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
2240 * for masking). Caller should use TIOCGICOUNT to see which one it was
2241 */
2242 case TIOCMIWAIT:
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002243 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 cprev = pCh->icount; /* note the counters on entry */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002245 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
2247 CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
2248 init_waitqueue_entry(&wait, current);
2249 add_wait_queue(&pCh->delta_msr_wait, &wait);
2250 set_current_state( TASK_INTERRUPTIBLE );
2251
2252 serviceOutgoingFifo( pCh->pMyBord );
2253 for(;;) {
2254 ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
2255
2256 schedule();
2257
2258 ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
2259
2260 /* see if a signal did it */
2261 if (signal_pending(current)) {
2262 rc = -ERESTARTSYS;
2263 break;
2264 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002265 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 cnow = pCh->icount; /* atomic copy */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002267 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2269 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2270 rc = -EIO; /* no change => rc */
2271 break;
2272 }
2273 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2274 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2275 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2276 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2277 rc = 0;
2278 break;
2279 }
2280 cprev = cnow;
2281 }
2282 set_current_state( TASK_RUNNING );
2283 remove_wait_queue(&pCh->delta_msr_wait, &wait);
2284
2285 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3,
2286 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
2287 if ( ! (pCh->flags & ASYNC_CHECK_CD)) {
2288 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP);
2289 }
2290 serviceOutgoingFifo( pCh->pMyBord );
2291 return rc;
2292 break;
2293
2294 /*
2295 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2296 * Return: write counters to the user passed counter struct
2297 * NB: both 1->0 and 0->1 transitions are counted except for RI where
2298 * only 0->1 is counted. The controller is quite capable of counting
2299 * both, but this done to preserve compatibility with the standard
2300 * serial driver.
2301 */
2302 case TIOCGICOUNT:
2303 ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
2304
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002305 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 cnow = pCh->icount;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002307 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 p_cuser = argp;
2309 rc = put_user(cnow.cts, &p_cuser->cts);
2310 rc = put_user(cnow.dsr, &p_cuser->dsr);
2311 rc = put_user(cnow.rng, &p_cuser->rng);
2312 rc = put_user(cnow.dcd, &p_cuser->dcd);
2313 rc = put_user(cnow.rx, &p_cuser->rx);
2314 rc = put_user(cnow.tx, &p_cuser->tx);
2315 rc = put_user(cnow.frame, &p_cuser->frame);
2316 rc = put_user(cnow.overrun, &p_cuser->overrun);
2317 rc = put_user(cnow.parity, &p_cuser->parity);
2318 rc = put_user(cnow.brk, &p_cuser->brk);
2319 rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
2320 break;
2321
2322 /*
2323 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
2324 * will be passed to the line discipline for it to handle.
2325 */
2326 case TIOCSERCONFIG:
2327 case TIOCSERGWILD:
2328 case TIOCSERGETLSR:
2329 case TIOCSERSWILD:
2330 case TIOCSERGSTRUCT:
2331 case TIOCSERGETMULTI:
2332 case TIOCSERSETMULTI:
2333
2334 default:
2335 ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
2336
2337 rc = -ENOIOCTLCMD;
2338 break;
2339 }
2340
2341 ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
2342
2343 return rc;
2344}
2345
2346/******************************************************************************/
2347/* Function: GetSerialInfo() */
2348/* Parameters: Pointer to channel structure */
2349/* Pointer to old termios structure */
2350/* Returns: Nothing */
2351/* */
2352/* Description: */
2353/* This is to support the setserial command, and requires processing of the */
2354/* standard Linux serial structure. */
2355/******************************************************************************/
2356static int
2357get_serial_info ( i2ChanStrPtr pCh, struct serial_struct __user *retinfo )
2358{
2359 struct serial_struct tmp;
2360
2361 memset ( &tmp, 0, sizeof(tmp) );
2362 tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
2363 if (BID_HAS_654(tmp.type)) {
2364 tmp.type = PORT_16650;
2365 } else {
2366 tmp.type = PORT_CIRRUS;
2367 }
2368 tmp.line = pCh->port_index;
2369 tmp.port = pCh->pMyBord->i2eBase;
2370 tmp.irq = ip2config.irq[pCh->port_index/64];
2371 tmp.flags = pCh->flags;
2372 tmp.baud_base = pCh->BaudBase;
2373 tmp.close_delay = pCh->ClosingDelay;
2374 tmp.closing_wait = pCh->ClosingWaitTime;
2375 tmp.custom_divisor = pCh->BaudDivisor;
2376 return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
2377}
2378
2379/******************************************************************************/
2380/* Function: SetSerialInfo() */
2381/* Parameters: Pointer to channel structure */
2382/* Pointer to old termios structure */
2383/* Returns: Nothing */
2384/* */
2385/* Description: */
2386/* This function provides support for setserial, which uses the TIOCSSERIAL */
2387/* ioctl. Not all setserial parameters are relevant. If the user attempts to */
2388/* change the IRQ, address or type of the port the ioctl fails. */
2389/******************************************************************************/
2390static int
2391set_serial_info( i2ChanStrPtr pCh, struct serial_struct __user *new_info )
2392{
2393 struct serial_struct ns;
2394 int old_flags, old_baud_divisor;
2395
2396 if (copy_from_user(&ns, new_info, sizeof (ns)))
2397 return -EFAULT;
2398
2399 /*
2400 * We don't allow setserial to change IRQ, board address, type or baud
2401 * base. Also line nunber as such is meaningless but we use it for our
2402 * array index so it is fixed also.
2403 */
2404 if ( (ns.irq != ip2config.irq[pCh->port_index])
2405 || ((int) ns.port != ((int) (pCh->pMyBord->i2eBase)))
2406 || (ns.baud_base != pCh->BaudBase)
2407 || (ns.line != pCh->port_index) ) {
2408 return -EINVAL;
2409 }
2410
2411 old_flags = pCh->flags;
2412 old_baud_divisor = pCh->BaudDivisor;
2413
2414 if ( !capable(CAP_SYS_ADMIN) ) {
2415 if ( ( ns.close_delay != pCh->ClosingDelay ) ||
2416 ( (ns.flags & ~ASYNC_USR_MASK) !=
2417 (pCh->flags & ~ASYNC_USR_MASK) ) ) {
2418 return -EPERM;
2419 }
2420
2421 pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
2422 (ns.flags & ASYNC_USR_MASK);
2423 pCh->BaudDivisor = ns.custom_divisor;
2424 } else {
2425 pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
2426 (ns.flags & ASYNC_FLAGS);
2427 pCh->BaudDivisor = ns.custom_divisor;
2428 pCh->ClosingDelay = ns.close_delay * HZ/100;
2429 pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
2430 }
2431
2432 if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
2433 || (old_baud_divisor != pCh->BaudDivisor) ) {
2434 // Invalidate speed and reset parameters
2435 set_params( pCh, NULL );
2436 }
2437
2438 return 0;
2439}
2440
2441/******************************************************************************/
2442/* Function: ip2_set_termios() */
2443/* Parameters: Pointer to tty structure */
2444/* Pointer to old termios structure */
2445/* Returns: Nothing */
2446/* */
2447/* Description: */
2448/* */
2449/* */
2450/******************************************************************************/
2451static void
Alan Cox606d0992006-12-08 02:38:45 -08002452ip2_set_termios( PTTY tty, struct ktermios *old_termios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453{
2454 i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
2455
2456#ifdef IP2DEBUG_IOCTL
2457 printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
2458#endif
2459
2460 set_params( pCh, old_termios );
2461}
2462
2463/******************************************************************************/
2464/* Function: ip2_set_line_discipline() */
2465/* Parameters: Pointer to tty structure */
2466/* Returns: Nothing */
2467/* */
2468/* Description: Does nothing */
2469/* */
2470/* */
2471/******************************************************************************/
2472static void
2473ip2_set_line_discipline ( PTTY tty )
2474{
2475#ifdef IP2DEBUG_IOCTL
2476 printk (KERN_DEBUG "IP2: set line discipline\n" );
2477#endif
2478
2479 ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
2480
2481}
2482
2483/******************************************************************************/
2484/* Function: SetLine Characteristics() */
2485/* Parameters: Pointer to channel structure */
2486/* Returns: Nothing */
2487/* */
2488/* Description: */
2489/* This routine is called to update the channel structure with the new line */
2490/* characteristics, and send the appropriate commands to the board when they */
2491/* change. */
2492/******************************************************************************/
2493static void
Alan Cox606d0992006-12-08 02:38:45 -08002494set_params( i2ChanStrPtr pCh, struct ktermios *o_tios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495{
2496 tcflag_t cflag, iflag, lflag;
2497 char stop_char, start_char;
Alan Cox606d0992006-12-08 02:38:45 -08002498 struct ktermios dummy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
2500 lflag = pCh->pTTY->termios->c_lflag;
2501 cflag = pCh->pTTY->termios->c_cflag;
2502 iflag = pCh->pTTY->termios->c_iflag;
2503
2504 if (o_tios == NULL) {
2505 dummy.c_lflag = ~lflag;
2506 dummy.c_cflag = ~cflag;
2507 dummy.c_iflag = ~iflag;
2508 o_tios = &dummy;
2509 }
2510
2511 {
2512 switch ( cflag & CBAUD ) {
2513 case B0:
2514 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
2515 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
2516 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
2517 pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
2518 goto service_it;
2519 break;
2520 case B38400:
2521 /*
2522 * This is the speed that is overloaded with all the other high
2523 * speeds, depending upon the flag settings.
2524 */
2525 if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
2526 pCh->speed = CBR_57600;
2527 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
2528 pCh->speed = CBR_115200;
2529 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
2530 pCh->speed = CBR_C1;
2531 } else {
2532 pCh->speed = CBR_38400;
2533 }
2534 break;
2535 case B50: pCh->speed = CBR_50; break;
2536 case B75: pCh->speed = CBR_75; break;
2537 case B110: pCh->speed = CBR_110; break;
2538 case B134: pCh->speed = CBR_134; break;
2539 case B150: pCh->speed = CBR_150; break;
2540 case B200: pCh->speed = CBR_200; break;
2541 case B300: pCh->speed = CBR_300; break;
2542 case B600: pCh->speed = CBR_600; break;
2543 case B1200: pCh->speed = CBR_1200; break;
2544 case B1800: pCh->speed = CBR_1800; break;
2545 case B2400: pCh->speed = CBR_2400; break;
2546 case B4800: pCh->speed = CBR_4800; break;
2547 case B9600: pCh->speed = CBR_9600; break;
2548 case B19200: pCh->speed = CBR_19200; break;
2549 case B57600: pCh->speed = CBR_57600; break;
2550 case B115200: pCh->speed = CBR_115200; break;
2551 case B153600: pCh->speed = CBR_153600; break;
2552 case B230400: pCh->speed = CBR_230400; break;
2553 case B307200: pCh->speed = CBR_307200; break;
2554 case B460800: pCh->speed = CBR_460800; break;
2555 case B921600: pCh->speed = CBR_921600; break;
2556 default: pCh->speed = CBR_9600; break;
2557 }
2558 if ( pCh->speed == CBR_C1 ) {
2559 // Process the custom speed parameters.
2560 int bps = pCh->BaudBase / pCh->BaudDivisor;
2561 if ( bps == 921600 ) {
2562 pCh->speed = CBR_921600;
2563 } else {
2564 bps = bps/10;
2565 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
2566 }
2567 }
2568 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
2569
2570 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
2571 pCh->dataSetOut |= (I2_DTR | I2_RTS);
2572 }
2573 if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag))
2574 {
2575 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2576 CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
2577 }
2578 if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag))
2579 {
2580 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2581 CMD_SETPAR(
2582 (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
2583 )
2584 );
2585 }
2586 /* byte size and parity */
2587 if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag))
2588 {
2589 int datasize;
2590 switch ( cflag & CSIZE ) {
2591 case CS5: datasize = CSZ_5; break;
2592 case CS6: datasize = CSZ_6; break;
2593 case CS7: datasize = CSZ_7; break;
2594 case CS8: datasize = CSZ_8; break;
2595 default: datasize = CSZ_5; break; /* as per serial.c */
2596 }
2597 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
2598 }
2599 /* Process CTS flow control flag setting */
2600 if ( (cflag & CRTSCTS) ) {
2601 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2602 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
2603 } else {
2604 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2605 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
2606 }
2607 //
2608 // Process XON/XOFF flow control flags settings
2609 //
2610 stop_char = STOP_CHAR(pCh->pTTY);
2611 start_char = START_CHAR(pCh->pTTY);
2612
2613 //////////// can't be \000
2614 if (stop_char == __DISABLED_CHAR )
2615 {
2616 stop_char = ~__DISABLED_CHAR;
2617 }
2618 if (start_char == __DISABLED_CHAR )
2619 {
2620 start_char = ~__DISABLED_CHAR;
2621 }
2622 /////////////////////////////////
2623
2624 if ( o_tios->c_cc[VSTART] != start_char )
2625 {
2626 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
2627 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
2628 }
2629 if ( o_tios->c_cc[VSTOP] != stop_char )
2630 {
2631 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
2632 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
2633 }
2634 if (stop_char == __DISABLED_CHAR )
2635 {
2636 stop_char = ~__DISABLED_CHAR; //TEST123
2637 goto no_xoff;
2638 }
2639 if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF)))
2640 {
2641 if ( iflag & IXOFF ) { // Enable XOFF output flow control
2642 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
2643 } else { // Disable XOFF output flow control
2644no_xoff:
2645 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
2646 }
2647 }
2648 if (start_char == __DISABLED_CHAR )
2649 {
2650 goto no_xon;
2651 }
2652 if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY)))
2653 {
2654 if ( iflag & IXON ) {
2655 if ( iflag & IXANY ) { // Enable XON/XANY output flow control
2656 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
2657 } else { // Enable XON output flow control
2658 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
2659 }
2660 } else { // Disable XON output flow control
2661no_xon:
2662 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
2663 }
2664 }
2665 if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) )
2666 {
2667 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2668 CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
2669 }
2670 if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) )
2671 {
2672 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2673 CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
2674 }
2675
2676 if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR))
2677 ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) )
2678 {
2679 char brkrpt = 0;
2680 char parrpt = 0;
2681
2682 if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
2683 /* Ignore breaks altogether */
2684 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
2685 } else {
2686 if ( iflag & BRKINT ) {
2687 if ( iflag & PARMRK ) {
2688 brkrpt = 0x0a; // exception an inline triple
2689 } else {
2690 brkrpt = 0x1a; // exception and NULL
2691 }
2692 brkrpt |= 0x04; // flush input
2693 } else {
2694 if ( iflag & PARMRK ) {
2695 brkrpt = 0x0b; //POSIX triple \0377 \0 \0
2696 } else {
2697 brkrpt = 0x01; // Null only
2698 }
2699 }
2700 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
2701 }
2702
2703 if (iflag & IGNPAR) {
2704 parrpt = 0x20;
2705 /* would be 2 for not cirrus bug */
2706 /* would be 0x20 cept for cirrus bug */
2707 } else {
2708 if ( iflag & PARMRK ) {
2709 /*
2710 * Replace error characters with 3-byte sequence (\0377,\0,char)
2711 */
2712 parrpt = 0x04 ;
2713 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
2714 } else {
2715 parrpt = 0x03;
2716 }
2717 }
2718 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
2719 }
2720 if (cflag & CLOCAL) {
2721 // Status reporting fails for DCD if this is off
2722 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
2723 pCh->flags &= ~ASYNC_CHECK_CD;
2724 } else {
2725 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
2726 pCh->flags |= ASYNC_CHECK_CD;
2727 }
2728
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729service_it:
2730 i2DrainOutput( pCh, 100 );
2731}
2732
2733/******************************************************************************/
2734/* IPL Device Section */
2735/******************************************************************************/
2736
2737/******************************************************************************/
2738/* Function: ip2_ipl_read() */
2739/* Parameters: Pointer to device inode */
2740/* Pointer to file structure */
2741/* Pointer to data */
2742/* Number of bytes to read */
2743/* Returns: Success or failure */
2744/* */
2745/* Description: Ugly */
2746/* */
2747/* */
2748/******************************************************************************/
2749
2750static
2751ssize_t
2752ip2_ipl_read(struct file *pFile, char __user *pData, size_t count, loff_t *off )
2753{
Josef Sipeka7113a92006-12-08 02:36:55 -08002754 unsigned int minor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 int rc = 0;
2756
2757#ifdef IP2DEBUG_IPL
2758 printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
2759#endif
2760
2761 switch( minor ) {
2762 case 0: // IPL device
2763 rc = -EINVAL;
2764 break;
2765 case 1: // Status dump
2766 rc = -EINVAL;
2767 break;
2768 case 2: // Ping device
2769 rc = -EINVAL;
2770 break;
2771 case 3: // Trace device
2772 rc = DumpTraceBuffer ( pData, count );
2773 break;
2774 case 4: // Trace device
2775 rc = DumpFifoBuffer ( pData, count );
2776 break;
2777 default:
2778 rc = -ENODEV;
2779 break;
2780 }
2781 return rc;
2782}
2783
2784static int
2785DumpFifoBuffer ( char __user *pData, int count )
2786{
2787#ifdef DEBUG_FIFO
2788 int rc;
2789 rc = copy_to_user(pData, DBGBuf, count);
2790
2791 printk(KERN_DEBUG "Last index %d\n", I );
2792
2793 return count;
2794#endif /* DEBUG_FIFO */
2795 return 0;
2796}
2797
2798static int
2799DumpTraceBuffer ( char __user *pData, int count )
2800{
2801#ifdef IP2DEBUG_TRACE
2802 int rc;
2803 int dumpcount;
2804 int chunk;
2805 int *pIndex = (int __user *)pData;
2806
2807 if ( count < (sizeof(int) * 6) ) {
2808 return -EIO;
2809 }
2810 rc = put_user(tracewrap, pIndex );
2811 rc = put_user(TRACEMAX, ++pIndex );
2812 rc = put_user(tracestrip, ++pIndex );
2813 rc = put_user(tracestuff, ++pIndex );
2814 pData += sizeof(int) * 6;
2815 count -= sizeof(int) * 6;
2816
2817 dumpcount = tracestuff - tracestrip;
2818 if ( dumpcount < 0 ) {
2819 dumpcount += TRACEMAX;
2820 }
2821 if ( dumpcount > count ) {
2822 dumpcount = count;
2823 }
2824 chunk = TRACEMAX - tracestrip;
2825 if ( dumpcount > chunk ) {
2826 rc = copy_to_user(pData, &tracebuf[tracestrip],
2827 chunk * sizeof(tracebuf[0]) );
2828 pData += chunk * sizeof(tracebuf[0]);
2829 tracestrip = 0;
2830 chunk = dumpcount - chunk;
2831 } else {
2832 chunk = dumpcount;
2833 }
2834 rc = copy_to_user(pData, &tracebuf[tracestrip],
2835 chunk * sizeof(tracebuf[0]) );
2836 tracestrip += chunk;
2837 tracewrap = 0;
2838
2839 rc = put_user(tracestrip, ++pIndex );
2840 rc = put_user(tracestuff, ++pIndex );
2841
2842 return dumpcount;
2843#else
2844 return 0;
2845#endif
2846}
2847
2848/******************************************************************************/
2849/* Function: ip2_ipl_write() */
2850/* Parameters: */
2851/* Pointer to file structure */
2852/* Pointer to data */
2853/* Number of bytes to write */
2854/* Returns: Success or failure */
2855/* */
2856/* Description: */
2857/* */
2858/* */
2859/******************************************************************************/
2860static ssize_t
2861ip2_ipl_write(struct file *pFile, const char __user *pData, size_t count, loff_t *off)
2862{
2863#ifdef IP2DEBUG_IPL
2864 printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
2865#endif
2866 return 0;
2867}
2868
2869/******************************************************************************/
2870/* Function: ip2_ipl_ioctl() */
2871/* Parameters: Pointer to device inode */
2872/* Pointer to file structure */
2873/* Command */
2874/* Argument */
2875/* Returns: Success or failure */
2876/* */
2877/* Description: */
2878/* */
2879/* */
2880/******************************************************************************/
Alan Cox47be36a2008-07-25 01:48:13 -07002881static long
2882ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883{
Alan Cox47be36a2008-07-25 01:48:13 -07002884 unsigned int iplminor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 int rc = 0;
2886 void __user *argp = (void __user *)arg;
2887 ULONG __user *pIndex = argp;
2888 i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
2889 i2ChanStrPtr pCh;
2890
2891#ifdef IP2DEBUG_IPL
2892 printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
2893#endif
2894
Alan Cox47be36a2008-07-25 01:48:13 -07002895 lock_kernel();
2896
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 switch ( iplminor ) {
2898 case 0: // IPL device
2899 rc = -EINVAL;
2900 break;
2901 case 1: // Status dump
2902 case 5:
2903 case 9:
2904 case 13:
2905 switch ( cmd ) {
2906 case 64: /* Driver - ip2stat */
2907 rc = put_user(ip2_tty_driver->refcount, pIndex++ );
2908 rc = put_user(irq_counter, pIndex++ );
2909 rc = put_user(bh_counter, pIndex++ );
2910 break;
2911
2912 case 65: /* Board - ip2stat */
2913 if ( pB ) {
2914 rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002915 rc = put_user(inb(pB->i2eStatus),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 (ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
2917 } else {
2918 rc = -ENODEV;
2919 }
2920 break;
2921
2922 default:
2923 if (cmd < IP2_MAX_PORTS) {
2924 pCh = DevTable[cmd];
2925 if ( pCh )
2926 {
2927 rc = copy_to_user(argp, pCh, sizeof(i2ChanStr));
2928 } else {
2929 rc = -ENODEV;
2930 }
2931 } else {
2932 rc = -EINVAL;
2933 }
2934 }
2935 break;
2936
2937 case 2: // Ping device
2938 rc = -EINVAL;
2939 break;
2940 case 3: // Trace device
Andrew Mortondef93912006-02-03 03:04:47 -08002941 /*
2942 * akpm: This used to write a whole bunch of function addresses
2943 * to userspace, which generated lots of put_user() warnings.
2944 * I killed it all. Just return "success" and don't do
2945 * anything.
2946 */
2947 if (cmd == 1)
2948 rc = 0;
2949 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 break;
2952
2953 default:
2954 rc = -ENODEV;
2955 break;
2956 }
Alan Cox47be36a2008-07-25 01:48:13 -07002957 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 return rc;
2959}
2960
2961/******************************************************************************/
2962/* Function: ip2_ipl_open() */
2963/* Parameters: Pointer to device inode */
2964/* Pointer to file structure */
2965/* Returns: Success or failure */
2966/* */
2967/* Description: */
2968/* */
2969/* */
2970/******************************************************************************/
2971static int
2972ip2_ipl_open( struct inode *pInode, struct file *pFile )
2973{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974
2975#ifdef IP2DEBUG_IPL
2976 printk (KERN_DEBUG "IP2IPL: open\n" );
2977#endif
Jonathan Corbetf2b98572008-05-18 15:32:43 -06002978 cycle_kernel_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 return 0;
2980}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
2982static int
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002983proc_ip2mem_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984{
2985 i2eBordStrPtr pB;
2986 i2ChanStrPtr pCh;
2987 PTTY tty;
2988 int i;
2989
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
2991#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
2992#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
2993
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002994 seq_printf(m,"\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
2996 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
2997 pB = i2BoardPtrTable[i];
2998 if ( pB ) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002999 seq_printf(m,"board %d:\n",i);
3000 seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
3002 }
3003 }
3004
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003005 seq_printf(m,"#: tty flags, port flags, cflags, iflags\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 for (i=0; i < IP2_MAX_PORTS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 pCh = DevTable[i];
3008 if (pCh) {
3009 tty = pCh->pTTY;
3010 if (tty && tty->count) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003011 seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 tty->termios->c_cflag,tty->termios->c_iflag);
3013
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003014 seq_printf(m,FMTLIN2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003016 seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 }
3018 }
3019 }
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003020 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021}
3022
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003023static int proc_ip2mem_open(struct inode *inode, struct file *file)
3024{
3025 return single_open(file, proc_ip2mem_show, NULL);
3026}
3027
3028static const struct file_operations ip2mem_proc_fops = {
3029 .owner = THIS_MODULE,
3030 .open = proc_ip2mem_open,
3031 .read = seq_read,
3032 .llseek = seq_lseek,
3033 .release = single_release,
3034};
3035
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036/*
3037 * This is the handler for /proc/tty/driver/ip2
3038 *
3039 * This stretch of code has been largely plagerized from at least three
3040 * different sources including ip2mkdev.c and a couple of other drivers.
3041 * The bugs are all mine. :-) =mhw=
3042 */
3043static int ip2_read_proc(char *page, char **start, off_t off,
3044 int count, int *eof, void *data)
3045{
3046 int i, j, box;
3047 int len = 0;
3048 int boxes = 0;
3049 int ports = 0;
3050 int tports = 0;
3051 off_t begin = 0;
3052 i2eBordStrPtr pB;
3053
3054 len += sprintf(page, "ip2info: 1.0 driver: %s\n", pcVersion );
3055 len += sprintf(page+len, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
3056 IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
3057 IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
3058
3059 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3060 /* This need to be reset for a board by board count... */
3061 boxes = 0;
3062 pB = i2BoardPtrTable[i];
3063 if( pB ) {
3064 switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED )
3065 {
3066 case POR_ID_FIIEX:
3067 len += sprintf( page+len, "Board %d: EX ports=", i );
3068 for( box = 0; box < ABS_MAX_BOXES; ++box )
3069 {
3070 ports = 0;
3071
3072 if( pB->i2eChannelMap[box] != 0 ) ++boxes;
3073 for( j = 0; j < ABS_BIGGEST_BOX; ++j )
3074 {
3075 if( pB->i2eChannelMap[box] & 1<< j ) {
3076 ++ports;
3077 }
3078 }
3079 len += sprintf( page+len, "%d,", ports );
3080 tports += ports;
3081 }
3082
3083 --len; /* Backup over that last comma */
3084
3085 len += sprintf( page+len, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8 );
3086 break;
3087
3088 case POR_ID_II_4:
3089 len += sprintf(page+len, "Board %d: ISA-4 ports=4 boxes=1", i );
3090 tports = ports = 4;
3091 break;
3092
3093 case POR_ID_II_8:
3094 len += sprintf(page+len, "Board %d: ISA-8-std ports=8 boxes=1", i );
3095 tports = ports = 8;
3096 break;
3097
3098 case POR_ID_II_8R:
3099 len += sprintf(page+len, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i );
3100 tports = ports = 8;
3101 break;
3102
3103 default:
3104 len += sprintf(page+len, "Board %d: unknown", i );
3105 /* Don't try and probe for minor numbers */
3106 tports = ports = 0;
3107 }
3108
3109 } else {
3110 /* Don't try and probe for minor numbers */
3111 len += sprintf(page+len, "Board %d: vacant", i );
3112 tports = ports = 0;
3113 }
3114
3115 if( tports ) {
3116 len += sprintf(page+len, " minors=" );
3117
3118 for ( box = 0; box < ABS_MAX_BOXES; ++box )
3119 {
3120 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
3121 {
3122 if ( pB->i2eChannelMap[box] & (1 << j) )
3123 {
3124 len += sprintf (page+len,"%d,",
3125 j + ABS_BIGGEST_BOX *
3126 (box+i*ABS_MAX_BOXES));
3127 }
3128 }
3129 }
3130
3131 page[ len - 1 ] = '\n'; /* Overwrite that last comma */
3132 } else {
3133 len += sprintf (page+len,"\n" );
3134 }
3135
3136 if (len+begin > off+count)
3137 break;
3138 if (len+begin < off) {
3139 begin += len;
3140 len = 0;
3141 }
3142 }
3143
3144 if (i >= IP2_MAX_BOARDS)
3145 *eof = 1;
3146 if (off >= len+begin)
3147 return 0;
3148
3149 *start = page + (off-begin);
3150 return ((count < begin+len-off) ? count : begin+len-off);
3151 }
3152
3153/******************************************************************************/
3154/* Function: ip2trace() */
3155/* Parameters: Value to add to trace buffer */
3156/* Returns: Nothing */
3157/* */
3158/* Description: */
3159/* */
3160/* */
3161/******************************************************************************/
3162#ifdef IP2DEBUG_TRACE
3163void
3164ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
3165{
3166 long flags;
3167 unsigned long *pCode = &codes;
3168 union ip2breadcrumb bc;
3169 i2ChanStrPtr pCh;
3170
3171
3172 tracebuf[tracestuff++] = jiffies;
3173 if ( tracestuff == TRACEMAX ) {
3174 tracestuff = 0;
3175 }
3176 if ( tracestuff == tracestrip ) {
3177 if ( ++tracestrip == TRACEMAX ) {
3178 tracestrip = 0;
3179 }
3180 ++tracewrap;
3181 }
3182
3183 bc.hdr.port = 0xff & pn;
3184 bc.hdr.cat = cat;
3185 bc.hdr.codes = (unsigned char)( codes & 0xff );
3186 bc.hdr.label = label;
3187 tracebuf[tracestuff++] = bc.value;
3188
3189 for (;;) {
3190 if ( tracestuff == TRACEMAX ) {
3191 tracestuff = 0;
3192 }
3193 if ( tracestuff == tracestrip ) {
3194 if ( ++tracestrip == TRACEMAX ) {
3195 tracestrip = 0;
3196 }
3197 ++tracewrap;
3198 }
3199
3200 if ( !codes-- )
3201 break;
3202
3203 tracebuf[tracestuff++] = *++pCode;
3204 }
3205}
3206#endif
3207
3208
3209MODULE_LICENSE("GPL");
Chuck Shorteb0e71c2006-07-10 04:43:59 -07003210
3211static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
3212 { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
3213 { }
3214};
3215
3216MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);