blob: 07f3ea38b5828eda0a16ceed8b23fdbdee891d79 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2*
3* (c) 1999 by Computone Corporation
4*
5********************************************************************************
6*
7* PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
8* serial I/O controllers.
9*
10* DESCRIPTION: Mainline code for the device driver
11*
12*******************************************************************************/
13// ToDo:
14//
15// Fix the immediate DSS_NOW problem.
16// Work over the channel stats return logic in ip2_ipl_ioctl so they
17// make sense for all 256 possible channels and so the user space
18// utilities will compile and work properly.
19//
20// Done:
21//
22// 1.2.14 /\/\|=mhw=|\/\/
23// Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts.
24// Changed the definition of ip2trace to be more consistent with kernel style
25// Thanks to Andreas Dilger <adilger@turbolabs.com> for these updates
26//
27// 1.2.13 /\/\|=mhw=|\/\/
28// DEVFS: Renamed ttf/{n} to tts/F{n} and cuf/{n} to cua/F{n} to conform
29// to agreed devfs serial device naming convention.
30//
31// 1.2.12 /\/\|=mhw=|\/\/
32// Cleaned up some remove queue cut and paste errors
33//
34// 1.2.11 /\/\|=mhw=|\/\/
35// Clean up potential NULL pointer dereferences
36// Clean up devfs registration
37// Add kernel command line parsing for io and irq
Adrian Bunk9c4b5622006-01-19 18:07:10 +010038// Compile defaults for io and irq are now set in ip2.c not ip2.h!
Linus Torvalds1da177e2005-04-16 15:20:36 -070039// Reworked poll_only hack for explicit parameter setting
40// You must now EXPLICITLY set poll_only = 1 or set all irqs to 0
41// Merged ip2_loadmain and old_ip2_init
42// Converted all instances of interruptible_sleep_on into queue calls
43// Most of these had no race conditions but better to clean up now
44//
45// 1.2.10 /\/\|=mhw=|\/\/
46// Fixed the bottom half interrupt handler and enabled USE_IQI
47// to split the interrupt handler into a formal top-half / bottom-half
48// Fixed timing window on high speed processors that queued messages to
49// the outbound mail fifo faster than the board could handle.
50//
51// 1.2.9
52// Four box EX was barfing on >128k kmalloc, made structure smaller by
53// reducing output buffer size
54//
55// 1.2.8
56// Device file system support (MHW)
57//
58// 1.2.7
59// Fixed
60// Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules
61//
62// 1.2.6
63//Fixes DCD problems
64// DCD was not reported when CLOCAL was set on call to TIOCMGET
65//
66//Enhancements:
67// TIOCMGET requests and waits for status return
68// No DSS interrupts enabled except for DCD when needed
69//
70// For internal use only
71//
72//#define IP2DEBUG_INIT
73//#define IP2DEBUG_OPEN
74//#define IP2DEBUG_WRITE
75//#define IP2DEBUG_READ
76//#define IP2DEBUG_IOCTL
77//#define IP2DEBUG_IPL
78
79//#define IP2DEBUG_TRACE
80//#define DEBUG_FIFO
81
82/************/
83/* Includes */
84/************/
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
86#include <linux/ctype.h>
87#include <linux/string.h>
88#include <linux/fcntl.h>
89#include <linux/errno.h>
90#include <linux/module.h>
91#include <linux/signal.h>
92#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070093#include <linux/timer.h>
94#include <linux/interrupt.h>
95#include <linux/pci.h>
96#include <linux/mm.h>
97#include <linux/slab.h>
98#include <linux/major.h>
99#include <linux/wait.h>
100#include <linux/device.h>
Jonathan Corbetf2b98572008-05-18 15:32:43 -0600101#include <linux/smp_lock.h>
David Woodhouse547d8bb2008-06-11 16:57:21 +0100102#include <linux/firmware.h>
103#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105#include <linux/tty.h>
106#include <linux/tty_flip.h>
107#include <linux/termios.h>
108#include <linux/tty_driver.h>
109#include <linux/serial.h>
110#include <linux/ptrace.h>
111#include <linux/ioport.h>
112
113#include <linux/cdk.h>
114#include <linux/comstats.h>
115#include <linux/delay.h>
116#include <linux/bitops.h>
117
118#include <asm/system.h>
119#include <asm/io.h>
120#include <asm/irq.h>
121
122#include <linux/vmalloc.h>
123#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125#include <asm/uaccess.h>
126
Adrian Bunk9c4b5622006-01-19 18:07:10 +0100127#include "ip2types.h"
128#include "ip2trace.h"
129#include "ip2ioctl.h"
130#include "ip2.h"
131#include "i2ellis.h"
132#include "i2lib.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134/*****************
135 * /proc/ip2mem *
136 *****************/
137
138#include <linux/proc_fs.h>
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700139#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700141static const struct file_operations ip2mem_proc_fops;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700142static const struct file_operations ip2_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144/********************/
145/* Type Definitions */
146/********************/
147
148/*************/
149/* Constants */
150/*************/
151
152/* String constants to identify ourselves */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100153static const char pcName[] = "Computone IntelliPort Plus multiport driver";
154static const char pcVersion[] = "1.2.14";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156/* String constants for port names */
Jiri Slabycf176bc2008-10-13 10:34:36 +0100157static const char pcDriver_name[] = "ip2";
158static const char pcIpl[] = "ip2ipl";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160/***********************/
161/* Function Prototypes */
162/***********************/
163
164/* Global module entry functions */
165
166/* Private (static) functions */
167static int ip2_open(PTTY, struct file *);
168static void ip2_close(PTTY, struct file *);
Alan Coxd9e39532006-01-09 20:54:20 -0800169static int ip2_write(PTTY, const unsigned char *, int);
Alan Coxf34d7a52008-04-30 00:54:13 -0700170static int ip2_putchar(PTTY, unsigned char);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171static void ip2_flush_chars(PTTY);
172static int ip2_write_room(PTTY);
173static int ip2_chars_in_buf(PTTY);
174static void ip2_flush_buffer(PTTY);
175static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);
Alan Cox606d0992006-12-08 02:38:45 -0800176static void ip2_set_termios(PTTY, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177static void ip2_set_line_discipline(PTTY);
178static void ip2_throttle(PTTY);
179static void ip2_unthrottle(PTTY);
180static void ip2_stop(PTTY);
181static void ip2_start(PTTY);
182static void ip2_hangup(PTTY);
183static int ip2_tiocmget(struct tty_struct *tty, struct file *file);
184static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
185 unsigned int set, unsigned int clear);
186
187static void set_irq(int, int);
David Howellsc4028952006-11-22 14:57:56 +0000188static void ip2_interrupt_bh(struct work_struct *work);
David Howells7d12e782006-10-05 14:55:46 +0100189static irqreturn_t ip2_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void ip2_poll(unsigned long arg);
191static inline void service_all_boards(void);
David Howellsc4028952006-11-22 14:57:56 +0000192static void do_input(struct work_struct *);
193static void do_status(struct work_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195static void ip2_wait_until_sent(PTTY,int);
196
Alan Cox606d0992006-12-08 02:38:45 -0800197static void set_params (i2ChanStrPtr, struct ktermios *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *);
199static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *);
200
201static ssize_t ip2_ipl_read(struct file *, char __user *, size_t, loff_t *);
202static ssize_t ip2_ipl_write(struct file *, const char __user *, size_t, loff_t *);
Alan Cox47be36a2008-07-25 01:48:13 -0700203static long ip2_ipl_ioctl(struct file *, UINT, ULONG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static int ip2_ipl_open(struct inode *, struct file *);
205
206static int DumpTraceBuffer(char __user *, int);
207static int DumpFifoBuffer( char __user *, int);
208
David Woodhouse547d8bb2008-06-11 16:57:21 +0100209static void ip2_init_board(int, const struct firmware *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210static unsigned short find_eisa_board(int);
Rakib Mullick02c95a62010-01-23 18:53:51 +0600211static int ip2_setup(char *str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213/***************/
214/* Static Data */
215/***************/
216
217static struct tty_driver *ip2_tty_driver;
218
219/* Here, then is a table of board pointers which the interrupt routine should
220 * scan through to determine who it must service.
221 */
222static unsigned short i2nBoards; // Number of boards here
223
224static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS];
225
226static i2ChanStrPtr DevTable[IP2_MAX_PORTS];
227//DevTableMem just used to save addresses for kfree
228static void *DevTableMem[IP2_MAX_BOARDS];
229
230/* This is the driver descriptor for the ip2ipl device, which is used to
231 * download the loadware to the boards.
232 */
Arjan van de Ven62322d22006-07-03 00:24:21 -0700233static const struct file_operations ip2_ipl = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 .owner = THIS_MODULE,
235 .read = ip2_ipl_read,
236 .write = ip2_ipl_write,
Alan Cox47be36a2008-07-25 01:48:13 -0700237 .unlocked_ioctl = ip2_ipl_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 .open = ip2_ipl_open,
239};
240
Jiri Slabycf176bc2008-10-13 10:34:36 +0100241static unsigned long irq_counter;
242static unsigned long bh_counter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244// Use immediate queue to service interrupts
245#define USE_IQI
246//#define USE_IQ // PCI&2.2 needs work
247
248/* The timer_list entry for our poll routine. If interrupt operation is not
249 * selected, the board is serviced periodically to see if anything needs doing.
250 */
251#define POLL_TIMEOUT (jiffies + 1)
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700252static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
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
Rakib Mullick795877c2009-12-09 12:34:18 -0800267#ifdef IP2DEBUG_OPEN
Alan Cox7d7b93c2008-10-13 10:42:09 +0100268#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
269 tty->name,(pCh->flags), \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 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
Rakib Mullick02c95a62010-01-23 18:53:51 +0600289#define MAX_CMD_STR 50
290
Jiri Slabycf176bc2008-10-13 10:34:36 +0100291static int poll_only;
Rakib Mullick02c95a62010-01-23 18:53:51 +0600292static char cmd[MAX_CMD_STR];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294static int Eisa_irq;
295static int Eisa_slot;
296
297static int iindx;
298static char rirqs[IP2_MAX_BOARDS];
299static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
300
Jiri Slaby47babd42008-10-13 10:34:27 +0100301/* Note: Add compiled in defaults to these arrays, not to the structure
302 in ip2.h any longer. That structure WILL get overridden
303 by these values, or command line values, or insmod values!!! =mhw=
304*/
305static int io[IP2_MAX_BOARDS];
306static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
307
308MODULE_AUTHOR("Doug McNash");
309MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
310module_param_array(irq, int, NULL, 0);
311MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards");
312module_param_array(io, int, NULL, 0);
313MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards");
314module_param(poll_only, bool, 0);
315MODULE_PARM_DESC(poll_only, "Do not use card interrupts");
Rakib Mullick02c95a62010-01-23 18:53:51 +0600316module_param_string(ip2, cmd, MAX_CMD_STR, 0);
317MODULE_PARM_DESC(ip2, "Contains module parameter passed with 'ip2='");
Jiri Slaby47babd42008-10-13 10:34:27 +0100318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319/* for sysfs class support */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800320static struct class *ip2_class;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100322/* Some functions to keep track of what irqs we have */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100324static int __init is_valid_irq(int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
326 int *i = Valid_Irqs;
327
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100328 while (*i != 0 && *i != irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 i++;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100330
331 return *i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100334static void __init mark_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
336 rirqs[iindx++] = irq;
337}
338
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100339static int __exit clear_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
341 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100342 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 if (rirqs[i] == irq) {
344 rirqs[i] = 0;
345 return 1;
346 }
347 }
348 return 0;
349}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100351static int have_requested_irq(char irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100353 /* array init to zeros so 0 irq will not be requested as a side
354 * effect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 int i;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100356 for (i = 0; i < IP2_MAX_BOARDS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 if (rirqs[i] == irq)
358 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 return 0;
360}
361
362/******************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363/* Function: cleanup_module() */
364/* Parameters: None */
365/* Returns: Nothing */
366/* */
367/* Description: */
368/* This is a required entry point for an installable module. It has to return */
369/* the device and the driver to a passive state. It should not be necessary */
370/* to reset the board fully, especially as the loadware is downloaded */
371/* externally rather than in the driver. We just want to disable the board */
372/* and clear the loadware to a reset state. To allow this there has to be a */
373/* way to detect whether the board has the loadware running at init time to */
374/* handle subsequent installations of the driver. All memory allocated by the */
375/* driver should be returned since it may be unloaded from memory. */
376/******************************************************************************/
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100377static void __exit ip2_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
379 int err;
380 int i;
381
Akinobu Mita9d020a2e2008-10-13 10:35:05 +0100382 del_timer_sync(&PollTimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 /* Reset the boards we have. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100385 for (i = 0; i < IP2_MAX_BOARDS; i++)
386 if (i2BoardPtrTable[i])
387 iiReset(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389 /* The following is done at most once, if any boards were installed. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100390 for (i = 0; i < IP2_MAX_BOARDS; i++) {
391 if (i2BoardPtrTable[i]) {
392 iiResetDelay(i2BoardPtrTable[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 /* free io addresses and Tibet */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100394 release_region(ip2config.addr[i], 8);
tonyj@suse.de07c015e2007-08-07 22:28:44 -0700395 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100396 device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR,
397 4 * i + 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 }
399 /* Disable and remove interrupt handler. */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100400 if (ip2config.irq[i] > 0 &&
401 have_requested_irq(ip2config.irq[i])) {
402 free_irq(ip2config.irq[i], (void *)&pcName);
403 clear_requested_irq(ip2config.irq[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
405 }
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800406 class_destroy(ip2_class);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100407 err = tty_unregister_driver(ip2_tty_driver);
408 if (err)
409 printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n",
410 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 put_tty_driver(ip2_tty_driver);
Akinobu Mita68fc4fa2007-07-19 01:47:50 -0700412 unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
Alexey Dobriyanc74c1202008-04-29 01:01:44 -0700413 remove_proc_entry("ip2mem", NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100415 /* free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 for (i = 0; i < IP2_MAX_BOARDS; i++) {
417 void *pB;
418#ifdef CONFIG_PCI
419 if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
420 pci_disable_device(ip2config.pci_dev[i]);
Alan Cox1aff0ec2006-09-30 23:27:59 -0700421 pci_dev_put(ip2config.pci_dev[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 ip2config.pci_dev[i] = NULL;
423 }
424#endif
Jiri Slaby7ccd7022008-10-13 10:34:45 +0100425 pB = i2BoardPtrTable[i];
426 if (pB != NULL) {
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100427 kfree(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 i2BoardPtrTable[i] = NULL;
429 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100430 if (DevTableMem[i] != NULL) {
431 kfree(DevTableMem[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 DevTableMem[i] = NULL;
433 }
434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435}
Jon Schindler83e422b2008-04-30 00:53:53 -0700436module_exit(ip2_cleanup_module);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700438static const struct tty_operations ip2_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 .open = ip2_open,
440 .close = ip2_close,
441 .write = ip2_write,
442 .put_char = ip2_putchar,
443 .flush_chars = ip2_flush_chars,
444 .write_room = ip2_write_room,
445 .chars_in_buffer = ip2_chars_in_buf,
446 .flush_buffer = ip2_flush_buffer,
447 .ioctl = ip2_ioctl,
448 .throttle = ip2_throttle,
449 .unthrottle = ip2_unthrottle,
450 .set_termios = ip2_set_termios,
451 .set_ldisc = ip2_set_line_discipline,
452 .stop = ip2_stop,
453 .start = ip2_start,
454 .hangup = ip2_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 .tiocmget = ip2_tiocmget,
456 .tiocmset = ip2_tiocmset,
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -0700457 .proc_fops = &ip2_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458};
459
460/******************************************************************************/
461/* Function: ip2_loadmain() */
462/* Parameters: irq, io from command line of insmod et. al. */
463/* pointer to fip firmware and firmware size for boards */
464/* Returns: Success (0) */
465/* */
466/* Description: */
467/* This was the required entry point for all drivers (now in ip2.c) */
468/* It performs all */
469/* initialisation of the devices and driver structures, and registers itself */
470/* with the relevant kernel modules. */
471/******************************************************************************/
Thomas Gleixner0f2ed4c2006-07-01 19:29:33 -0700472/* IRQF_DISABLED - if set blocks all interrupts else only this line */
473/* IRQF_SHARED - for shared irq PCI or maybe EISA only */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474/* SA_RANDOM - can be source for cert. random number generators */
475#define IP2_SA_FLAGS 0
476
David Woodhouse547d8bb2008-06-11 16:57:21 +0100477
478static const struct firmware *ip2_request_firmware(void)
479{
480 struct platform_device *pdev;
481 const struct firmware *fw;
482
483 pdev = platform_device_register_simple("ip2", 0, NULL, 0);
484 if (IS_ERR(pdev)) {
485 printk(KERN_ERR "Failed to register platform device for ip2\n");
486 return NULL;
487 }
488 if (request_firmware(&fw, "intelliport2.bin", &pdev->dev)) {
489 printk(KERN_ERR "Failed to load firmware 'intelliport2.bin'\n");
490 fw = NULL;
491 }
492 platform_device_unregister(pdev);
493 return fw;
494}
495
Jiri Slaby47babd42008-10-13 10:34:27 +0100496/******************************************************************************
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);
Jiri Slaby47babd42008-10-13 10:34:27 +0100539
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100540static int __init ip2_loadmain(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
542 int i, j, box;
543 int err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 i2eBordStrPtr pB = NULL;
545 int rc = -1;
David Woodhouse547d8bb2008-06-11 16:57:21 +0100546 const struct firmware *fw = NULL;
Rakib Mullick02c95a62010-01-23 18:53:51 +0600547 char *str;
548
549 str = cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
Jiri Slaby47babd42008-10-13 10:34:27 +0100551 if (poll_only) {
552 /* Hard lock the interrupts to zero */
553 irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0;
554 }
555
Rakib Mullick02c95a62010-01-23 18:53:51 +0600556 /* Check module parameter with 'ip2=' has been passed or not */
557 if (!poll_only && (!strncmp(str, "ip2=", 4)))
558 ip2_setup(str);
559
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100560 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 /* process command line arguments to modprobe or
563 insmod i.e. iop & irqp */
564 /* irqp and iop should ALWAYS be specified now... But we check
565 them individually just to be sure, anyways... */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100566 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
Jiri Slaby47babd42008-10-13 10:34:27 +0100567 ip2config.addr[i] = io[i];
568 if (irq[i] >= 0)
569 ip2config.irq[i] = irq[i];
570 else
571 ip2config.irq[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100572 /* This is a little bit of a hack. If poll_only=1 on command
573 line back in ip2.c OR all IRQs on all specified boards are
574 explicitly set to 0, then drop to poll only mode and override
575 PCI or EISA interrupts. This superceeds the old hack of
576 triggering if all interrupts were zero (like da default).
577 Still a hack but less prone to random acts of terrorism.
578
579 What we really should do, now that the IRQ default is set
580 to -1, is to use 0 as a hard coded, do not probe.
581
582 /\/\|=mhw=|\/\/
583 */
Jiri Slaby47babd42008-10-13 10:34:27 +0100584 poll_only |= irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 }
586 poll_only = !poll_only;
587
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 /* Announce our presence */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100589 printk(KERN_INFO "%s version %s\n", pcName, pcVersion);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
591 ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS);
592 if (!ip2_tty_driver)
593 return -ENOMEM;
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 /* Initialise all the boards we can find (up to the maximum). */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100596 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
597 switch (ip2config.addr[i]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 case 0: /* skip this slot even if card is present */
599 break;
600 default: /* ISA */
601 /* ISA address must be specified */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100602 if (ip2config.addr[i] < 0x100 ||
603 ip2config.addr[i] > 0x3f8) {
604 printk(KERN_ERR "IP2: Bad ISA board %d "
605 "address %x\n", i,
606 ip2config.addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 ip2config.addr[i] = 0;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100608 break;
609 }
610 ip2config.type[i] = ISA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100612 /* Check for valid irq argument, set for polling if
613 * invalid */
614 if (ip2config.irq[i] &&
615 !is_valid_irq(ip2config.irq[i])) {
616 printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",
617 ip2config.irq[i]);
618 /* 0 is polling and is valid in that sense */
619 ip2config.irq[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 }
621 break;
622 case PCI:
623#ifdef CONFIG_PCI
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100624 {
Rakib Mullick795877c2009-12-09 12:34:18 -0800625 struct pci_dev *pdev = NULL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100626 u32 addr;
627 int status;
Andrew Mortonad4a5bb2007-07-31 00:39:41 -0700628
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100629 pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
630 PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev);
631 if (pdev == NULL) {
632 ip2config.addr[i] = 0;
633 printk(KERN_ERR "IP2: PCI board %d not "
634 "found\n", i);
635 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100637
638 if (pci_enable_device(pdev)) {
639 dev_err(&pdev->dev, "can't enable device\n");
Rakib Mullick795877c2009-12-09 12:34:18 -0800640 goto out;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100641 }
642 ip2config.type[i] = PCI;
643 ip2config.pci_dev[i] = pci_dev_get(pdev);
644 status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1,
645 &addr);
646 if (addr & 1)
647 ip2config.addr[i] = (USHORT)(addr & 0xfffe);
648 else
649 dev_err(&pdev->dev, "I/O address error\n");
650
651 ip2config.irq[i] = pdev->irq;
Rakib Mullick795877c2009-12-09 12:34:18 -0800652out:
653 pci_dev_put(pdev);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655#else
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100656 printk(KERN_ERR "IP2: PCI card specified but PCI "
657 "support not enabled.\n");
658 printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI "
659 "defined!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660#endif /* CONFIG_PCI */
661 break;
662 case EISA:
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100663 ip2config.addr[i] = find_eisa_board(Eisa_slot + 1);
664 if (ip2config.addr[i] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 /* Eisa_irq set as side effect, boo */
666 ip2config.type[i] = EISA;
667 }
668 ip2config.irq[i] = Eisa_irq;
669 break;
670 } /* switch */
671 } /* for */
Alan Cox1aff0ec2006-09-30 23:27:59 -0700672
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100673 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
674 if (ip2config.addr[i]) {
Mariusz Kozlowski978550b82007-10-16 23:26:45 -0700675 pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
676 if (pB) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 i2BoardPtrTable[i] = pB;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100678 iiSetAddress(pB, ip2config.addr[i],
679 ii2DelayTimer);
680 iiReset(pB);
681 } else
682 printk(KERN_ERR "IP2: board memory allocation "
683 "error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
685 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100686 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
687 pB = i2BoardPtrTable[i];
688 if (pB != NULL) {
689 iiResetDelay(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 break;
691 }
692 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100693 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100694 /* We don't want to request the firmware unless we have at
695 least one board */
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100696 if (i2BoardPtrTable[i] != NULL) {
David Woodhouse547d8bb2008-06-11 16:57:21 +0100697 if (!fw)
698 fw = ip2_request_firmware();
699 if (!fw)
700 break;
701 ip2_init_board(i, fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
703 }
David Woodhouse547d8bb2008-06-11 16:57:21 +0100704 if (fw)
705 release_firmware(fw);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100707 ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 ip2_tty_driver->owner = THIS_MODULE;
710 ip2_tty_driver->name = "ttyF";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 ip2_tty_driver->driver_name = pcDriver_name;
712 ip2_tty_driver->major = IP2_TTY_MAJOR;
713 ip2_tty_driver->minor_start = 0;
714 ip2_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
715 ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL;
716 ip2_tty_driver->init_termios = tty_std_termios;
717 ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100718 ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW |
719 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 tty_set_operations(ip2_tty_driver, &ip2_ops);
721
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100722 ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100724 err = tty_register_driver(ip2_tty_driver);
725 if (err) {
726 printk(KERN_ERR "IP2: failed to register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 put_tty_driver(ip2_tty_driver);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100728 return err; /* leaking resources */
729 }
730
731 err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl);
732 if (err) {
733 printk(KERN_ERR "IP2: failed to register IPL device (%d)\n",
734 err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 } else {
736 /* create the sysfs class */
gregkh@suse.deca8eca62005-03-23 09:53:09 -0800737 ip2_class = class_create(THIS_MODULE, "ip2");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (IS_ERR(ip2_class)) {
739 err = PTR_ERR(ip2_class);
740 goto out_chrdev;
741 }
742 }
743 /* Register the read_procmem thing */
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -0700744 if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 printk(KERN_ERR "IP2: failed to register read_procmem\n");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100746 return -EIO; /* leaking resources */
747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100749 ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0);
750 /* Register the interrupt handler or poll handler, depending upon the
751 * specified interrupt.
752 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100754 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
755 if (ip2config.addr[i] == 0)
756 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100758 pB = i2BoardPtrTable[i];
759 if (pB != NULL) {
Greg Kroah-Hartman03457cd2008-07-21 20:03:34 -0700760 device_create(ip2_class, NULL,
761 MKDEV(IP2_IPL_MAJOR, 4 * i),
762 NULL, "ipl%d", i);
763 device_create(ip2_class, NULL,
764 MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
765 NULL, "stat%d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100767 for (box = 0; box < ABS_MAX_BOXES; box++)
768 for (j = 0; j < ABS_BIGGEST_BOX; j++)
769 if (pB->i2eChannelMap[box] & (1 << j))
770 tty_register_device(
771 ip2_tty_driver,
772 j + ABS_BIGGEST_BOX *
773 (box+i*ABS_MAX_BOXES),
774 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100776
777 if (poll_only) {
778 /* Poll only forces driver to only use polling and
779 to ignore the probed PCI or EISA interrupts. */
780 ip2config.irq[i] = CIR_POLL;
781 }
782 if (ip2config.irq[i] == CIR_POLL) {
783retry:
Akinobu Mita9d020a2e2008-10-13 10:35:05 +0100784 if (!timer_pending(&PollTimer)) {
785 mod_timer(&PollTimer, POLL_TIMEOUT);
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100786 printk(KERN_INFO "IP2: polling\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100788 } else {
789 if (have_requested_irq(ip2config.irq[i]))
790 continue;
791 rc = request_irq(ip2config.irq[i], ip2_interrupt,
792 IP2_SA_FLAGS |
793 (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
794 pcName, i2BoardPtrTable[i]);
795 if (rc) {
796 printk(KERN_ERR "IP2: request_irq failed: "
797 "error %d\n", rc);
798 ip2config.irq[i] = CIR_POLL;
799 printk(KERN_INFO "IP2: Polling %ld/sec.\n",
800 (POLL_TIMEOUT - jiffies));
801 goto retry;
802 }
803 mark_requested_irq(ip2config.irq[i]);
804 /* Initialise the interrupt handler bottom half
805 * (aka slih). */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
807 }
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100808
809 for (i = 0; i < IP2_MAX_BOARDS; ++i) {
810 if (i2BoardPtrTable[i]) {
811 /* set and enable board interrupt */
812 set_irq(i, ip2config.irq[i]);
813 }
814 }
815
816 ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0);
817
818 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820out_chrdev:
821 unregister_chrdev(IP2_IPL_MAJOR, "ip2");
Jiri Slabyf1ddfd92008-10-13 10:34:56 +0100822 /* unregister and put tty here */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 return err;
824}
Jiri Slaby47babd42008-10-13 10:34:27 +0100825module_init(ip2_loadmain);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827/******************************************************************************/
828/* Function: ip2_init_board() */
829/* Parameters: Index of board in configuration structure */
830/* Returns: Success (0) */
831/* */
832/* Description: */
833/* This function initializes the specified board. The loadware is copied to */
834/* the board, the channel structures are initialized, and the board details */
835/* are reported on the console. */
836/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700837static void
David Woodhouse547d8bb2008-06-11 16:57:21 +0100838ip2_init_board(int boardnum, const struct firmware *fw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839{
840 int i;
841 int nports = 0, nboxes = 0;
842 i2ChanStrPtr pCh;
843 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
844
845 if ( !iiInitialize ( pB ) ) {
846 printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
847 pB->i2eBase, pB->i2eError );
848 goto err_initialize;
849 }
850 printk(KERN_INFO "IP2: Board %d: addr=0x%x irq=%d\n", boardnum + 1,
851 ip2config.addr[boardnum], ip2config.irq[boardnum] );
852
853 if (!request_region( ip2config.addr[boardnum], 8, pcName )) {
854 printk(KERN_ERR "IP2: bad addr=0x%x\n", ip2config.addr[boardnum]);
855 goto err_initialize;
856 }
857
David Woodhouse547d8bb2008-06-11 16:57:21 +0100858 if ( iiDownloadAll ( pB, (loadHdrStrPtr)fw->data, 1, fw->size )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 != II_DOWN_GOOD ) {
860 printk ( KERN_ERR "IP2: failed to download loadware\n" );
861 goto err_release_region;
862 } else {
863 printk ( KERN_INFO "IP2: fv=%d.%d.%d lv=%d.%d.%d\n",
864 pB->i2ePom.e.porVersion,
865 pB->i2ePom.e.porRevision,
866 pB->i2ePom.e.porSubRev, pB->i2eLVersion,
867 pB->i2eLRevision, pB->i2eLSub );
868 }
869
870 switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
871
872 default:
873 printk( KERN_ERR "IP2: Unknown board type, ID = %x\n",
874 pB->i2ePom.e.porID );
875 nports = 0;
876 goto err_release_region;
877 break;
878
879 case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
880 printk ( KERN_INFO "IP2: ISA-4\n" );
881 nports = 4;
882 break;
883
884 case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
885 printk ( KERN_INFO "IP2: ISA-8 std\n" );
886 nports = 8;
887 break;
888
889 case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
890 printk ( KERN_INFO "IP2: ISA-8 RJ11\n" );
891 nports = 8;
892 break;
893
894 case POR_ID_FIIEX: /* IntelliPort IIEX */
895 {
896 int portnum = IP2_PORTS_PER_BOARD * boardnum;
897 int box;
898
899 for( box = 0; box < ABS_MAX_BOXES; ++box ) {
900 if ( pB->i2eChannelMap[box] != 0 ) {
901 ++nboxes;
902 }
903 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
904 if ( pB->i2eChannelMap[box] & 1<< i ) {
905 ++nports;
906 }
907 }
908 }
909 DevTableMem[boardnum] = pCh =
910 kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
911 if ( !pCh ) {
912 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
913 goto err_release_region;
914 }
915 if ( !i2InitChannels( pB, nports, pCh ) ) {
916 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
917 kfree ( pCh );
918 goto err_release_region;
919 }
920 pB->i2eChannelPtr = &DevTable[portnum];
921 pB->i2eChannelCnt = ABS_MOST_PORTS;
922
923 for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
924 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
925 if ( pB->i2eChannelMap[box] & (1 << i) ) {
926 DevTable[portnum + i] = pCh;
927 pCh->port_index = portnum + i;
928 pCh++;
929 }
930 }
931 }
932 printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit\n",
933 nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
934 }
935 goto ex_exit;
936 }
937 DevTableMem[boardnum] = pCh =
938 kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
939 if ( !pCh ) {
940 printk ( KERN_ERR "IP2: (i2_init_channel:) Out of memory.\n");
941 goto err_release_region;
942 }
943 pB->i2eChannelPtr = pCh;
944 pB->i2eChannelCnt = nports;
945 if ( !i2InitChannels( pB, nports, pCh ) ) {
946 printk(KERN_ERR "IP2: i2InitChannels failed: %d\n",pB->i2eError);
947 kfree ( pCh );
948 goto err_release_region;
949 }
950 pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
951
952 for( i = 0; i < pB->i2eChannelCnt; ++i ) {
953 DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
954 pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
955 pCh++;
956 }
957ex_exit:
David Howellsc4028952006-11-22 14:57:56 +0000958 INIT_WORK(&pB->tqueue_interrupt, ip2_interrupt_bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 return;
960
961err_release_region:
962 release_region(ip2config.addr[boardnum], 8);
963err_initialize:
964 kfree ( pB );
965 i2BoardPtrTable[boardnum] = NULL;
966 return;
967}
968
969/******************************************************************************/
970/* Function: find_eisa_board ( int start_slot ) */
971/* Parameters: First slot to check */
972/* Returns: Address of EISA IntelliPort II controller */
973/* */
974/* Description: */
975/* This function searches for an EISA IntelliPort controller, starting */
976/* from the specified slot number. If the motherboard is not identified as an */
977/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
978/* it returns the base address of the controller. */
979/******************************************************************************/
Randy Dunlap673e3212006-06-25 05:48:39 -0700980static unsigned short
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981find_eisa_board( int start_slot )
982{
983 int i, j;
984 unsigned int idm = 0;
985 unsigned int idp = 0;
986 unsigned int base = 0;
987 unsigned int value;
988 int setup_address;
989 int setup_irq;
990 int ismine = 0;
991
992 /*
993 * First a check for an EISA motherboard, which we do by comparing the
994 * EISA ID registers for the system board and the first couple of slots.
995 * No slot ID should match the system board ID, but on an ISA or PCI
996 * machine the odds are that an empty bus will return similar values for
997 * each slot.
998 */
999 i = 0x0c80;
1000 value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
1001 for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
1002 j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
1003 if ( value == j )
1004 return 0;
1005 }
1006
1007 /*
1008 * OK, so we are inclined to believe that this is an EISA machine. Find
1009 * an IntelliPort controller.
1010 */
1011 for( i = start_slot; i < 16; i++ ) {
1012 base = i << 12;
1013 idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
1014 idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
1015 ismine = 0;
1016 if ( idm == 0x0e8e ) {
1017 if ( idp == 0x0281 || idp == 0x0218 ) {
1018 ismine = 1;
1019 } else if ( idp == 0x0282 || idp == 0x0283 ) {
1020 ismine = 3; /* Can do edge-trigger */
1021 }
1022 if ( ismine ) {
1023 Eisa_slot = i;
1024 break;
1025 }
1026 }
1027 }
1028 if ( !ismine )
1029 return 0;
1030
1031 /* It's some sort of EISA card, but at what address is it configured? */
1032
1033 setup_address = base + 0xc88;
1034 value = inb(base + 0xc86);
1035 setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
1036
1037 if ( (ismine & 2) && !(value & 0x10) ) {
1038 ismine = 1; /* Could be edging, but not */
1039 }
1040
1041 if ( Eisa_irq == 0 ) {
1042 Eisa_irq = setup_irq;
1043 } else if ( Eisa_irq != setup_irq ) {
1044 printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
1045 }
1046
1047#ifdef IP2DEBUG_INIT
1048printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
1049 base >> 12, idm, idp, setup_address);
1050 if ( Eisa_irq ) {
1051 printk(KERN_DEBUG ", Interrupt %d %s\n",
1052 setup_irq, (ismine & 2) ? "(edge)" : "(level)");
1053 } else {
1054 printk(KERN_DEBUG ", (polled)\n");
1055 }
1056#endif
1057 return setup_address;
1058}
1059
1060/******************************************************************************/
1061/* Function: set_irq() */
1062/* Parameters: index to board in board table */
1063/* IRQ to use */
1064/* Returns: Success (0) */
1065/* */
1066/* Description: */
1067/******************************************************************************/
1068static void
1069set_irq( int boardnum, int boardIrq )
1070{
1071 unsigned char tempCommand[16];
1072 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
1073 unsigned long flags;
1074
1075 /*
1076 * Notify the boards they may generate interrupts. This is done by
1077 * sending an in-line command to channel 0 on each board. This is why
1078 * the channels have to be defined already. For each board, if the
1079 * interrupt has never been defined, we must do so NOW, directly, since
1080 * board will not send flow control or even give an interrupt until this
1081 * is done. If polling we must send 0 as the interrupt parameter.
1082 */
1083
1084 // We will get an interrupt here at the end of this function
1085
1086 iiDisableMailIrq(pB);
1087
1088 /* We build up the entire packet header. */
1089 CHANNEL_OF(tempCommand) = 0;
1090 PTYPE_OF(tempCommand) = PTYPE_INLINE;
1091 CMD_COUNT_OF(tempCommand) = 2;
1092 (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
1093 (CMD_OF(tempCommand))[1] = boardIrq;
1094 /*
1095 * Write to FIFO; don't bother to adjust fifo capacity for this, since
1096 * board will respond almost immediately after SendMail hit.
1097 */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001098 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001100 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 pB->i2eUsingIrq = boardIrq;
1102 pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
1103
1104 /* Need to update number of boards before you enable mailbox int */
1105 ++i2nBoards;
1106
1107 CHANNEL_OF(tempCommand) = 0;
1108 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1109 CMD_COUNT_OF(tempCommand) = 6;
1110 (CMD_OF(tempCommand))[0] = 88; // SILO
1111 (CMD_OF(tempCommand))[1] = 64; // chars
1112 (CMD_OF(tempCommand))[2] = 32; // ms
1113
1114 (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK
1115 (CMD_OF(tempCommand))[4] = 64; // chars
1116
1117 (CMD_OF(tempCommand))[5] = 87; // HW_TEST
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001118 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 iiWriteBuf(pB, tempCommand, 8);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001120 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122 CHANNEL_OF(tempCommand) = 0;
1123 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1124 CMD_COUNT_OF(tempCommand) = 1;
1125 (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */
1126 iiWriteBuf(pB, tempCommand, 3);
1127
1128#ifdef XXX
1129 // enable heartbeat for test porpoises
1130 CHANNEL_OF(tempCommand) = 0;
1131 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1132 CMD_COUNT_OF(tempCommand) = 2;
1133 (CMD_OF(tempCommand))[0] = 44; /* get ping */
1134 (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001135 write_lock_irqsave(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 iiWriteBuf(pB, tempCommand, 4);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001137 write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138#endif
1139
1140 iiEnableMailIrq(pB);
1141 iiSendPendingMail(pB);
1142}
1143
1144/******************************************************************************/
1145/* Interrupt Handler Section */
1146/******************************************************************************/
1147
1148static inline void
1149service_all_boards(void)
1150{
1151 int i;
1152 i2eBordStrPtr pB;
1153
1154 /* Service every board on the list */
1155 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
1156 pB = i2BoardPtrTable[i];
1157 if ( pB ) {
1158 i2ServiceBoard( pB );
1159 }
1160 }
1161}
1162
1163
1164/******************************************************************************/
David Howellsc4028952006-11-22 14:57:56 +00001165/* Function: ip2_interrupt_bh(work) */
1166/* Parameters: work - pointer to the board structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167/* Returns: Nothing */
1168/* */
1169/* Description: */
1170/* Service the board in a bottom half interrupt handler and then */
1171/* reenable the board's interrupts if it has an IRQ number */
1172/* */
1173/******************************************************************************/
1174static void
David Howellsc4028952006-11-22 14:57:56 +00001175ip2_interrupt_bh(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176{
David Howellsc4028952006-11-22 14:57:56 +00001177 i2eBordStrPtr pB = container_of(work, i2eBordStr, tqueue_interrupt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178// pB better well be set or we have a problem! We can only get
1179// here from the IMMEDIATE queue. Here, we process the boards.
1180// Checking pB doesn't cost much and it saves us from the sanity checkers.
1181
1182 bh_counter++;
1183
1184 if ( pB ) {
1185 i2ServiceBoard( pB );
1186 if( pB->i2eUsingIrq ) {
1187// Re-enable his interrupts
1188 iiEnableMailIrq(pB);
1189 }
1190 }
1191}
1192
1193
1194/******************************************************************************/
David Howells7d12e782006-10-05 14:55:46 +01001195/* Function: ip2_interrupt(int irq, void *dev_id) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196/* Parameters: irq - interrupt number */
1197/* pointer to optional device ID structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198/* Returns: Nothing */
1199/* */
1200/* Description: */
1201/* */
1202/* Our task here is simply to identify each board which needs servicing. */
1203/* If we are queuing then, queue it to be serviced, and disable its irq */
1204/* mask otherwise process the board directly. */
1205/* */
1206/* We could queue by IRQ but that just complicates things on both ends */
1207/* with very little gain in performance (how many instructions does */
1208/* it take to iterate on the immediate queue). */
1209/* */
1210/* */
1211/******************************************************************************/
Jeff Garzikf3518e42007-10-19 15:24:59 -04001212static void
1213ip2_irq_work(i2eBordStrPtr pB)
1214{
1215#ifdef USE_IQI
1216 if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
1217// Disable his interrupt (will be enabled when serviced)
1218// This is mostly to protect from reentrancy.
1219 iiDisableMailIrq(pB);
1220
1221// Park the board on the immediate queue for processing.
1222 schedule_work(&pB->tqueue_interrupt);
1223
1224// Make sure the immediate queue is flagged to fire.
1225 }
1226#else
1227
1228// We are using immediate servicing here. This sucks and can
1229// cause all sorts of havoc with ppp and others. The failsafe
1230// check on iiSendPendingMail could also throw a hairball.
1231
1232 i2ServiceBoard( pB );
1233
1234#endif /* USE_IQI */
1235}
1236
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001237static void
1238ip2_polled_interrupt(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239{
1240 int i;
1241 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001243 ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
1245 /* Service just the boards on the list using this irq */
1246 for( i = 0; i < i2nBoards; ++i ) {
1247 pB = i2BoardPtrTable[i];
1248
1249// Only process those boards which match our IRQ.
1250// IRQ = 0 for polled boards, we won't poll "IRQ" boards
1251
Jiri Slaby7ccd7022008-10-13 10:34:45 +01001252 if (pB && pB->i2eUsingIrq == 0)
Jeff Garzikf3518e42007-10-19 15:24:59 -04001253 ip2_irq_work(pB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 }
1255
1256 ++irq_counter;
1257
1258 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001259}
1260
1261static irqreturn_t
1262ip2_interrupt(int irq, void *dev_id)
1263{
1264 i2eBordStrPtr pB = dev_id;
1265
1266 ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, pB->i2eUsingIrq );
1267
1268 ip2_irq_work(pB);
1269
1270 ++irq_counter;
1271
1272 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1273 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274}
1275
1276/******************************************************************************/
1277/* Function: ip2_poll(unsigned long arg) */
1278/* Parameters: ? */
1279/* Returns: Nothing */
1280/* */
1281/* Description: */
1282/* This function calls the library routine i2ServiceBoard for each board in */
1283/* the board table. This is used instead of the interrupt routine when polled */
1284/* mode is specified. */
1285/******************************************************************************/
1286static void
1287ip2_poll(unsigned long arg)
1288{
1289 ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
1290
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 // Just polled boards, IRQ = 0 will hit all non-interrupt boards.
1292 // It will NOT poll boards handled by hard interrupts.
Joe Perches8dfba4d2008-02-03 17:11:42 +02001293 // The issue of queued BH interrupts is handled in ip2_interrupt().
Jeff Garzik6bd3bd62007-10-19 15:38:40 -04001294 ip2_polled_interrupt();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
Akinobu Mita9d020a2e2008-10-13 10:35:05 +01001296 mod_timer(&PollTimer, POLL_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
1298 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1299}
1300
David Howellsc4028952006-11-22 14:57:56 +00001301static void do_input(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
David Howellsc4028952006-11-22 14:57:56 +00001303 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_input);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 unsigned long flags;
1305
1306 ip2trace(CHANN, ITRC_INPUT, 21, 0 );
1307
1308 // Data input
1309 if ( pCh->pTTY != NULL ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001310 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001312 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 i2Input( pCh );
1314 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001315 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 } else {
1317 ip2trace(CHANN, ITRC_INPUT, 22, 0 );
1318
1319 i2InputFlush( pCh );
1320 }
1321}
1322
1323// code duplicated from n_tty (ldisc)
1324static inline void isig(int sig, struct tty_struct *tty, int flush)
1325{
Alan Coxa352def2008-07-16 21:53:12 +01001326 /* FIXME: This is completely bogus */
Eric W. Biedermanab521dc2007-02-12 00:53:00 -08001327 if (tty->pgrp)
1328 kill_pgrp(tty->pgrp, sig, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 if (flush || !L_NOFLSH(tty)) {
Alan Coxc65c9bc2009-06-11 12:50:12 +01001330 if ( tty->ldisc->ops->flush_buffer )
1331 tty->ldisc->ops->flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 i2InputFlush( tty->driver_data );
1333 }
1334}
1335
David Howellsc4028952006-11-22 14:57:56 +00001336static void do_status(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337{
David Howellsc4028952006-11-22 14:57:56 +00001338 i2ChanStrPtr pCh = container_of(work, i2ChanStr, tqueue_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 int status;
1340
1341 status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
1342
1343 ip2trace (CHANN, ITRC_STATUS, 21, 1, status );
1344
1345 if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
1346 if ( (status & I2_BRK) ) {
1347 // code duplicated from n_tty (ldisc)
1348 if (I_IGNBRK(pCh->pTTY))
1349 goto skip_this;
1350 if (I_BRKINT(pCh->pTTY)) {
1351 isig(SIGINT, pCh->pTTY, 1);
1352 goto skip_this;
1353 }
1354 wake_up_interruptible(&pCh->pTTY->read_wait);
1355 }
1356#ifdef NEVER_HAPPENS_AS_SETUP_XXX
1357 // and can't work because we don't know the_char
1358 // as the_char is reported on a separate path
1359 // The intelligent board does this stuff as setup
1360 {
1361 char brkf = TTY_NORMAL;
1362 unsigned char brkc = '\0';
1363 unsigned char tmp;
1364 if ( (status & I2_BRK) ) {
1365 brkf = TTY_BREAK;
1366 brkc = '\0';
1367 }
1368 else if (status & I2_PAR) {
1369 brkf = TTY_PARITY;
1370 brkc = the_char;
1371 } else if (status & I2_FRA) {
1372 brkf = TTY_FRAME;
1373 brkc = the_char;
1374 } else if (status & I2_OVR) {
1375 brkf = TTY_OVERRUN;
1376 brkc = the_char;
1377 }
1378 tmp = pCh->pTTY->real_raw;
1379 pCh->pTTY->real_raw = 0;
Alan Coxa352def2008-07-16 21:53:12 +01001380 pCh->pTTY->ldisc->ops.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 pCh->pTTY->real_raw = tmp;
1382 }
1383#endif /* NEVER_HAPPENS_AS_SETUP_XXX */
1384 }
1385skip_this:
1386
1387 if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
1388 wake_up_interruptible(&pCh->delta_msr_wait);
1389
1390 if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
1391 if ( status & I2_DCD ) {
1392 if ( pCh->wopen ) {
1393 wake_up_interruptible ( &pCh->open_wait );
1394 }
1395 } else {
1396 if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
1397 tty_hangup( pCh->pTTY );
1398 }
1399 }
1400 }
1401 }
1402
1403 ip2trace (CHANN, ITRC_STATUS, 26, 0 );
1404}
1405
1406/******************************************************************************/
1407/* Device Open/Close/Ioctl Entry Point Section */
1408/******************************************************************************/
1409
1410/******************************************************************************/
1411/* Function: open_sanity_check() */
1412/* Parameters: Pointer to tty structure */
1413/* Pointer to file structure */
1414/* Returns: Success or failure */
1415/* */
1416/* Description: */
1417/* Verifies the structure magic numbers and cross links. */
1418/******************************************************************************/
1419#ifdef IP2DEBUG_OPEN
1420static void
1421open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
1422{
1423 if ( pBrd->i2eValid != I2E_MAGIC ) {
1424 printk(KERN_ERR "IP2: invalid board structure\n" );
1425 } else if ( pBrd != pCh->pMyBord ) {
1426 printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
1427 pCh->pMyBord );
1428 } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
1429 printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
1430 } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
1431 } else {
1432 printk(KERN_INFO "IP2: all pointers check out!\n" );
1433 }
1434}
1435#endif
1436
1437
1438/******************************************************************************/
1439/* Function: ip2_open() */
1440/* Parameters: Pointer to tty structure */
1441/* Pointer to file structure */
1442/* Returns: Success or failure */
1443/* */
1444/* Description: (MANDATORY) */
1445/* A successful device open has to run a gauntlet of checks before it */
1446/* completes. After some sanity checking and pointer setup, the function */
1447/* blocks until all conditions are satisfied. It then initialises the port to */
1448/* the default characteristics and returns. */
1449/******************************************************************************/
1450static int
1451ip2_open( PTTY tty, struct file *pFile )
1452{
1453 wait_queue_t wait;
1454 int rc = 0;
1455 int do_clocal = 0;
1456 i2ChanStrPtr pCh = DevTable[tty->index];
1457
1458 ip2trace (tty->index, ITRC_OPEN, ITRC_ENTER, 0 );
1459
1460 if ( pCh == NULL ) {
1461 return -ENODEV;
1462 }
1463 /* Setup pointer links in device and tty structures */
1464 pCh->pTTY = tty;
1465 tty->driver_data = pCh;
1466
1467#ifdef IP2DEBUG_OPEN
1468 printk(KERN_DEBUG \
1469 "IP2:open(tty=%p,pFile=%p):dev=%s,ch=%d,idx=%d\n",
1470 tty, pFile, tty->name, pCh->infl.hd.i2sChannel, pCh->port_index);
1471 open_sanity_check ( pCh, pCh->pMyBord );
1472#endif
1473
1474 i2QueueCommands(PTYPE_INLINE, pCh, 100, 3, CMD_DTRUP,CMD_RTSUP,CMD_DCD_REP);
1475 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1476 serviceOutgoingFifo( pCh->pMyBord );
1477
1478 /* Block here until the port is ready (per serial and istallion) */
1479 /*
1480 * 1. If the port is in the middle of closing wait for the completion
1481 * and then return the appropriate error.
1482 */
1483 init_waitqueue_entry(&wait, current);
1484 add_wait_queue(&pCh->close_wait, &wait);
1485 set_current_state( TASK_INTERRUPTIBLE );
1486
1487 if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
1488 if ( pCh->flags & ASYNC_CLOSING ) {
Arnd Bergmanne142a312010-06-01 22:53:10 +02001489 tty_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 schedule();
Arnd Bergmanne142a312010-06-01 22:53:10 +02001491 tty_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 }
1493 if ( tty_hung_up_p(pFile) ) {
1494 set_current_state( TASK_RUNNING );
1495 remove_wait_queue(&pCh->close_wait, &wait);
1496 return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
1497 }
1498 }
1499 set_current_state( TASK_RUNNING );
1500 remove_wait_queue(&pCh->close_wait, &wait);
1501
1502 /*
1503 * 3. Handle a non-blocking open of a normal port.
1504 */
1505 if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
1506 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1507 goto noblock;
1508 }
1509 /*
1510 * 4. Now loop waiting for the port to be free and carrier present
1511 * (if required).
1512 */
1513 if ( tty->termios->c_cflag & CLOCAL )
1514 do_clocal = 1;
1515
1516#ifdef IP2DEBUG_OPEN
1517 printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
1518#endif
1519
1520 ++pCh->wopen;
1521
1522 init_waitqueue_entry(&wait, current);
1523 add_wait_queue(&pCh->open_wait, &wait);
1524
1525 for(;;) {
1526 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1527 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1528 set_current_state( TASK_INTERRUPTIBLE );
1529 serviceOutgoingFifo( pCh->pMyBord );
1530 if ( tty_hung_up_p(pFile) ) {
1531 set_current_state( TASK_RUNNING );
1532 remove_wait_queue(&pCh->open_wait, &wait);
1533 return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
1534 }
1535 if (!(pCh->flags & ASYNC_CLOSING) &&
1536 (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
1537 rc = 0;
1538 break;
1539 }
1540
1541#ifdef IP2DEBUG_OPEN
1542 printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
1543 (pCh->flags & ASYNC_CLOSING)?"True":"False");
1544 printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
1545#endif
1546 ip2trace (CHANN, ITRC_OPEN, 3, 2, 0,
1547 (pCh->flags & ASYNC_CLOSING) );
1548 /* check for signal */
1549 if (signal_pending(current)) {
1550 rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
1551 break;
1552 }
Arnd Bergmanne142a312010-06-01 22:53:10 +02001553 tty_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 schedule();
Arnd Bergmanne142a312010-06-01 22:53:10 +02001555 tty_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 }
1557 set_current_state( TASK_RUNNING );
1558 remove_wait_queue(&pCh->open_wait, &wait);
1559
1560 --pCh->wopen; //why count?
1561
1562 ip2trace (CHANN, ITRC_OPEN, 4, 0 );
1563
1564 if (rc != 0 ) {
1565 return rc;
1566 }
1567 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1568
1569noblock:
1570
1571 /* first open - Assign termios structure to port */
1572 if ( tty->count == 1 ) {
1573 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1574 /* Now we must send the termios settings to the loadware */
1575 set_params( pCh, NULL );
1576 }
1577
1578 /*
1579 * Now set any i2lib options. These may go away if the i2lib code ends
1580 * up rolled into the mainline.
1581 */
1582 pCh->channelOptions |= CO_NBLOCK_WRITE;
1583
1584#ifdef IP2DEBUG_OPEN
1585 printk (KERN_DEBUG "IP2: open completed\n" );
1586#endif
1587 serviceOutgoingFifo( pCh->pMyBord );
1588
1589 ip2trace (CHANN, ITRC_OPEN, ITRC_RETURN, 0 );
1590
1591 return 0;
1592}
1593
1594/******************************************************************************/
1595/* Function: ip2_close() */
1596/* Parameters: Pointer to tty structure */
1597/* Pointer to file structure */
1598/* Returns: Nothing */
1599/* */
1600/* Description: */
1601/* */
1602/* */
1603/******************************************************************************/
1604static void
1605ip2_close( PTTY tty, struct file *pFile )
1606{
1607 i2ChanStrPtr pCh = tty->driver_data;
1608
1609 if ( !pCh ) {
1610 return;
1611 }
1612
1613 ip2trace (CHANN, ITRC_CLOSE, ITRC_ENTER, 0 );
1614
1615#ifdef IP2DEBUG_OPEN
1616 printk(KERN_DEBUG "IP2:close %s:\n",tty->name);
1617#endif
1618
1619 if ( tty_hung_up_p ( pFile ) ) {
1620
1621 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
1622
1623 return;
1624 }
1625 if ( tty->count > 1 ) { /* not the last close */
1626
1627 ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
1628
1629 return;
1630 }
1631 pCh->flags |= ASYNC_CLOSING; // last close actually
1632
1633 tty->closing = 1;
1634
1635 if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
1636 /*
1637 * Before we drop DTR, make sure the transmitter has completely drained.
1638 * This uses an timeout, after which the close
1639 * completes.
1640 */
1641 ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
1642 }
1643 /*
1644 * At this point we stop accepting input. Here we flush the channel
1645 * input buffer which will allow the board to send up more data. Any
1646 * additional input is tossed at interrupt/poll time.
1647 */
1648 i2InputFlush( pCh );
1649
1650 /* disable DSS reporting */
1651 i2QueueCommands(PTYPE_INLINE, pCh, 100, 4,
1652 CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1653 if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
1654 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
1655 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1656 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1657 }
1658
1659 serviceOutgoingFifo ( pCh->pMyBord );
1660
Alan Coxf34d7a52008-04-30 00:54:13 -07001661 tty_ldisc_flush(tty);
Alan Coxa6fc8192008-04-30 00:54:18 -07001662 tty_driver_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 tty->closing = 0;
1664
1665 pCh->pTTY = NULL;
1666
1667 if (pCh->wopen) {
1668 if (pCh->ClosingDelay) {
1669 msleep_interruptible(jiffies_to_msecs(pCh->ClosingDelay));
1670 }
1671 wake_up_interruptible(&pCh->open_wait);
1672 }
1673
1674 pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
1675 wake_up_interruptible(&pCh->close_wait);
1676
1677#ifdef IP2DEBUG_OPEN
1678 DBG_CNT("ip2_close: after wakeups--");
1679#endif
1680
1681
1682 ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
1683
1684 return;
1685}
1686
1687/******************************************************************************/
1688/* Function: ip2_hangup() */
1689/* Parameters: Pointer to tty structure */
1690/* Returns: Nothing */
1691/* */
1692/* Description: */
1693/* */
1694/* */
1695/******************************************************************************/
1696static void
1697ip2_hangup ( PTTY tty )
1698{
1699 i2ChanStrPtr pCh = tty->driver_data;
1700
1701 if( !pCh ) {
1702 return;
1703 }
1704
1705 ip2trace (CHANN, ITRC_HANGUP, ITRC_ENTER, 0 );
1706
1707 ip2_flush_buffer(tty);
1708
1709 /* disable DSS reporting */
1710
1711 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
1712 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1713 if ( (tty->termios->c_cflag & HUPCL) ) {
1714 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
1715 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1716 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1717 }
1718 i2QueueCommands(PTYPE_INLINE, pCh, 1, 3,
1719 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1720 serviceOutgoingFifo ( pCh->pMyBord );
1721
1722 wake_up_interruptible ( &pCh->delta_msr_wait );
1723
1724 pCh->flags &= ~ASYNC_NORMAL_ACTIVE;
1725 pCh->pTTY = NULL;
1726 wake_up_interruptible ( &pCh->open_wait );
1727
1728 ip2trace (CHANN, ITRC_HANGUP, ITRC_RETURN, 0 );
1729}
1730
1731/******************************************************************************/
1732/******************************************************************************/
1733/* Device Output Section */
1734/******************************************************************************/
1735/******************************************************************************/
1736
1737/******************************************************************************/
1738/* Function: ip2_write() */
1739/* Parameters: Pointer to tty structure */
1740/* Flag denoting data is in user (1) or kernel (0) space */
1741/* Pointer to data */
1742/* Number of bytes to write */
1743/* Returns: Number of bytes actually written */
1744/* */
1745/* Description: (MANDATORY) */
1746/* */
1747/* */
1748/******************************************************************************/
1749static int
Alan Coxd9e39532006-01-09 20:54:20 -08001750ip2_write( PTTY tty, const unsigned char *pData, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751{
1752 i2ChanStrPtr pCh = tty->driver_data;
1753 int bytesSent = 0;
1754 unsigned long flags;
1755
1756 ip2trace (CHANN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
1757
1758 /* Flush out any buffered data left over from ip2_putchar() calls. */
1759 ip2_flush_chars( tty );
1760
1761 /* This is the actual move bit. Make sure it does what we need!!!!! */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001762 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Al Virof061c582006-10-11 17:45:47 +01001763 bytesSent = i2Output( pCh, pData, count);
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001764 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
1766 ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
1767
1768 return bytesSent > 0 ? bytesSent : 0;
1769}
1770
1771/******************************************************************************/
1772/* Function: ip2_putchar() */
1773/* Parameters: Pointer to tty structure */
1774/* Character to write */
1775/* Returns: Nothing */
1776/* */
1777/* Description: */
1778/* */
1779/* */
1780/******************************************************************************/
Alan Coxf34d7a52008-04-30 00:54:13 -07001781static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782ip2_putchar( PTTY tty, unsigned char ch )
1783{
1784 i2ChanStrPtr pCh = tty->driver_data;
1785 unsigned long flags;
1786
1787// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
1788
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001789 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
1791 if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001792 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 ip2_flush_chars( tty );
1794 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001795 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Alan Coxf34d7a52008-04-30 00:54:13 -07001796 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
1798// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
1799}
1800
1801/******************************************************************************/
1802/* Function: ip2_flush_chars() */
1803/* Parameters: Pointer to tty structure */
1804/* Returns: Nothing */
1805/* */
1806/* Description: */
1807/* */
1808/******************************************************************************/
1809static void
1810ip2_flush_chars( PTTY tty )
1811{
1812 int strip;
1813 i2ChanStrPtr pCh = tty->driver_data;
1814 unsigned long flags;
1815
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001816 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 if ( pCh->Pbuf_stuff ) {
1818
1819// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
1820
1821 //
1822 // We may need to restart i2Output if it does not fullfill this request
1823 //
Al Virof061c582006-10-11 17:45:47 +01001824 strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 if ( strip != pCh->Pbuf_stuff ) {
1826 memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
1827 }
1828 pCh->Pbuf_stuff -= strip;
1829 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001830 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831}
1832
1833/******************************************************************************/
1834/* Function: ip2_write_room() */
1835/* Parameters: Pointer to tty structure */
1836/* Returns: Number of bytes that the driver can accept */
1837/* */
1838/* Description: */
1839/* */
1840/******************************************************************************/
1841static int
1842ip2_write_room ( PTTY tty )
1843{
1844 int bytesFree;
1845 i2ChanStrPtr pCh = tty->driver_data;
1846 unsigned long flags;
1847
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001848 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001850 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
1852 ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
1853
1854 return ((bytesFree > 0) ? bytesFree : 0);
1855}
1856
1857/******************************************************************************/
1858/* Function: ip2_chars_in_buf() */
1859/* Parameters: Pointer to tty structure */
1860/* Returns: Number of bytes queued for transmission */
1861/* */
1862/* Description: */
1863/* */
1864/* */
1865/******************************************************************************/
1866static int
1867ip2_chars_in_buf ( PTTY tty )
1868{
1869 i2ChanStrPtr pCh = tty->driver_data;
1870 int rc;
1871 unsigned long flags;
1872
1873 ip2trace (CHANN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
1874
1875#ifdef IP2DEBUG_WRITE
1876 printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
1877 pCh->Obuf_char_count + pCh->Pbuf_stuff,
1878 pCh->Obuf_char_count, pCh->Pbuf_stuff );
1879#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001880 read_lock_irqsave(&pCh->Obuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 rc = pCh->Obuf_char_count;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001882 read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
1883 read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 rc += pCh->Pbuf_stuff;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001885 read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 return rc;
1887}
1888
1889/******************************************************************************/
1890/* Function: ip2_flush_buffer() */
1891/* Parameters: Pointer to tty structure */
1892/* Returns: Nothing */
1893/* */
1894/* Description: */
1895/* */
1896/* */
1897/******************************************************************************/
1898static void
1899ip2_flush_buffer( PTTY tty )
1900{
1901 i2ChanStrPtr pCh = tty->driver_data;
1902 unsigned long flags;
1903
1904 ip2trace (CHANN, ITRC_FLUSH, ITRC_ENTER, 0 );
1905
1906#ifdef IP2DEBUG_WRITE
1907 printk (KERN_DEBUG "IP2: flush buffer\n" );
1908#endif
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001909 write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 pCh->Pbuf_stuff = 0;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001911 write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 i2FlushOutput( pCh );
1913 ip2_owake(tty);
1914
1915 ip2trace (CHANN, ITRC_FLUSH, ITRC_RETURN, 0 );
1916
1917}
1918
1919/******************************************************************************/
1920/* Function: ip2_wait_until_sent() */
1921/* Parameters: Pointer to tty structure */
1922/* Timeout for wait. */
1923/* Returns: Nothing */
1924/* */
1925/* Description: */
1926/* This function is used in place of the normal tty_wait_until_sent, which */
1927/* only waits for the driver buffers to be empty (or rather, those buffers */
1928/* reported by chars_in_buffer) which doesn't work for IP2 due to the */
1929/* indeterminate number of bytes buffered on the board. */
1930/******************************************************************************/
1931static void
1932ip2_wait_until_sent ( PTTY tty, int timeout )
1933{
1934 int i = jiffies;
1935 i2ChanStrPtr pCh = tty->driver_data;
1936
1937 tty_wait_until_sent(tty, timeout );
1938 if ( (i = timeout - (jiffies -i)) > 0)
1939 i2DrainOutput( pCh, i );
1940}
1941
1942/******************************************************************************/
1943/******************************************************************************/
1944/* Device Input Section */
1945/******************************************************************************/
1946/******************************************************************************/
1947
1948/******************************************************************************/
1949/* Function: ip2_throttle() */
1950/* Parameters: Pointer to tty structure */
1951/* Returns: Nothing */
1952/* */
1953/* Description: */
1954/* */
1955/* */
1956/******************************************************************************/
1957static void
1958ip2_throttle ( PTTY tty )
1959{
1960 i2ChanStrPtr pCh = tty->driver_data;
1961
1962#ifdef IP2DEBUG_READ
1963 printk (KERN_DEBUG "IP2: throttle\n" );
1964#endif
1965 /*
1966 * Signal the poll/interrupt handlers not to forward incoming data to
1967 * the line discipline. This will cause the buffers to fill up in the
1968 * library and thus cause the library routines to send the flow control
1969 * stuff.
1970 */
1971 pCh->throttled = 1;
1972}
1973
1974/******************************************************************************/
1975/* Function: ip2_unthrottle() */
1976/* Parameters: Pointer to tty structure */
1977/* Returns: Nothing */
1978/* */
1979/* Description: */
1980/* */
1981/* */
1982/******************************************************************************/
1983static void
1984ip2_unthrottle ( PTTY tty )
1985{
1986 i2ChanStrPtr pCh = tty->driver_data;
1987 unsigned long flags;
1988
1989#ifdef IP2DEBUG_READ
1990 printk (KERN_DEBUG "IP2: unthrottle\n" );
1991#endif
1992
1993 /* Pass incoming data up to the line discipline again. */
1994 pCh->throttled = 0;
1995 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
1996 serviceOutgoingFifo( pCh->pMyBord );
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001997 read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
Jiri Slabycf1c63c2008-04-30 00:53:54 -07001999 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000#ifdef IP2DEBUG_READ
2001 printk (KERN_DEBUG "i2Input called from unthrottle\n" );
2002#endif
2003 i2Input( pCh );
2004 } else
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002005 read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006}
2007
2008static void
2009ip2_start ( PTTY tty )
2010{
2011 i2ChanStrPtr pCh = DevTable[tty->index];
2012
2013 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
2014 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
2015 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
2016#ifdef IP2DEBUG_WRITE
2017 printk (KERN_DEBUG "IP2: start tx\n" );
2018#endif
2019}
2020
2021static void
2022ip2_stop ( PTTY tty )
2023{
2024 i2ChanStrPtr pCh = DevTable[tty->index];
2025
2026 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
2027#ifdef IP2DEBUG_WRITE
2028 printk (KERN_DEBUG "IP2: stop tx\n" );
2029#endif
2030}
2031
2032/******************************************************************************/
2033/* Device Ioctl Section */
2034/******************************************************************************/
2035
2036static int ip2_tiocmget(struct tty_struct *tty, struct file *file)
2037{
2038 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002039#ifdef ENABLE_DSSNOW
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 wait_queue_t wait;
Alan Coxd9e39532006-01-09 20:54:20 -08002041#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042
2043 if (pCh == NULL)
2044 return -ENODEV;
2045
2046/*
2047 FIXME - the following code is causing a NULL pointer dereference in
2048 2.3.51 in an interrupt handler. It's suppose to prompt the board
2049 to return the DSS signal status immediately. Why doesn't it do
2050 the same thing in 2.2.14?
2051*/
2052
2053/* This thing is still busted in the 1.2.12 driver on 2.4.x
2054 and even hoses the serial console so the oops can be trapped.
2055 /\/\|=mhw=|\/\/ */
2056
2057#ifdef ENABLE_DSSNOW
2058 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DSS_NOW);
2059
2060 init_waitqueue_entry(&wait, current);
2061 add_wait_queue(&pCh->dss_now_wait, &wait);
2062 set_current_state( TASK_INTERRUPTIBLE );
2063
2064 serviceOutgoingFifo( pCh->pMyBord );
2065
2066 schedule();
2067
2068 set_current_state( TASK_RUNNING );
2069 remove_wait_queue(&pCh->dss_now_wait, &wait);
2070
2071 if (signal_pending(current)) {
2072 return -EINTR;
2073 }
2074#endif
2075 return ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
2076 | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
2077 | ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0)
2078 | ((pCh->dataSetIn & I2_RI) ? TIOCM_RNG : 0)
2079 | ((pCh->dataSetIn & I2_DSR) ? TIOCM_DSR : 0)
2080 | ((pCh->dataSetIn & I2_CTS) ? TIOCM_CTS : 0);
2081}
2082
2083static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
2084 unsigned int set, unsigned int clear)
2085{
2086 i2ChanStrPtr pCh = DevTable[tty->index];
2087
2088 if (pCh == NULL)
2089 return -ENODEV;
2090
2091 if (set & TIOCM_RTS) {
2092 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2093 pCh->dataSetOut |= I2_RTS;
2094 }
2095 if (set & TIOCM_DTR) {
2096 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2097 pCh->dataSetOut |= I2_DTR;
2098 }
2099
2100 if (clear & TIOCM_RTS) {
2101 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2102 pCh->dataSetOut &= ~I2_RTS;
2103 }
2104 if (clear & TIOCM_DTR) {
2105 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2106 pCh->dataSetOut &= ~I2_DTR;
2107 }
2108 serviceOutgoingFifo( pCh->pMyBord );
2109 return 0;
2110}
2111
2112/******************************************************************************/
2113/* Function: ip2_ioctl() */
2114/* Parameters: Pointer to tty structure */
2115/* Pointer to file structure */
2116/* Command */
2117/* Argument */
2118/* Returns: Success or failure */
2119/* */
2120/* Description: */
2121/* */
2122/* */
2123/******************************************************************************/
2124static int
2125ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
2126{
2127 wait_queue_t wait;
2128 i2ChanStrPtr pCh = DevTable[tty->index];
Alan Coxd9e39532006-01-09 20:54:20 -08002129 i2eBordStrPtr pB;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 struct async_icount cprev, cnow; /* kernel counter temps */
2131 struct serial_icounter_struct __user *p_cuser;
2132 int rc = 0;
2133 unsigned long flags;
2134 void __user *argp = (void __user *)arg;
2135
Alan Coxd9e39532006-01-09 20:54:20 -08002136 if ( pCh == NULL )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 return -ENODEV;
Alan Coxd9e39532006-01-09 20:54:20 -08002138
2139 pB = pCh->pMyBord;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
2141 ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
2142
2143#ifdef IP2DEBUG_IOCTL
2144 printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
2145#endif
2146
2147 switch(cmd) {
2148 case TIOCGSERIAL:
2149
2150 ip2trace (CHANN, ITRC_IOCTL, 2, 1, rc );
2151
2152 rc = get_serial_info(pCh, argp);
2153 if (rc)
2154 return rc;
2155 break;
2156
2157 case TIOCSSERIAL:
2158
2159 ip2trace (CHANN, ITRC_IOCTL, 3, 1, rc );
2160
2161 rc = set_serial_info(pCh, argp);
2162 if (rc)
2163 return rc;
2164 break;
2165
2166 case TCXONC:
2167 rc = tty_check_change(tty);
2168 if (rc)
2169 return rc;
2170 switch (arg) {
2171 case TCOOFF:
2172 //return -ENOIOCTLCMD;
2173 break;
2174 case TCOON:
2175 //return -ENOIOCTLCMD;
2176 break;
2177 case TCIOFF:
2178 if (STOP_CHAR(tty) != __DISABLED_CHAR) {
2179 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2180 CMD_XMIT_NOW(STOP_CHAR(tty)));
2181 }
2182 break;
2183 case TCION:
2184 if (START_CHAR(tty) != __DISABLED_CHAR) {
2185 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2186 CMD_XMIT_NOW(START_CHAR(tty)));
2187 }
2188 break;
2189 default:
2190 return -EINVAL;
2191 }
2192 return 0;
2193
2194 case TCSBRK: /* SVID version: non-zero arg --> no break */
2195 rc = tty_check_change(tty);
2196
2197 ip2trace (CHANN, ITRC_IOCTL, 4, 1, rc );
2198
2199 if (!rc) {
2200 ip2_wait_until_sent(tty,0);
2201 if (!arg) {
2202 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
2203 serviceOutgoingFifo( pCh->pMyBord );
2204 }
2205 }
2206 break;
2207
2208 case TCSBRKP: /* support for POSIX tcsendbreak() */
2209 rc = tty_check_change(tty);
2210
2211 ip2trace (CHANN, ITRC_IOCTL, 5, 1, rc );
2212
2213 if (!rc) {
2214 ip2_wait_until_sent(tty,0);
2215 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2216 CMD_SEND_BRK(arg ? arg*100 : 250));
2217 serviceOutgoingFifo ( pCh->pMyBord );
2218 }
2219 break;
2220
2221 case TIOCGSOFTCAR:
2222
2223 ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
2224
2225 rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
2226 if (rc)
2227 return rc;
2228 break;
2229
2230 case TIOCSSOFTCAR:
2231
2232 ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
2233
2234 rc = get_user(arg,(unsigned long __user *) argp);
2235 if (rc)
2236 return rc;
2237 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
2238 | (arg ? CLOCAL : 0));
2239
2240 break;
2241
2242 /*
2243 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
2244 * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
2245 * for masking). Caller should use TIOCGICOUNT to see which one it was
2246 */
2247 case TIOCMIWAIT:
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002248 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 cprev = pCh->icount; /* note the counters on entry */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002250 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
2252 CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
2253 init_waitqueue_entry(&wait, current);
2254 add_wait_queue(&pCh->delta_msr_wait, &wait);
2255 set_current_state( TASK_INTERRUPTIBLE );
2256
2257 serviceOutgoingFifo( pCh->pMyBord );
2258 for(;;) {
2259 ip2trace (CHANN, ITRC_IOCTL, 10, 0 );
2260
2261 schedule();
2262
2263 ip2trace (CHANN, ITRC_IOCTL, 11, 0 );
2264
2265 /* see if a signal did it */
2266 if (signal_pending(current)) {
2267 rc = -ERESTARTSYS;
2268 break;
2269 }
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002270 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 cnow = pCh->icount; /* atomic copy */
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002272 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2274 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2275 rc = -EIO; /* no change => rc */
2276 break;
2277 }
2278 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2279 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2280 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2281 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2282 rc = 0;
2283 break;
2284 }
2285 cprev = cnow;
2286 }
2287 set_current_state( TASK_RUNNING );
2288 remove_wait_queue(&pCh->delta_msr_wait, &wait);
2289
2290 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 3,
2291 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
2292 if ( ! (pCh->flags & ASYNC_CHECK_CD)) {
2293 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DCD_NREP);
2294 }
2295 serviceOutgoingFifo( pCh->pMyBord );
2296 return rc;
2297 break;
2298
2299 /*
2300 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2301 * Return: write counters to the user passed counter struct
2302 * NB: both 1->0 and 0->1 transitions are counted except for RI where
2303 * only 0->1 is counted. The controller is quite capable of counting
2304 * both, but this done to preserve compatibility with the standard
2305 * serial driver.
2306 */
2307 case TIOCGICOUNT:
2308 ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
2309
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002310 write_lock_irqsave(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 cnow = pCh->icount;
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002312 write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 p_cuser = argp;
2314 rc = put_user(cnow.cts, &p_cuser->cts);
2315 rc = put_user(cnow.dsr, &p_cuser->dsr);
2316 rc = put_user(cnow.rng, &p_cuser->rng);
2317 rc = put_user(cnow.dcd, &p_cuser->dcd);
2318 rc = put_user(cnow.rx, &p_cuser->rx);
2319 rc = put_user(cnow.tx, &p_cuser->tx);
2320 rc = put_user(cnow.frame, &p_cuser->frame);
2321 rc = put_user(cnow.overrun, &p_cuser->overrun);
2322 rc = put_user(cnow.parity, &p_cuser->parity);
2323 rc = put_user(cnow.brk, &p_cuser->brk);
2324 rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
2325 break;
2326
2327 /*
2328 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
2329 * will be passed to the line discipline for it to handle.
2330 */
2331 case TIOCSERCONFIG:
2332 case TIOCSERGWILD:
2333 case TIOCSERGETLSR:
2334 case TIOCSERSWILD:
2335 case TIOCSERGSTRUCT:
2336 case TIOCSERGETMULTI:
2337 case TIOCSERSETMULTI:
2338
2339 default:
2340 ip2trace (CHANN, ITRC_IOCTL, 12, 0 );
2341
2342 rc = -ENOIOCTLCMD;
2343 break;
2344 }
2345
2346 ip2trace (CHANN, ITRC_IOCTL, ITRC_RETURN, 0 );
2347
2348 return rc;
2349}
2350
2351/******************************************************************************/
2352/* Function: GetSerialInfo() */
2353/* Parameters: Pointer to channel structure */
2354/* Pointer to old termios structure */
2355/* Returns: Nothing */
2356/* */
2357/* Description: */
2358/* This is to support the setserial command, and requires processing of the */
2359/* standard Linux serial structure. */
2360/******************************************************************************/
2361static int
2362get_serial_info ( i2ChanStrPtr pCh, struct serial_struct __user *retinfo )
2363{
2364 struct serial_struct tmp;
2365
2366 memset ( &tmp, 0, sizeof(tmp) );
2367 tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
2368 if (BID_HAS_654(tmp.type)) {
2369 tmp.type = PORT_16650;
2370 } else {
2371 tmp.type = PORT_CIRRUS;
2372 }
2373 tmp.line = pCh->port_index;
2374 tmp.port = pCh->pMyBord->i2eBase;
2375 tmp.irq = ip2config.irq[pCh->port_index/64];
2376 tmp.flags = pCh->flags;
2377 tmp.baud_base = pCh->BaudBase;
2378 tmp.close_delay = pCh->ClosingDelay;
2379 tmp.closing_wait = pCh->ClosingWaitTime;
2380 tmp.custom_divisor = pCh->BaudDivisor;
2381 return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
2382}
2383
2384/******************************************************************************/
2385/* Function: SetSerialInfo() */
2386/* Parameters: Pointer to channel structure */
2387/* Pointer to old termios structure */
2388/* Returns: Nothing */
2389/* */
2390/* Description: */
2391/* This function provides support for setserial, which uses the TIOCSSERIAL */
2392/* ioctl. Not all setserial parameters are relevant. If the user attempts to */
2393/* change the IRQ, address or type of the port the ioctl fails. */
2394/******************************************************************************/
2395static int
2396set_serial_info( i2ChanStrPtr pCh, struct serial_struct __user *new_info )
2397{
2398 struct serial_struct ns;
2399 int old_flags, old_baud_divisor;
2400
2401 if (copy_from_user(&ns, new_info, sizeof (ns)))
2402 return -EFAULT;
2403
2404 /*
2405 * We don't allow setserial to change IRQ, board address, type or baud
2406 * base. Also line nunber as such is meaningless but we use it for our
2407 * array index so it is fixed also.
2408 */
2409 if ( (ns.irq != ip2config.irq[pCh->port_index])
2410 || ((int) ns.port != ((int) (pCh->pMyBord->i2eBase)))
2411 || (ns.baud_base != pCh->BaudBase)
2412 || (ns.line != pCh->port_index) ) {
2413 return -EINVAL;
2414 }
2415
2416 old_flags = pCh->flags;
2417 old_baud_divisor = pCh->BaudDivisor;
2418
2419 if ( !capable(CAP_SYS_ADMIN) ) {
2420 if ( ( ns.close_delay != pCh->ClosingDelay ) ||
2421 ( (ns.flags & ~ASYNC_USR_MASK) !=
2422 (pCh->flags & ~ASYNC_USR_MASK) ) ) {
2423 return -EPERM;
2424 }
2425
2426 pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
2427 (ns.flags & ASYNC_USR_MASK);
2428 pCh->BaudDivisor = ns.custom_divisor;
2429 } else {
2430 pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
2431 (ns.flags & ASYNC_FLAGS);
2432 pCh->BaudDivisor = ns.custom_divisor;
2433 pCh->ClosingDelay = ns.close_delay * HZ/100;
2434 pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
2435 }
2436
2437 if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
2438 || (old_baud_divisor != pCh->BaudDivisor) ) {
2439 // Invalidate speed and reset parameters
2440 set_params( pCh, NULL );
2441 }
2442
2443 return 0;
2444}
2445
2446/******************************************************************************/
2447/* Function: ip2_set_termios() */
2448/* Parameters: Pointer to tty structure */
2449/* Pointer to old termios structure */
2450/* Returns: Nothing */
2451/* */
2452/* Description: */
2453/* */
2454/* */
2455/******************************************************************************/
2456static void
Alan Cox606d0992006-12-08 02:38:45 -08002457ip2_set_termios( PTTY tty, struct ktermios *old_termios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458{
2459 i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
2460
2461#ifdef IP2DEBUG_IOCTL
2462 printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
2463#endif
2464
2465 set_params( pCh, old_termios );
2466}
2467
2468/******************************************************************************/
2469/* Function: ip2_set_line_discipline() */
2470/* Parameters: Pointer to tty structure */
2471/* Returns: Nothing */
2472/* */
2473/* Description: Does nothing */
2474/* */
2475/* */
2476/******************************************************************************/
2477static void
2478ip2_set_line_discipline ( PTTY tty )
2479{
2480#ifdef IP2DEBUG_IOCTL
2481 printk (KERN_DEBUG "IP2: set line discipline\n" );
2482#endif
2483
2484 ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
2485
2486}
2487
2488/******************************************************************************/
2489/* Function: SetLine Characteristics() */
2490/* Parameters: Pointer to channel structure */
2491/* Returns: Nothing */
2492/* */
2493/* Description: */
2494/* This routine is called to update the channel structure with the new line */
2495/* characteristics, and send the appropriate commands to the board when they */
2496/* change. */
2497/******************************************************************************/
2498static void
Alan Cox606d0992006-12-08 02:38:45 -08002499set_params( i2ChanStrPtr pCh, struct ktermios *o_tios )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500{
2501 tcflag_t cflag, iflag, lflag;
2502 char stop_char, start_char;
Alan Cox606d0992006-12-08 02:38:45 -08002503 struct ktermios dummy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
2505 lflag = pCh->pTTY->termios->c_lflag;
2506 cflag = pCh->pTTY->termios->c_cflag;
2507 iflag = pCh->pTTY->termios->c_iflag;
2508
2509 if (o_tios == NULL) {
2510 dummy.c_lflag = ~lflag;
2511 dummy.c_cflag = ~cflag;
2512 dummy.c_iflag = ~iflag;
2513 o_tios = &dummy;
2514 }
2515
2516 {
2517 switch ( cflag & CBAUD ) {
2518 case B0:
2519 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
2520 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
2521 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
2522 pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
2523 goto service_it;
2524 break;
2525 case B38400:
2526 /*
2527 * This is the speed that is overloaded with all the other high
2528 * speeds, depending upon the flag settings.
2529 */
2530 if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
2531 pCh->speed = CBR_57600;
2532 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
2533 pCh->speed = CBR_115200;
2534 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
2535 pCh->speed = CBR_C1;
2536 } else {
2537 pCh->speed = CBR_38400;
2538 }
2539 break;
2540 case B50: pCh->speed = CBR_50; break;
2541 case B75: pCh->speed = CBR_75; break;
2542 case B110: pCh->speed = CBR_110; break;
2543 case B134: pCh->speed = CBR_134; break;
2544 case B150: pCh->speed = CBR_150; break;
2545 case B200: pCh->speed = CBR_200; break;
2546 case B300: pCh->speed = CBR_300; break;
2547 case B600: pCh->speed = CBR_600; break;
2548 case B1200: pCh->speed = CBR_1200; break;
2549 case B1800: pCh->speed = CBR_1800; break;
2550 case B2400: pCh->speed = CBR_2400; break;
2551 case B4800: pCh->speed = CBR_4800; break;
2552 case B9600: pCh->speed = CBR_9600; break;
2553 case B19200: pCh->speed = CBR_19200; break;
2554 case B57600: pCh->speed = CBR_57600; break;
2555 case B115200: pCh->speed = CBR_115200; break;
2556 case B153600: pCh->speed = CBR_153600; break;
2557 case B230400: pCh->speed = CBR_230400; break;
2558 case B307200: pCh->speed = CBR_307200; break;
2559 case B460800: pCh->speed = CBR_460800; break;
2560 case B921600: pCh->speed = CBR_921600; break;
2561 default: pCh->speed = CBR_9600; break;
2562 }
2563 if ( pCh->speed == CBR_C1 ) {
2564 // Process the custom speed parameters.
2565 int bps = pCh->BaudBase / pCh->BaudDivisor;
2566 if ( bps == 921600 ) {
2567 pCh->speed = CBR_921600;
2568 } else {
2569 bps = bps/10;
2570 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
2571 }
2572 }
2573 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
2574
2575 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
2576 pCh->dataSetOut |= (I2_DTR | I2_RTS);
2577 }
2578 if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag))
2579 {
2580 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2581 CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
2582 }
2583 if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag))
2584 {
2585 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2586 CMD_SETPAR(
2587 (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
2588 )
2589 );
2590 }
2591 /* byte size and parity */
2592 if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag))
2593 {
2594 int datasize;
2595 switch ( cflag & CSIZE ) {
2596 case CS5: datasize = CSZ_5; break;
2597 case CS6: datasize = CSZ_6; break;
2598 case CS7: datasize = CSZ_7; break;
2599 case CS8: datasize = CSZ_8; break;
2600 default: datasize = CSZ_5; break; /* as per serial.c */
2601 }
2602 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
2603 }
2604 /* Process CTS flow control flag setting */
2605 if ( (cflag & CRTSCTS) ) {
2606 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2607 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
2608 } else {
2609 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2610 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
2611 }
2612 //
2613 // Process XON/XOFF flow control flags settings
2614 //
2615 stop_char = STOP_CHAR(pCh->pTTY);
2616 start_char = START_CHAR(pCh->pTTY);
2617
2618 //////////// can't be \000
2619 if (stop_char == __DISABLED_CHAR )
2620 {
2621 stop_char = ~__DISABLED_CHAR;
2622 }
2623 if (start_char == __DISABLED_CHAR )
2624 {
2625 start_char = ~__DISABLED_CHAR;
2626 }
2627 /////////////////////////////////
2628
2629 if ( o_tios->c_cc[VSTART] != start_char )
2630 {
2631 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
2632 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
2633 }
2634 if ( o_tios->c_cc[VSTOP] != stop_char )
2635 {
2636 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
2637 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
2638 }
2639 if (stop_char == __DISABLED_CHAR )
2640 {
2641 stop_char = ~__DISABLED_CHAR; //TEST123
2642 goto no_xoff;
2643 }
2644 if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF)))
2645 {
2646 if ( iflag & IXOFF ) { // Enable XOFF output flow control
2647 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
2648 } else { // Disable XOFF output flow control
2649no_xoff:
2650 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
2651 }
2652 }
2653 if (start_char == __DISABLED_CHAR )
2654 {
2655 goto no_xon;
2656 }
2657 if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY)))
2658 {
2659 if ( iflag & IXON ) {
2660 if ( iflag & IXANY ) { // Enable XON/XANY output flow control
2661 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
2662 } else { // Enable XON output flow control
2663 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
2664 }
2665 } else { // Disable XON output flow control
2666no_xon:
2667 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
2668 }
2669 }
2670 if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) )
2671 {
2672 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2673 CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
2674 }
2675 if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) )
2676 {
2677 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2678 CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
2679 }
2680
2681 if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR))
2682 ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) )
2683 {
2684 char brkrpt = 0;
2685 char parrpt = 0;
2686
2687 if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
2688 /* Ignore breaks altogether */
2689 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
2690 } else {
2691 if ( iflag & BRKINT ) {
2692 if ( iflag & PARMRK ) {
2693 brkrpt = 0x0a; // exception an inline triple
2694 } else {
2695 brkrpt = 0x1a; // exception and NULL
2696 }
2697 brkrpt |= 0x04; // flush input
2698 } else {
2699 if ( iflag & PARMRK ) {
2700 brkrpt = 0x0b; //POSIX triple \0377 \0 \0
2701 } else {
2702 brkrpt = 0x01; // Null only
2703 }
2704 }
2705 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
2706 }
2707
2708 if (iflag & IGNPAR) {
2709 parrpt = 0x20;
2710 /* would be 2 for not cirrus bug */
2711 /* would be 0x20 cept for cirrus bug */
2712 } else {
2713 if ( iflag & PARMRK ) {
2714 /*
2715 * Replace error characters with 3-byte sequence (\0377,\0,char)
2716 */
2717 parrpt = 0x04 ;
2718 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
2719 } else {
2720 parrpt = 0x03;
2721 }
2722 }
2723 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
2724 }
2725 if (cflag & CLOCAL) {
2726 // Status reporting fails for DCD if this is off
2727 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
2728 pCh->flags &= ~ASYNC_CHECK_CD;
2729 } else {
2730 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
2731 pCh->flags |= ASYNC_CHECK_CD;
2732 }
2733
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734service_it:
2735 i2DrainOutput( pCh, 100 );
2736}
2737
2738/******************************************************************************/
2739/* IPL Device Section */
2740/******************************************************************************/
2741
2742/******************************************************************************/
2743/* Function: ip2_ipl_read() */
2744/* Parameters: Pointer to device inode */
2745/* Pointer to file structure */
2746/* Pointer to data */
2747/* Number of bytes to read */
2748/* Returns: Success or failure */
2749/* */
2750/* Description: Ugly */
2751/* */
2752/* */
2753/******************************************************************************/
2754
2755static
2756ssize_t
2757ip2_ipl_read(struct file *pFile, char __user *pData, size_t count, loff_t *off )
2758{
Josef Sipeka7113a92006-12-08 02:36:55 -08002759 unsigned int minor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 int rc = 0;
2761
2762#ifdef IP2DEBUG_IPL
2763 printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
2764#endif
2765
2766 switch( minor ) {
2767 case 0: // IPL device
2768 rc = -EINVAL;
2769 break;
2770 case 1: // Status dump
2771 rc = -EINVAL;
2772 break;
2773 case 2: // Ping device
2774 rc = -EINVAL;
2775 break;
2776 case 3: // Trace device
2777 rc = DumpTraceBuffer ( pData, count );
2778 break;
2779 case 4: // Trace device
2780 rc = DumpFifoBuffer ( pData, count );
2781 break;
2782 default:
2783 rc = -ENODEV;
2784 break;
2785 }
2786 return rc;
2787}
2788
2789static int
2790DumpFifoBuffer ( char __user *pData, int count )
2791{
2792#ifdef DEBUG_FIFO
2793 int rc;
2794 rc = copy_to_user(pData, DBGBuf, count);
2795
2796 printk(KERN_DEBUG "Last index %d\n", I );
2797
2798 return count;
2799#endif /* DEBUG_FIFO */
2800 return 0;
2801}
2802
2803static int
2804DumpTraceBuffer ( char __user *pData, int count )
2805{
2806#ifdef IP2DEBUG_TRACE
2807 int rc;
2808 int dumpcount;
2809 int chunk;
2810 int *pIndex = (int __user *)pData;
2811
2812 if ( count < (sizeof(int) * 6) ) {
2813 return -EIO;
2814 }
2815 rc = put_user(tracewrap, pIndex );
2816 rc = put_user(TRACEMAX, ++pIndex );
2817 rc = put_user(tracestrip, ++pIndex );
2818 rc = put_user(tracestuff, ++pIndex );
2819 pData += sizeof(int) * 6;
2820 count -= sizeof(int) * 6;
2821
2822 dumpcount = tracestuff - tracestrip;
2823 if ( dumpcount < 0 ) {
2824 dumpcount += TRACEMAX;
2825 }
2826 if ( dumpcount > count ) {
2827 dumpcount = count;
2828 }
2829 chunk = TRACEMAX - tracestrip;
2830 if ( dumpcount > chunk ) {
2831 rc = copy_to_user(pData, &tracebuf[tracestrip],
2832 chunk * sizeof(tracebuf[0]) );
2833 pData += chunk * sizeof(tracebuf[0]);
2834 tracestrip = 0;
2835 chunk = dumpcount - chunk;
2836 } else {
2837 chunk = dumpcount;
2838 }
2839 rc = copy_to_user(pData, &tracebuf[tracestrip],
2840 chunk * sizeof(tracebuf[0]) );
2841 tracestrip += chunk;
2842 tracewrap = 0;
2843
2844 rc = put_user(tracestrip, ++pIndex );
2845 rc = put_user(tracestuff, ++pIndex );
2846
2847 return dumpcount;
2848#else
2849 return 0;
2850#endif
2851}
2852
2853/******************************************************************************/
2854/* Function: ip2_ipl_write() */
2855/* Parameters: */
2856/* Pointer to file structure */
2857/* Pointer to data */
2858/* Number of bytes to write */
2859/* Returns: Success or failure */
2860/* */
2861/* Description: */
2862/* */
2863/* */
2864/******************************************************************************/
2865static ssize_t
2866ip2_ipl_write(struct file *pFile, const char __user *pData, size_t count, loff_t *off)
2867{
2868#ifdef IP2DEBUG_IPL
2869 printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
2870#endif
2871 return 0;
2872}
2873
2874/******************************************************************************/
2875/* Function: ip2_ipl_ioctl() */
2876/* Parameters: Pointer to device inode */
2877/* Pointer to file structure */
2878/* Command */
2879/* Argument */
2880/* Returns: Success or failure */
2881/* */
2882/* Description: */
2883/* */
2884/* */
2885/******************************************************************************/
Alan Cox47be36a2008-07-25 01:48:13 -07002886static long
2887ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888{
Alan Cox47be36a2008-07-25 01:48:13 -07002889 unsigned int iplminor = iminor(pFile->f_path.dentry->d_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 int rc = 0;
2891 void __user *argp = (void __user *)arg;
2892 ULONG __user *pIndex = argp;
2893 i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
2894 i2ChanStrPtr pCh;
2895
2896#ifdef IP2DEBUG_IPL
2897 printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
2898#endif
2899
Alan Cox47be36a2008-07-25 01:48:13 -07002900 lock_kernel();
2901
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 switch ( iplminor ) {
2903 case 0: // IPL device
2904 rc = -EINVAL;
2905 break;
2906 case 1: // Status dump
2907 case 5:
2908 case 9:
2909 case 13:
2910 switch ( cmd ) {
2911 case 64: /* Driver - ip2stat */
Alan Cox7d7b93c2008-10-13 10:42:09 +01002912 rc = put_user(-1, pIndex++ );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 rc = put_user(irq_counter, pIndex++ );
2914 rc = put_user(bh_counter, pIndex++ );
2915 break;
2916
2917 case 65: /* Board - ip2stat */
2918 if ( pB ) {
2919 rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
Jiri Slabycf1c63c2008-04-30 00:53:54 -07002920 rc = put_user(inb(pB->i2eStatus),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 (ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
2922 } else {
2923 rc = -ENODEV;
2924 }
2925 break;
2926
2927 default:
2928 if (cmd < IP2_MAX_PORTS) {
2929 pCh = DevTable[cmd];
2930 if ( pCh )
2931 {
2932 rc = copy_to_user(argp, pCh, sizeof(i2ChanStr));
2933 } else {
2934 rc = -ENODEV;
2935 }
2936 } else {
2937 rc = -EINVAL;
2938 }
2939 }
2940 break;
2941
2942 case 2: // Ping device
2943 rc = -EINVAL;
2944 break;
2945 case 3: // Trace device
Andrew Mortondef93912006-02-03 03:04:47 -08002946 /*
2947 * akpm: This used to write a whole bunch of function addresses
2948 * to userspace, which generated lots of put_user() warnings.
2949 * I killed it all. Just return "success" and don't do
2950 * anything.
2951 */
2952 if (cmd == 1)
2953 rc = 0;
2954 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 break;
2957
2958 default:
2959 rc = -ENODEV;
2960 break;
2961 }
Alan Cox47be36a2008-07-25 01:48:13 -07002962 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 return rc;
2964}
2965
2966/******************************************************************************/
2967/* Function: ip2_ipl_open() */
2968/* Parameters: Pointer to device inode */
2969/* Pointer to file structure */
2970/* Returns: Success or failure */
2971/* */
2972/* Description: */
2973/* */
2974/* */
2975/******************************************************************************/
2976static int
2977ip2_ipl_open( struct inode *pInode, struct file *pFile )
2978{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979
2980#ifdef IP2DEBUG_IPL
2981 printk (KERN_DEBUG "IP2IPL: open\n" );
2982#endif
Jonathan Corbetf2b98572008-05-18 15:32:43 -06002983 cycle_kernel_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 return 0;
2985}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986
2987static int
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002988proc_ip2mem_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989{
2990 i2eBordStrPtr pB;
2991 i2ChanStrPtr pCh;
2992 PTTY tty;
2993 int i;
2994
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
2996#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
2997#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
2998
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07002999 seq_printf(m,"\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000
3001 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3002 pB = i2BoardPtrTable[i];
3003 if ( pB ) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003004 seq_printf(m,"board %d:\n",i);
3005 seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
3007 }
3008 }
3009
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003010 seq_printf(m,"#: tty flags, port flags, cflags, iflags\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 for (i=0; i < IP2_MAX_PORTS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 pCh = DevTable[i];
3013 if (pCh) {
3014 tty = pCh->pTTY;
3015 if (tty && tty->count) {
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003016 seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 tty->termios->c_cflag,tty->termios->c_iflag);
3018
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003019 seq_printf(m,FMTLIN2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003021 seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 }
3023 }
3024 }
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003025 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026}
3027
Alexey Dobriyan4a5cdb52008-04-29 01:01:55 -07003028static int proc_ip2mem_open(struct inode *inode, struct file *file)
3029{
3030 return single_open(file, proc_ip2mem_show, NULL);
3031}
3032
3033static const struct file_operations ip2mem_proc_fops = {
3034 .owner = THIS_MODULE,
3035 .open = proc_ip2mem_open,
3036 .read = seq_read,
3037 .llseek = seq_lseek,
3038 .release = single_release,
3039};
3040
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041/*
3042 * This is the handler for /proc/tty/driver/ip2
3043 *
3044 * This stretch of code has been largely plagerized from at least three
3045 * different sources including ip2mkdev.c and a couple of other drivers.
3046 * The bugs are all mine. :-) =mhw=
3047 */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003048static int ip2_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049{
3050 int i, j, box;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 int boxes = 0;
3052 int ports = 0;
3053 int tports = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 i2eBordStrPtr pB;
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003055 char *sep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003057 seq_printf(m, "ip2info: 1.0 driver: %s\n", pcVersion);
3058 seq_printf(m, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
3060 IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
3061
3062 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3063 /* This need to be reset for a board by board count... */
3064 boxes = 0;
3065 pB = i2BoardPtrTable[i];
3066 if( pB ) {
3067 switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED )
3068 {
3069 case POR_ID_FIIEX:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003070 seq_printf(m, "Board %d: EX ports=", i);
3071 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 for( box = 0; box < ABS_MAX_BOXES; ++box )
3073 {
3074 ports = 0;
3075
3076 if( pB->i2eChannelMap[box] != 0 ) ++boxes;
3077 for( j = 0; j < ABS_BIGGEST_BOX; ++j )
3078 {
3079 if( pB->i2eChannelMap[box] & 1<< j ) {
3080 ++ports;
3081 }
3082 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003083 seq_printf(m, "%s%d", sep, ports);
3084 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 tports += ports;
3086 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003087 seq_printf(m, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 break;
3089
3090 case POR_ID_II_4:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003091 seq_printf(m, "Board %d: ISA-4 ports=4 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 tports = ports = 4;
3093 break;
3094
3095 case POR_ID_II_8:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003096 seq_printf(m, "Board %d: ISA-8-std ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 tports = ports = 8;
3098 break;
3099
3100 case POR_ID_II_8R:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003101 seq_printf(m, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 tports = ports = 8;
3103 break;
3104
3105 default:
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003106 seq_printf(m, "Board %d: unknown", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 /* Don't try and probe for minor numbers */
3108 tports = ports = 0;
3109 }
3110
3111 } else {
3112 /* Don't try and probe for minor numbers */
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003113 seq_printf(m, "Board %d: vacant", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 tports = ports = 0;
3115 }
3116
3117 if( tports ) {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003118 seq_puts(m, " minors=");
3119 sep = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 for ( box = 0; box < ABS_MAX_BOXES; ++box )
3121 {
3122 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
3123 {
3124 if ( pB->i2eChannelMap[box] & (1 << j) )
3125 {
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003126 seq_printf(m, "%s%d", sep,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 j + ABS_BIGGEST_BOX *
3128 (box+i*ABS_MAX_BOXES));
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003129 sep = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 }
3131 }
3132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003134 seq_putc(m, '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003136 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 }
Alexey Dobriyancdda7cd2009-03-31 15:19:16 -07003138
3139static int ip2_proc_open(struct inode *inode, struct file *file)
3140{
3141 return single_open(file, ip2_proc_show, NULL);
3142}
3143
3144static const struct file_operations ip2_proc_fops = {
3145 .owner = THIS_MODULE,
3146 .open = ip2_proc_open,
3147 .read = seq_read,
3148 .llseek = seq_lseek,
3149 .release = single_release,
3150};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151
3152/******************************************************************************/
3153/* Function: ip2trace() */
3154/* Parameters: Value to add to trace buffer */
3155/* Returns: Nothing */
3156/* */
3157/* Description: */
3158/* */
3159/* */
3160/******************************************************************************/
3161#ifdef IP2DEBUG_TRACE
3162void
3163ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
3164{
3165 long flags;
3166 unsigned long *pCode = &codes;
3167 union ip2breadcrumb bc;
3168 i2ChanStrPtr pCh;
3169
3170
3171 tracebuf[tracestuff++] = jiffies;
3172 if ( tracestuff == TRACEMAX ) {
3173 tracestuff = 0;
3174 }
3175 if ( tracestuff == tracestrip ) {
3176 if ( ++tracestrip == TRACEMAX ) {
3177 tracestrip = 0;
3178 }
3179 ++tracewrap;
3180 }
3181
3182 bc.hdr.port = 0xff & pn;
3183 bc.hdr.cat = cat;
3184 bc.hdr.codes = (unsigned char)( codes & 0xff );
3185 bc.hdr.label = label;
3186 tracebuf[tracestuff++] = bc.value;
3187
3188 for (;;) {
3189 if ( tracestuff == TRACEMAX ) {
3190 tracestuff = 0;
3191 }
3192 if ( tracestuff == tracestrip ) {
3193 if ( ++tracestrip == TRACEMAX ) {
3194 tracestrip = 0;
3195 }
3196 ++tracewrap;
3197 }
3198
3199 if ( !codes-- )
3200 break;
3201
3202 tracebuf[tracestuff++] = *++pCode;
3203 }
3204}
3205#endif
3206
3207
3208MODULE_LICENSE("GPL");
Chuck Shorteb0e71c2006-07-10 04:43:59 -07003209
3210static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
3211 { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
3212 { }
3213};
3214
3215MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);
Ben Hutchingse6c4ef92010-01-13 23:34:18 +00003216
3217MODULE_FIRMWARE("intelliport2.bin");