* add p cc
[mascara-docs.git] / i386 / linux / linux-2.3.21 / drivers / char / ip2main.c
blob8f0ef75ae7f43b1404828cb8b593001c8566022e
1 /*
3 * (c) 1999 by Computone Corporation
5 ********************************************************************************
7 * PACKAGE: Linux tty Device Driver for IntelliPort family of multiport
8 * serial I/O controllers.
10 * DESCRIPTION: Mainline code for the device driver
12 *******************************************************************************/
13 /************/
14 /* Includes */
15 /************/
17 #include <linux/config.h>
18 #include <linux/module.h>
19 #include <linux/version.h>
21 #include <linux/ctype.h>
22 #include <linux/string.h>
23 #include <linux/fcntl.h>
24 #include <linux/errno.h>
26 #include <linux/signal.h>
27 #include <linux/sched.h>
28 #include <linux/timer.h>
29 #include <linux/interrupt.h>
30 #include <linux/pci.h>
31 #include <linux/mm.h>
32 #include <linux/malloc.h>
33 #include <linux/major.h>
34 #include <linux/wait.h>
36 #include <linux/tty.h>
37 #include <linux/tty_flip.h>
38 #include <linux/termios.h>
39 #include <linux/tty_driver.h>
40 #include <linux/serial.h>
41 #include <linux/ptrace.h>
42 #include <linux/ioport.h>
44 #include <linux/cdk.h>
45 #include <linux/comstats.h>
46 #include <linux/delay.h>
48 #include <asm/system.h>
49 #include <asm/io.h>
50 #include <asm/irq.h>
51 #include <asm/bitops.h>
53 #include <linux/vmalloc.h>
54 #include <linux/init.h>
55 #include <asm/serial.h>
57 #include <asm/uaccess.h>
58 #define pcibios_strerror(status) \
59 printk( KERN_ERR "IP2: PCI error 0x%x \n", status );
61 #include "./ip2/ip2types.h"
62 #include "./ip2/ip2trace.h"
63 #include "./ip2/ip2ioctl.h"
64 #include "./ip2/ip2.h"
65 #include "./ip2/i2ellis.h"
66 #include "./ip2/i2lib.h"
68 /*****************
69 * /proc/ip2mem *
70 *****************/
72 #include <linux/proc_fs.h>
74 int ip2_read_procmem(char *, char **, off_t, int, int );
75 int ip2_read_proc(char *, char **, off_t, int, int *, void * );
77 struct proc_dir_entry ip2_proc_entry = {
79 6,"ip2mem",
80 S_IFREG | S_IRUGO,
81 1, 0, 0,
83 NULL,
84 ip2_read_procmem
87 /********************/
88 /* Type Definitions */
89 /********************/
91 /*************/
92 /* Constants */
93 /*************/
95 /* String constants to identify ourselves */
96 static char *pcName = "Computone IntelliPort Plus multiport driver";
97 static char *pcVersion = "1.2.4";
99 /* String constants for port names */
100 static char *pcDriver_name = "ip2";
101 static char *pcTty = "ttyf";
102 static char *pcCallout = "cuf";
103 static char *pcIpl = "ip2ipl";
105 /* Serial subtype definitions */
106 #define SERIAL_TYPE_NORMAL 1
107 #define SERIAL_TYPE_CALLOUT 2
109 // cheezy kludge or genius - you decide?
110 int ip2_loadmain(int *, int *, unsigned char *, int);
111 static unsigned char *Fip_firmware;
112 static int Fip_firmware_size;
114 /***********************/
115 /* Function Prototypes */
116 /***********************/
118 /* Global module entry functions */
119 #ifdef MODULE
120 int init_module(void);
121 void cleanup_module(void);
122 #endif
124 int old_ip2_init(void);
126 /* Private (static) functions */
127 static int ip2_open(PTTY, struct file *);
128 static void ip2_close(PTTY, struct file *);
129 static int ip2_write(PTTY, int, const unsigned char *, int);
130 static void ip2_putchar(PTTY, unsigned char);
131 static void ip2_flush_chars(PTTY);
132 static int ip2_write_room(PTTY);
133 static int ip2_chars_in_buf(PTTY);
134 static void ip2_flush_buffer(PTTY);
135 static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);
136 static void ip2_set_termios(PTTY, struct termios *);
137 static void ip2_set_line_discipline(PTTY);
138 static void ip2_throttle(PTTY);
139 static void ip2_unthrottle(PTTY);
140 static void ip2_stop(PTTY);
141 static void ip2_start(PTTY);
142 static void ip2_hangup(PTTY);
144 static void set_irq(int, int);
145 static void ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs);
146 static void ip2_poll(unsigned long arg);
147 static inline void service_all_boards(void);
148 static inline void do_input(i2ChanStrPtr pCh);
149 static inline void do_status(i2ChanStrPtr pCh);
151 static void ip2_wait_until_sent(PTTY,int);
153 static void set_params (i2ChanStrPtr, struct termios *);
154 static int get_modem_info(i2ChanStrPtr, unsigned int *);
155 static int set_modem_info(i2ChanStrPtr, unsigned int, unsigned int *);
156 static int get_serial_info(i2ChanStrPtr, struct serial_struct *);
157 static int set_serial_info(i2ChanStrPtr, struct serial_struct *);
159 static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *) ;
160 static ssize_t ip2_ipl_write(struct file *, const char *, size_t, loff_t *);
161 static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG);
162 static int ip2_ipl_open(struct inode *, struct file *);
164 void ip2trace(unsigned short,unsigned char,unsigned char,unsigned long,...);
165 static int DumpTraceBuffer(char *, int);
166 static int DumpFifoBuffer( char *, int);
168 static void ip2_init_board(int);
169 static unsigned short find_eisa_board(int);
171 /***************/
172 /* Static Data */
173 /***************/
175 static struct tty_driver ip2_tty_driver;
176 static struct tty_driver ip2_callout_driver;
178 static int ref_count;
180 /* Here, then is a table of board pointers which the interrupt routine should
181 * scan through to determine who it must service.
183 static unsigned short i2nBoards = 0; // Number of boards here
185 static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS];
187 static i2ChanStrPtr DevTable[IP2_MAX_PORTS];
188 //DevTableMem just used to save addresses for kfree
189 static void *DevTableMem[IP2_MAX_BOARDS] = {NULL,NULL,NULL,NULL};
191 static struct tty_struct * TtyTable[IP2_MAX_PORTS];
192 static struct termios * Termios[IP2_MAX_PORTS];
193 static struct termios * TermiosLocked[IP2_MAX_PORTS];
195 /* This is the driver descriptor for the ip2ipl device, which is used to
196 * download the loadware to the boards.
198 static struct file_operations
199 ip2_ipl = {
200 NULL,
201 ip2_ipl_read,
202 ip2_ipl_write,
203 NULL,
204 NULL,
205 ip2_ipl_ioctl,
206 NULL,
207 ip2_ipl_open,
208 NULL,
209 NULL,
210 NULL,
211 NULL,
212 NULL,
213 /* NULL, NULL 2.2 */
216 static long irq_counter = 0;
217 static long bh_counter = 0;
219 // Use immediate queue to service interrupts
220 //#define USE_IQI // PCI&2.2 needs work
221 //#define USE_IQ // PCI&2.2 needs work
223 /* The timer_list entry for our poll routine. If interrupt operation is not
224 * selected, the board is serviced periodically to see if anything needs doing.
226 #define POLL_TIMEOUT (jiffies + 1)
227 static struct timer_list PollTimer = { NULL, NULL, 0, 0, ip2_poll };
228 // next, prev, expires,data, func()
229 static char TimerOn = 0;
231 #ifdef IP2DEBUG_TRACE
232 /* Trace (debug) buffer data */
233 #define TRACEMAX 1000
234 static unsigned long tracebuf[TRACEMAX];
235 static int tracestuff = 0;
236 static int tracestrip = 0;
237 static int tracewrap = 0;
238 #endif
240 /**********/
241 /* Macros */
242 /**********/
244 #if defined(MODULE) && defined(IP2DEBUG_OPEN)
245 #define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \
246 kdevname(tty->device),(pCh->flags),ref_count, \
247 tty->count,/*GET_USE_COUNT(module)*/0,s)
248 #else
249 #define DBG_CNT(s)
250 #endif
252 #define MIN(a,b) ( ( (a) < (b) ) ? (a) : (b) )
253 #define MAX(a,b) ( ( (a) > (b) ) ? (a) : (b) )
255 /********/
256 /* Code */
257 /********/
259 #include "./ip2/i2ellis.c" /* Extremely low-level interface services */
260 #include "./ip2/i2cmd.c" /* Standard loadware command definitions */
261 #include "./ip2/i2lib.c" /* High level interface services */
263 /* Configuration area for modprobe */
264 #ifdef MODULE
265 MODULE_AUTHOR("Doug McNash");
266 MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
267 #endif /* MODULE */
269 static int poll_only = 0;
271 static int Pci_index = 0;
272 static int Eisa_irq = 0;
273 static int Eisa_slot = 0;
275 static int iindx = 0;
276 static char rirqs[IP2_MAX_BOARDS] = {0,};
277 static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
279 /******************************************************************************/
280 /* Initialisation Section */
281 /******************************************************************************/
282 int
283 ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
285 int i;
286 /* process command line arguments to modprobe or insmod i.e. iop & irqp */
287 /* otherwise ip2config is initialized by what's in ip2/ip2.h */
288 /* command line trumps initialization in ip2.h */
289 /* first two args are null if builtin to kernel */
290 if ((irqp != NULL) || (iop != NULL)) {
291 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
292 if (irqp && irqp[i]) {
293 ip2config.irq[i] = irqp[i];
295 if (iop && iop[i]) {
296 ip2config.addr[i] = iop[i];
300 Fip_firmware = firmware;
301 Fip_firmware_size = firmsize;
302 return old_ip2_init();
305 // Some functions to keep track of what irq's we have
307 static int __init
308 is_valid_irq(int irq)
310 int *i = Valid_Irqs;
312 while ((*i != 0) && (*i != irq)) {
313 i++;
315 return (*i);
318 static void __init
319 mark_requested_irq( char irq )
321 rirqs[iindx++] = irq;
324 static int __init
325 clear_requested_irq( char irq )
327 int i;
328 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
329 if (rirqs[i] == irq) {
330 rirqs[i] = 0;
331 return 1;
334 return 0;
337 static int __init
338 have_requested_irq( char irq )
340 // array init to zeros so 0 irq will not be requested as a side effect
341 int i;
342 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
343 if (rirqs[i] == irq)
344 return 1;
346 return 0;
349 /******************************************************************************/
350 /* Function: init_module() */
351 /* Parameters: None */
352 /* Returns: Success (0) */
353 /* */
354 /* Description: */
355 /* This is a required entry point for an installable module. It simply calls */
356 /* the driver initialisation function and returns what it returns. */
357 /******************************************************************************/
358 #ifdef MODULE
360 init_module(void)
362 #ifdef IP2DEBUG_INIT
363 printk (KERN_DEBUG "Loading module ...\n" );
364 #endif
365 //was return old_ip2_init();
366 return 0;
368 #endif /* MODULE */
370 /******************************************************************************/
371 /* Function: cleanup_module() */
372 /* Parameters: None */
373 /* Returns: Nothing */
374 /* */
375 /* Description: */
376 /* This is a required entry point for an installable module. It has to return */
377 /* the device and the driver to a passive state. It should not be necessary */
378 /* to reset the board fully, especially as the loadware is downloaded */
379 /* externally rather than in the driver. We just want to disable the board */
380 /* and clear the loadware to a reset state. To allow this there has to be a */
381 /* way to detect whether the board has the loadware running at init time to */
382 /* handle subsequent installations of the driver. All memory allocated by the */
383 /* driver should be returned since it may be unloaded from memory. */
384 /******************************************************************************/
385 #ifdef MODULE
386 void
387 cleanup_module(void)
389 int err;
390 int i;
392 #ifdef IP2DEBUG_INIT
393 printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );
394 #endif
397 /* Stop poll timer if we had one. */
398 if ( TimerOn ) {
399 del_timer ( &PollTimer );
400 TimerOn = 0;
403 /* Reset the boards we have. */
404 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
405 if ( i2BoardPtrTable[i] ) {
406 iiReset ( i2BoardPtrTable[i] );
410 /* The following is done at most once, if any boards were installed. */
411 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
412 if ( i2BoardPtrTable[i] ) {
413 iiResetDelay( i2BoardPtrTable[i] );
414 /* free io addresses and Tibet */
415 release_region( ip2config.addr[i], 8 );
417 /* Disable and remove interrupt handler. */
418 if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {
419 free_irq ( ip2config.irq[i], (void *)&pcName);
420 clear_requested_irq( ip2config.irq[i]);
423 if ( ( err = tty_unregister_driver ( &ip2_tty_driver ) ) ) {
424 printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
426 if ( ( err = tty_unregister_driver ( &ip2_callout_driver ) ) ) {
427 printk(KERN_ERR "IP2: failed to unregister callout driver (%d)\n", err);
429 if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) {
430 printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err);
432 if ( ( err = proc_unregister( &proc_root, ip2_proc_entry.low_ino ) ) ) {
433 printk(KERN_ERR "IP2: failed to unregister read_procmem (%d)\n", err);
436 // free memory
437 for (i = 0; i < IP2_MAX_BOARDS; i++) {
438 void *pB;
439 if ((pB = i2BoardPtrTable[i]) != 0 ) {
440 kfree ( pB );
441 i2BoardPtrTable[i] = NULL;
443 if ((DevTableMem[i]) != NULL ) {
444 kfree ( DevTableMem[i] );
445 DevTableMem[i] = NULL;
449 /* Cleanup the iiEllis subsystem. */
450 iiEllisCleanup();
451 #ifdef IP2DEBUG_INIT
452 printk (KERN_DEBUG "IP2 Unloaded\n" );
453 #endif
455 #endif /* MODULE */
457 /******************************************************************************/
458 /* Function: old_ip2_init() */
459 /* Parameters: irq, io from command line of insmod et. al. */
460 /* Returns: Success (0) */
461 /* */
462 /* Description: */
463 /* This was the required entry point for all drivers (now in ip2.c) */
464 /* It performs all */
465 /* initialisation of the devices and driver structures, and registers itself */
466 /* with the relevant kernel modules. */
467 /******************************************************************************/
468 /* SA_INTERRUPT- if set blocks all interrupts else only this line */
469 /* SA_SHIRQ - for shared irq PCI or maybe EISA only */
470 /* SA_RANDOM - can be source for cert. random number generators */
471 #define IP2_SA_FLAGS 0
473 int __init
474 old_ip2_init(void)
476 int i;
477 int err;
478 int status = 0;
479 i2eBordStrPtr pB = NULL;
480 int rc = -1;
482 #ifdef IP2DEBUG_TRACE
483 ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
484 #endif
486 /* Announce our presence */
487 printk( KERN_INFO "%s version %s\n", pcName, pcVersion );
489 /* if all irq config is zero we shall poll_only */
490 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
491 poll_only |= ip2config.irq[i];
493 poll_only = !poll_only;
495 /* Initialise the iiEllis subsystem. */
496 iiEllisInit();
498 /* Initialize arrays. */
499 memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable );
500 memset( DevTable, 0, sizeof DevTable );
501 memset( TtyTable, 0, sizeof TtyTable );
502 memset( Termios, 0, sizeof Termios );
503 memset( TermiosLocked, 0, sizeof TermiosLocked );
505 /* Initialise all the boards we can find (up to the maximum). */
506 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
507 switch ( ip2config.addr[i] ) {
508 case 0: /* skip this slot even if card is present */
509 break;
510 default: /* ISA */
511 /* ISA address must be specified */
512 if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) {
513 printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n",
514 i, ip2config.addr[i] );
515 ip2config.addr[i] = 0;
516 } else {
517 ip2config.type[i] = ISA;
519 /* Check for valid irq argument, set for polling if invalid */
520 if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) {
521 printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]);
522 ip2config.irq[i] = 0;// 0 is polling and is valid in that sense
525 break;
526 case PCI:
527 #ifdef CONFIG_PCI
528 if (pci_present()) {
529 struct pci_dev *pci_dev_i = NULL;
530 pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE,
531 PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
532 if (pci_dev_i != NULL) {
533 unsigned int addr;
534 unsigned char pci_irq;
536 ip2config.type[i] = PCI;
538 * Update Pci_index, so that the next time we go
539 * searching for a PCI board we find a different
540 * one.
542 ++Pci_index;
543 status =
544 pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
545 if ( addr & 1 ) {
546 ip2config.addr[i]=(USHORT)(addr&0xfffe);
547 } else {
548 printk( KERN_ERR "IP2: PCI I/O address error\n");
550 status =
551 pci_read_config_byte(pci_dev_i, PCI_INTERRUPT_LINE, &pci_irq);
553 if (!is_valid_irq(pci_irq)) {
554 printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
555 pci_irq = 0;
557 ip2config.irq[i] = pci_irq;
558 } else { // ann error
559 ip2config.addr[i] = 0;
560 if (status == PCIBIOS_DEVICE_NOT_FOUND) {
561 printk( KERN_ERR "IP2: PCI board %d not found\n", i );
562 } else {
563 pcibios_strerror(status);
567 #else
568 printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
569 printk( KERN_ERR "IP2: configured in this kernel.\n");
570 printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n");
571 #endif /* CONFIG_PCI */
572 break;
573 case EISA:
574 if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) {
575 /* Eisa_irq set as side effect, boo */
576 ip2config.type[i] = EISA;
578 ip2config.irq[i] = Eisa_irq;
579 break;
580 } /* switch */
581 } /* for */
582 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
583 if ( ip2config.addr[i] ) {
584 pB = kmalloc( sizeof(i2eBordStr), GFP_KERNEL);
585 if ( pB != NULL ) {
586 i2BoardPtrTable[i] = pB;
587 memset( pB, 0, sizeof(i2eBordStr) );
588 iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer );
589 iiReset( pB );
590 } else {
591 printk(KERN_ERR "IP2: board memory allocation error\n");
595 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
596 if ( ( pB = i2BoardPtrTable[i] ) != NULL ) {
597 iiResetDelay( pB );
598 break;
601 for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
602 if ( i2BoardPtrTable[i] != NULL ) {
603 ip2_init_board( i );
607 #ifdef IP2DEBUG_TRACE
608 ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 );
609 #endif
611 /* Zero out the normal tty device structure. */
612 memset ( &ip2_tty_driver, 0, sizeof ip2_tty_driver );
614 /* Initialise the relevant fields. */
615 ip2_tty_driver.magic = TTY_DRIVER_MAGIC;
616 ip2_tty_driver.name = pcTty;
617 ip2_tty_driver.driver_name = pcDriver_name;
618 ip2_tty_driver.read_proc = ip2_read_proc;
619 ip2_tty_driver.major = IP2_TTY_MAJOR;
620 ip2_tty_driver.minor_start = 0;
621 ip2_tty_driver.num = IP2_MAX_PORTS;
622 ip2_tty_driver.type = TTY_DRIVER_TYPE_SERIAL;
623 ip2_tty_driver.subtype = SERIAL_TYPE_NORMAL;
624 ip2_tty_driver.init_termios = tty_std_termios;
625 ip2_tty_driver.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
626 ip2_tty_driver.flags = TTY_DRIVER_REAL_RAW;
627 ip2_tty_driver.refcount = &ref_count;
628 ip2_tty_driver.table = TtyTable;
629 ip2_tty_driver.termios = Termios;
630 ip2_tty_driver.termios_locked = TermiosLocked;
632 /* Setup the pointers to the implemented functions. */
633 ip2_tty_driver.open = ip2_open;
634 ip2_tty_driver.close = ip2_close;
635 ip2_tty_driver.write = ip2_write;
636 ip2_tty_driver.put_char = ip2_putchar;
637 ip2_tty_driver.flush_chars = ip2_flush_chars;
638 ip2_tty_driver.write_room = ip2_write_room;
639 ip2_tty_driver.chars_in_buffer = ip2_chars_in_buf;
640 ip2_tty_driver.flush_buffer = ip2_flush_buffer;
641 ip2_tty_driver.ioctl = ip2_ioctl;
642 ip2_tty_driver.throttle = ip2_throttle;
643 ip2_tty_driver.unthrottle = ip2_unthrottle;
644 ip2_tty_driver.set_termios = ip2_set_termios;
645 ip2_tty_driver.set_ldisc = ip2_set_line_discipline;
646 ip2_tty_driver.stop = ip2_stop;
647 ip2_tty_driver.start = ip2_start;
648 ip2_tty_driver.hangup = ip2_hangup;
650 /* Initialise the callout driver structure from the tty driver, and
651 * make the needed adjustments.
653 ip2_callout_driver = ip2_tty_driver;
654 ip2_callout_driver.name = pcCallout;
655 ip2_callout_driver.driver_name = pcDriver_name;
656 ip2_callout_driver.read_proc = NULL;
657 ip2_callout_driver.major = IP2_CALLOUT_MAJOR;
658 ip2_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
660 #ifdef IP2DEBUG_TRACE
661 ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
662 #endif
664 /* Register the tty devices. */
665 if ( ( err = tty_register_driver ( &ip2_tty_driver ) ) ) {
666 printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err);
667 } else
668 if ( ( err = tty_register_driver ( &ip2_callout_driver ) ) ) {
669 printk(KERN_ERR "IP2: failed to register callout driver (%d)\n", err);
670 } else
671 /* Register the IPL driver. */
672 if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
673 printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
674 } else
675 /* Register the read_procmem thing */
676 if ( ( err = proc_register( &proc_root, &ip2_proc_entry ) ) ) {
677 printk(KERN_ERR "IP2: failed to register read_procmem (%d)\n", err );
678 } else {
680 #ifdef IP2DEBUG_TRACE
681 ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 );
682 #endif
683 /* Register the interrupt handler or poll handler, depending upon the
684 * specified interrupt.
686 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
687 if ( 0 == ip2config.addr[i] ) {
688 continue;
690 if (poll_only) {
691 ip2config.irq[i] = CIR_POLL;
693 if ( ip2config.irq[i] == CIR_POLL ) {
694 retry:
695 if (!TimerOn) {
696 PollTimer.expires = POLL_TIMEOUT;
697 add_timer ( &PollTimer );
698 TimerOn = 1;
699 printk( KERN_INFO "IP2: polling\n");
701 } else {
702 if (have_requested_irq(ip2config.irq[i]))
703 continue;
704 rc = request_irq( ip2config.irq[i], ip2_interrupt,
705 IP2_SA_FLAGS | (ip2config.type[i] == PCI ? SA_SHIRQ : 0),
706 pcName, (void *)&pcName);
707 if (rc) {
708 printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
709 ip2config.irq[i] = CIR_POLL;
710 printk( KERN_INFO "IP2: Polling %ld/sec.\n",
711 (POLL_TIMEOUT - jiffies));
712 goto retry;
714 mark_requested_irq(ip2config.irq[i]);
715 /* Initialise the interrupt handler bottom half (aka slih). */
718 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
719 if ( i2BoardPtrTable[i] ) {
720 set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
724 #ifdef IP2DEBUG_TRACE
725 ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
726 #endif
728 return 0;
731 /******************************************************************************/
732 /* Function: ip2_init_board() */
733 /* Parameters: Index of board in configuration structure */
734 /* Returns: Success (0) */
735 /* */
736 /* Description: */
737 /* This function initializes the specified board. The loadware is copied to */
738 /* the board, the channel structures are initialized, and the board details */
739 /* are reported on the console. */
740 /******************************************************************************/
741 static void __init
742 ip2_init_board( int boardnum )
744 int i,rc;
745 int nports = 0, nboxes = 0;
746 i2ChanStrPtr pCh;
747 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
749 if ( !iiInitialize ( pB ) ) {
750 printk ( KERN_ERR "IP2: Failed to initialize board at 0x%x, error %d\n",
751 pB->i2eBase, pB->i2eError );
752 kfree ( pB );
753 i2BoardPtrTable[boardnum] = NULL;
754 return;
756 printk(KERN_INFO "Board %d: addr=0x%x irq=%d ", boardnum + 1,
757 ip2config.addr[boardnum], ip2config.irq[boardnum] );
759 if (0 != ( rc = check_region( ip2config.addr[boardnum], 8))) {
760 i2BoardPtrTable[boardnum] = NULL;
761 printk(KERN_ERR "bad addr=0x%x rc = %d\n",
762 ip2config.addr[boardnum], rc );
763 return;
765 request_region( ip2config.addr[boardnum], 8, pcName );
767 if ( iiDownloadAll ( pB, (loadHdrStrPtr)Fip_firmware, 1, Fip_firmware_size )
768 != II_DOWN_GOOD ) {
769 printk ( KERN_ERR "IP2:failed to download loadware " );
770 } else {
771 printk ( KERN_INFO "fv=%d.%d.%d lv=%d.%d.%d\n",
772 pB->i2ePom.e.porVersion,
773 pB->i2ePom.e.porRevision,
774 pB->i2ePom.e.porSubRev, pB->i2eLVersion,
775 pB->i2eLRevision, pB->i2eLSub );
778 switch ( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) {
780 default:
781 printk( KERN_ERR "IP2: Unknown board type, ID = %x",
782 pB->i2ePom.e.porID );
783 nports = 0;
784 goto ex_exit;
785 break;
787 case POR_ID_II_4: /* IntelliPort-II, ISA-4 (4xRJ45) */
788 printk ( KERN_INFO "ISA-4" );
789 nports = 4;
790 break;
792 case POR_ID_II_8: /* IntelliPort-II, 8-port using standard brick. */
793 printk ( KERN_INFO "ISA-8 std" );
794 nports = 8;
795 break;
797 case POR_ID_II_8R: /* IntelliPort-II, 8-port using RJ11's (no CTS) */
798 printk ( KERN_INFO "ISA-8 RJ11" );
799 nports = 8;
800 break;
802 case POR_ID_FIIEX: /* IntelliPort IIEX */
804 int portnum = IP2_PORTS_PER_BOARD * boardnum;
805 int box;
807 for( box = 0; box < ABS_MAX_BOXES; ++box ) {
808 if ( pB->i2eChannelMap[box] != 0 ) {
809 ++nboxes;
811 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
812 if ( pB->i2eChannelMap[box] & 1<< i ) {
813 ++nports;
817 DevTableMem[boardnum] = pCh =
818 kmalloc( sizeof(i2ChanStr) * nports, GFP_KERNEL );
819 if ( !i2InitChannels( pB, nports, pCh ) ) {
820 printk(KERN_ERR "i2InitChannels failed: %d\n",pB->i2eError);
822 pB->i2eChannelPtr = &DevTable[portnum];
823 pB->i2eChannelCnt = ABS_MOST_PORTS;
825 for( box = 0; box < ABS_MAX_BOXES; ++box, portnum += ABS_BIGGEST_BOX ) {
826 for( i = 0; i < ABS_BIGGEST_BOX; ++i ) {
827 if ( pB->i2eChannelMap[box] & (1 << i) ) {
828 DevTable[portnum + i] = pCh;
829 pCh->port_index = portnum + i;
830 pCh++;
834 printk(KERN_INFO "IP2: EX box=%d ports=%d %d bit",
835 nboxes, nports, pB->i2eDataWidth16 ? 16 : 8 );
837 goto ex_exit;
838 break;
840 DevTableMem[boardnum] = pCh =
841 kmalloc ( sizeof (i2ChanStr) * nports, GFP_KERNEL );
842 pB->i2eChannelPtr = pCh;
843 pB->i2eChannelCnt = nports;
844 i2InitChannels ( pB, pB->i2eChannelCnt, pCh );
845 pB->i2eChannelPtr = &DevTable[IP2_PORTS_PER_BOARD * boardnum];
847 for( i = 0; i < pB->i2eChannelCnt; ++i ) {
848 DevTable[IP2_PORTS_PER_BOARD * boardnum + i] = pCh;
849 pCh->port_index = (IP2_PORTS_PER_BOARD * boardnum) + i;
850 pCh++;
852 ex_exit:
853 printk ( KERN_INFO "\n" );
856 /******************************************************************************/
857 /* Function: find_eisa_board ( int start_slot ) */
858 /* Parameters: First slot to check */
859 /* Returns: Address of EISA IntelliPort II controller */
860 /* */
861 /* Description: */
862 /* This function searches for an EISA IntelliPort controller, starting */
863 /* from the specified slot number. If the motherboard is not identified as an */
864 /* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
865 /* it returns the base address of the controller. */
866 /******************************************************************************/
867 static unsigned short __init
868 find_eisa_board( int start_slot )
870 int i, j;
871 unsigned int idm = 0;
872 unsigned int idp = 0;
873 unsigned int base = 0;
874 unsigned int value;
875 int setup_address;
876 int setup_irq;
877 int ismine = 0;
880 * First a check for an EISA motherboard, which we do by comparing the
881 * EISA ID registers for the system board and the first couple of slots.
882 * No slot ID should match the system board ID, but on an ISA or PCI
883 * machine the odds are that an empty bus will return similar values for
884 * each slot.
886 i = 0x0c80;
887 value = (inb(i) << 24) + (inb(i+1) << 16) + (inb(i+2) << 8) + inb(i+3);
888 for( i = 0x1c80; i <= 0x4c80; i += 0x1000 ) {
889 j = (inb(i)<<24)+(inb(i+1)<<16)+(inb(i+2)<<8)+inb(i+3);
890 if ( value == j )
891 return 0;
895 * OK, so we are inclined to believe that this is an EISA machine. Find
896 * an IntelliPort controller.
898 for( i = start_slot; i < 16; i++ ) {
899 base = i << 12;
900 idm = (inb(base + 0xc80) << 8) | (inb(base + 0xc81) & 0xff);
901 idp = (inb(base + 0xc82) << 8) | (inb(base + 0xc83) & 0xff);
902 ismine = 0;
903 if ( idm == 0x0e8e ) {
904 if ( idp == 0x0281 || idp == 0x0218 ) {
905 ismine = 1;
906 } else if ( idp == 0x0282 || idp == 0x0283 ) {
907 ismine = 3; /* Can do edge-trigger */
909 if ( ismine ) {
910 Eisa_slot = i;
911 break;
915 if ( !ismine )
916 return 0;
918 /* It's some sort of EISA card, but at what address is it configured? */
920 setup_address = base + 0xc88;
921 value = inb(base + 0xc86);
922 setup_irq = (value & 8) ? Valid_Irqs[value & 7] : 0;
924 if ( (ismine & 2) && !(value & 0x10) ) {
925 ismine = 1; /* Could be edging, but not */
928 if ( Eisa_irq == 0 ) {
929 Eisa_irq = setup_irq;
930 } else if ( Eisa_irq != setup_irq ) {
931 printk ( KERN_ERR "IP2: EISA irq mismatch between EISA controllers\n" );
934 #ifdef IP2DEBUG_INIT
935 printk(KERN_DEBUG "Computone EISA board in slot %d, I.D. 0x%x%x, Address 0x%x",
936 base >> 12, idm, idp, setup_address);
937 if ( Eisa_irq ) {
938 printk(KERN_DEBUG ", Interrupt %d %s\n",
939 setup_irq, (ismine & 2) ? "(edge)" : "(level)");
940 } else {
941 printk(KERN_DEBUG ", (polled)\n");
943 #endif
944 return setup_address;
947 /******************************************************************************/
948 /* Function: set_irq() */
949 /* Parameters: index to board in board table */
950 /* IRQ to use */
951 /* Returns: Success (0) */
952 /* */
953 /* Description: */
954 /******************************************************************************/
955 static void
956 set_irq( int boardnum, int boardIrq )
958 i2ChanStrPtr pCh;
959 unsigned char tempCommand[16];
960 i2eBordStrPtr pB = i2BoardPtrTable[boardnum];
961 unsigned long flags;
964 * Notify the boards they may generate interrupts. This is done by
965 * sending an in-line command to channel 0 on each board. This is why
966 * the channels have to be defined already. For each board, if the
967 * interrupt has never been defined, we must do so NOW, directly, since
968 * board will not send flow control or even give an interrupt until this
969 * is done. If polling we must send 0 as the interrupt parameter.
972 pCh = (i2ChanStrPtr) pB->i2eChannelPtr;
974 // We will get an interrupt here at the end of this function
976 iiDisableMailIrq(pB);
978 /* We build up the entire packet header. */
979 CHANNEL_OF(tempCommand) = 0;
980 PTYPE_OF(tempCommand) = PTYPE_INLINE;
981 CMD_COUNT_OF(tempCommand) = 2;
982 (CMD_OF(tempCommand))[0] = CMDVALUE_IRQ;
983 (CMD_OF(tempCommand))[1] = boardIrq;
985 * Write to FIFO; don't bother to adjust fifo capacity for this, since
986 * board will respond almost immediately after SendMail hit.
988 WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
989 iiWriteBuf(pB, tempCommand, 4);
990 WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
991 pB->i2eUsingIrq = boardIrq;
992 pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
994 /* Need to update number of boards before you enable mailbox int */
995 ++i2nBoards;
997 CHANNEL_OF(tempCommand) = 0;
998 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
999 CMD_COUNT_OF(tempCommand) = 6;
1000 (CMD_OF(tempCommand))[0] = 88; // SILO
1001 (CMD_OF(tempCommand))[1] = 64; // chars
1002 (CMD_OF(tempCommand))[2] = 32; // ms
1004 (CMD_OF(tempCommand))[3] = 28; // MAX_BLOCK
1005 (CMD_OF(tempCommand))[4] = 64; // chars
1007 (CMD_OF(tempCommand))[5] = 87; // HW_TEST
1008 WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
1009 iiWriteBuf(pB, tempCommand, 8);
1010 WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
1012 CHANNEL_OF(tempCommand) = 0;
1013 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1014 CMD_COUNT_OF(tempCommand) = 1;
1015 (CMD_OF(tempCommand))[0] = 84; /* get BOX_IDS */
1016 iiWriteBuf(pB, tempCommand, 3);
1018 #ifdef XXX
1019 // enable heartbeat for test porpoises
1020 CHANNEL_OF(tempCommand) = 0;
1021 PTYPE_OF(tempCommand) = PTYPE_BYPASS;
1022 CMD_COUNT_OF(tempCommand) = 2;
1023 (CMD_OF(tempCommand))[0] = 44; /* get ping */
1024 (CMD_OF(tempCommand))[1] = 200; /* 200 ms */
1025 WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
1026 iiWriteBuf(pB, tempCommand, 4);
1027 WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
1028 #endif
1030 iiEnableMailIrq(pB);
1031 iiSendPendingMail(pB);
1034 /******************************************************************************/
1035 /* Interrupt Handler Section */
1036 /******************************************************************************/
1038 static inline void
1039 service_all_boards()
1041 int i;
1042 i2eBordStrPtr pB;
1044 /* Service every board on the list */
1045 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
1046 pB = i2BoardPtrTable[i];
1047 if ( pB ) {
1048 i2ServiceBoard( pB );
1054 #ifdef USE_IQI
1055 static struct tq_struct
1056 senior_service =
1057 { // it's the death that worse than fate
1058 NULL,
1060 (void(*)(void*)) service_all_boards,
1061 NULL, //later - board address XXX
1063 #endif
1065 /******************************************************************************/
1066 /* Function: ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs) */
1067 /* Parameters: irq - interrupt number */
1068 /* pointer to optional device ID structure */
1069 /* pointer to register structure */
1070 /* Returns: Nothing */
1071 /* */
1072 /* Description: */
1073 /* */
1074 /* */
1075 /******************************************************************************/
1076 static void
1077 ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs)
1079 int i;
1080 i2eBordStrPtr pB;
1082 #ifdef IP2DEBUG_TRACE
1083 ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
1084 #endif
1086 #ifdef USE_IQI
1088 queue_task(&senior_service, &tq_immediate);
1089 mark_bh(IMMEDIATE_BH);
1091 #else
1092 /* Service just the boards on the list using this irq */
1093 for( i = 0; i < i2nBoards; ++i ) {
1094 pB = i2BoardPtrTable[i];
1095 if ( pB && (pB->i2eUsingIrq == irq) ) {
1096 i2ServiceBoard( pB );
1100 #endif /* USE_IQI */
1102 ++irq_counter;
1104 #ifdef IP2DEBUG_TRACE
1105 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1106 #endif
1109 /******************************************************************************/
1110 /* Function: ip2_poll(unsigned long arg) */
1111 /* Parameters: ? */
1112 /* Returns: Nothing */
1113 /* */
1114 /* Description: */
1115 /* This function calls the library routine i2ServiceBoard for each board in */
1116 /* the board table. This is used instead of the interrupt routine when polled */
1117 /* mode is specified. */
1118 /******************************************************************************/
1119 static void
1120 ip2_poll(unsigned long arg)
1122 #ifdef IP2DEBUG_TRACE
1123 ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 );
1124 #endif
1125 TimerOn = 0; // it's the truth but not checked in service
1127 bh_counter++;
1129 #ifdef USE_IQI
1131 queue_task(&senior_service, &tq_immediate);
1132 mark_bh(IMMEDIATE_BH);
1134 #else
1135 // Just polled boards, service_all might be better
1136 ip2_interrupt(0, NULL, NULL);
1138 #endif /* USE_IQI */
1140 PollTimer.expires = POLL_TIMEOUT;
1141 add_timer( &PollTimer );
1142 TimerOn = 1;
1144 #ifdef IP2DEBUG_TRACE
1145 ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
1146 #endif
1149 static inline void
1150 do_input( i2ChanStrPtr pCh )
1152 unsigned long flags;
1154 #ifdef IP2DEBUG_TRACE
1155 ip2trace(PORTN, ITRC_INPUT, 21, 0 );
1156 #endif
1157 // Data input
1158 if ( pCh->pTTY != NULL ) {
1159 READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
1160 if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
1161 READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
1162 i2Input( pCh );
1163 } else
1164 READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
1165 } else {
1166 #ifdef IP2DEBUG_TRACE
1167 ip2trace(PORTN, ITRC_INPUT, 22, 0 );
1168 #endif
1169 i2InputFlush( pCh );
1173 // code duplicated from n_tty (ldisc)
1174 static inline void
1175 isig(int sig, struct tty_struct *tty, int flush)
1177 if (tty->pgrp > 0)
1178 kill_pg(tty->pgrp, sig, 1);
1179 if (flush || !L_NOFLSH(tty)) {
1180 if ( tty->ldisc.flush_buffer )
1181 tty->ldisc.flush_buffer(tty);
1182 i2InputFlush( tty->driver_data );
1186 static inline void
1187 do_status( i2ChanStrPtr pCh )
1189 int status;
1191 status = i2GetStatus( pCh, (I2_BRK|I2_PAR|I2_FRA|I2_OVR) );
1193 #ifdef IP2DEBUG_TRACE
1194 ip2trace (PORTN, ITRC_STATUS, 21, 1, status );
1195 #endif
1197 if (pCh->pTTY && (status & (I2_BRK|I2_PAR|I2_FRA|I2_OVR)) ) {
1198 if ( (status & I2_BRK) ) {
1199 // code duplicated from n_tty (ldisc)
1200 if (I_IGNBRK(pCh->pTTY))
1201 goto skip_this;
1202 if (I_BRKINT(pCh->pTTY)) {
1203 isig(SIGINT, pCh->pTTY, 1);
1204 goto skip_this;
1206 wake_up_interruptible(&pCh->pTTY->read_wait);
1208 #ifdef NEVER_HAPPENS_AS_SETUP_XXX
1209 // and can't work because we don't know the_char
1210 // as the_char is reported on a seperate path
1211 // The intelligent board does this stuff as setup
1213 char brkf = TTY_NORMAL;
1214 unsigned char brkc = '\0';
1215 unsigned char tmp;
1216 if ( (status & I2_BRK) ) {
1217 brkf = TTY_BREAK;
1218 brkc = '\0';
1220 else if (status & I2_PAR) {
1221 brkf = TTY_PARITY;
1222 brkc = the_char;
1223 } else if (status & I2_FRA) {
1224 brkf = TTY_FRAME;
1225 brkc = the_char;
1226 } else if (status & I2_OVR) {
1227 brkf = TTY_OVERRUN;
1228 brkc = the_char;
1230 tmp = pCh->pTTY->real_raw;
1231 pCh->pTTY->real_raw = 0;
1232 pCh->pTTY->ldisc.receive_buf( pCh->pTTY, &brkc, &brkf, 1 );
1233 pCh->pTTY->real_raw = tmp;
1235 #endif /* NEVER_HAPPENS_AS_SETUP_XXX */
1237 skip_this:
1239 if ( status & (I2_DDCD | I2_DDSR | I2_DCTS | I2_DRI) ) {
1240 wake_up_interruptible(&pCh->delta_msr_wait);
1242 if ( (pCh->flags & ASYNC_CHECK_CD) && (status & I2_DDCD) ) {
1243 if ( status & I2_DCD ) {
1244 if ( pCh->wopen ) {
1245 wake_up_interruptible ( &pCh->open_wait );
1247 } else if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) ) {
1248 if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
1249 tty_hangup( pCh->pTTY );
1255 #ifdef IP2DEBUG_TRACE
1256 ip2trace (PORTN, ITRC_STATUS, 26, 0 );
1257 #endif
1260 /******************************************************************************/
1261 /* Device Open/Close/Ioctl Entry Point Section */
1262 /******************************************************************************/
1264 /******************************************************************************/
1265 /* Function: open_sanity_check() */
1266 /* Parameters: Pointer to tty structure */
1267 /* Pointer to file structure */
1268 /* Returns: Success or failure */
1269 /* */
1270 /* Description: */
1271 /* Verifies the structure magic numbers and cross links. */
1272 /******************************************************************************/
1273 #ifdef IP2DEBUG_OPEN
1274 static void
1275 open_sanity_check( i2ChanStrPtr pCh, i2eBordStrPtr pBrd )
1277 if ( pBrd->i2eValid != I2E_MAGIC ) {
1278 printk(KERN_ERR "IP2: invalid board structure\n" );
1279 } else if ( pBrd != pCh->pMyBord ) {
1280 printk(KERN_ERR "IP2: board structure pointer mismatch (%p)\n",
1281 pCh->pMyBord );
1282 } else if ( pBrd->i2eChannelCnt < pCh->port_index ) {
1283 printk(KERN_ERR "IP2: bad device index (%d)\n", pCh->port_index );
1284 } else if (&((i2ChanStrPtr)pBrd->i2eChannelPtr)[pCh->port_index] != pCh) {
1285 } else {
1286 printk(KERN_INFO "IP2: all pointers check out!\n" );
1289 #endif
1292 /******************************************************************************/
1293 /* Function: ip2_open() */
1294 /* Parameters: Pointer to tty structure */
1295 /* Pointer to file structure */
1296 /* Returns: Success or failure */
1297 /* */
1298 /* Description: (MANDATORY) */
1299 /* A successful device open has to run a gauntlet of checks before it */
1300 /* completes. After some sanity checking and pointer setup, the function */
1301 /* blocks until all conditions are satisfied. It then initialises the port to */
1302 /* the default characteristics and returns. */
1303 /******************************************************************************/
1304 static int
1305 ip2_open( PTTY tty, struct file *pFile )
1307 int rc = 0;
1308 int do_clocal = 0;
1309 i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
1311 #ifdef IP2DEBUG_TRACE
1312 ip2trace (MINOR(tty->device), ITRC_OPEN, ITRC_ENTER, 0 );
1313 #endif
1315 if ( pCh == NULL ) {
1316 return -ENODEV;
1318 /* Setup pointer links in device and tty structures */
1319 pCh->pTTY = tty;
1320 tty->driver_data = pCh;
1321 MOD_INC_USE_COUNT;
1323 #ifdef IP2DEBUG_OPEN
1324 printk(KERN_DEBUG \
1325 "IP2:open(tty=%p,pFile=%p):dev=%x,maj=%d,min=%d,ch=%d,idx=%d\n",
1326 tty, pFile, tty->device, MAJOR(tty->device), MINOR(tty->device),
1327 pCh->infl.hd.i2sChannel, pCh->port_index);
1328 open_sanity_check ( pCh, pCh->pMyBord );
1329 #endif
1331 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1332 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1333 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
1334 i2QueueCommands(PTYPE_INLINE, pCh, 100, 3,
1335 CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
1336 serviceOutgoingFifo( pCh->pMyBord );
1338 /* Block here until the port is ready (per serial and istallion) */
1340 * 1. If the port is in the middle of closing wait for the completion
1341 * and then return the appropriate error.
1343 if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) {
1344 if ( pCh->flags & ASYNC_CLOSING ) {
1345 interruptible_sleep_on( &pCh->close_wait);
1347 if ( tty_hung_up_p(pFile) ) {
1348 return( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS;
1352 * 2. If this is a callout device, make sure the normal port is not in
1353 * use, and that someone else doesn't have the callout device locked.
1354 * (These are the only tests the standard serial driver makes for
1355 * callout devices.)
1357 if ( tty->driver.subtype == SERIAL_TYPE_CALLOUT ) {
1358 if ( pCh->flags & ASYNC_NORMAL_ACTIVE ) {
1359 return -EBUSY;
1361 if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) &&
1362 ( pCh->flags & ASYNC_SESSION_LOCKOUT ) &&
1363 ( pCh->session != current->session ) ) {
1364 return -EBUSY;
1366 if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) &&
1367 ( pCh->flags & ASYNC_PGRP_LOCKOUT ) &&
1368 ( pCh->pgrp != current->pgrp ) ) {
1369 return -EBUSY;
1371 pCh->flags |= ASYNC_CALLOUT_ACTIVE;
1372 goto noblock;
1375 * 3. Handle a non-blocking open of a normal port.
1377 if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
1378 if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) {
1379 return -EBUSY;
1381 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1382 goto noblock;
1385 * 4. Now loop waiting for the port to be free and carrier present
1386 * (if required).
1388 if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) {
1389 if ( pCh->NormalTermios.c_cflag & CLOCAL ) {
1390 do_clocal = 1;
1392 } else {
1393 if ( tty->termios->c_cflag & CLOCAL ) {
1394 do_clocal = 1;
1398 #ifdef IP2DEBUG_OPEN
1399 printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
1400 #endif
1402 ++pCh->wopen;
1403 for(;;) {
1404 if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE)) {
1405 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
1406 pCh->dataSetOut |= (I2_DTR | I2_RTS);
1407 serviceOutgoingFifo( pCh->pMyBord );
1409 if ( tty_hung_up_p(pFile) ) {
1410 return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
1412 if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) &&
1413 !(pCh->flags & ASYNC_CLOSING) &&
1414 (do_clocal || (pCh->dataSetIn & I2_DCD) )) {
1415 rc = 0;
1416 break;
1419 #ifdef IP2DEBUG_OPEN
1420 printk(KERN_DEBUG "ASYNC_CALLOUT_ACTIVE = %s\n",
1421 (pCh->flags & ASYNC_CALLOUT_ACTIVE)?"True":"False");
1422 printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
1423 (pCh->flags & ASYNC_CLOSING)?"True":"False");
1424 printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
1425 #endif
1426 #ifdef IP2DEBUG_TRACE
1427 ip2trace (PORTN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE),
1428 (pCh->flags & ASYNC_CLOSING) );
1429 #endif
1430 /* check for signal */
1431 if (signal_pending(current)) {
1432 rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS);
1433 break;
1435 interruptible_sleep_on(&pCh->open_wait);
1437 --pCh->wopen; //why count?
1438 #ifdef IP2DEBUG_TRACE
1439 ip2trace (PORTN, ITRC_OPEN, 4, 0 );
1440 #endif
1441 if (rc != 0 ) {
1442 return rc;
1444 pCh->flags |= ASYNC_NORMAL_ACTIVE;
1446 noblock:
1448 /* first open - Assign termios structure to port */
1449 if ( tty->count == 1 ) {
1450 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1451 if ( pCh->flags & ASYNC_SPLIT_TERMIOS ) {
1452 if ( tty->driver.subtype == SERIAL_TYPE_NORMAL ) {
1453 *tty->termios = pCh->NormalTermios;
1454 } else {
1455 *tty->termios = pCh->CalloutTermios;
1458 /* Now we must send the termios settings to the loadware */
1459 set_params( pCh, NULL );
1462 /* override previous and never reset ??? */
1463 pCh->session = current->session;
1464 pCh->pgrp = current->pgrp;
1467 * Now set any i2lib options. These may go away if the i2lib code ends
1468 * up rolled into the mainline.
1470 pCh->channelOptions |= CO_NBLOCK_WRITE;
1472 #ifdef IP2DEBUG_OPEN
1473 printk (KERN_DEBUG "IP2: open completed\n" );
1474 #endif
1475 serviceOutgoingFifo( pCh->pMyBord );
1477 #ifdef IP2DEBUG_TRACE
1478 ip2trace (PORTN, ITRC_OPEN, ITRC_RETURN, 0 );
1479 #endif
1480 return 0;
1483 /******************************************************************************/
1484 /* Function: ip2_close() */
1485 /* Parameters: Pointer to tty structure */
1486 /* Pointer to file structure */
1487 /* Returns: Nothing */
1488 /* */
1489 /* Description: */
1490 /* */
1491 /* */
1492 /******************************************************************************/
1493 static void
1494 ip2_close( PTTY tty, struct file *pFile )
1496 i2ChanStrPtr pCh = tty->driver_data;
1498 if ( !pCh ) {
1499 return;
1502 #ifdef IP2DEBUG_TRACE
1503 ip2trace (PORTN, ITRC_CLOSE, ITRC_ENTER, 0 );
1504 #endif
1506 #ifdef IP2DEBUG_OPEN
1507 printk(KERN_DEBUG "IP2:close ttyF%02X:\n",MINOR(tty->device));
1508 #endif
1510 if ( tty_hung_up_p ( pFile ) ) {
1511 MOD_DEC_USE_COUNT;
1513 #ifdef IP2DEBUG_TRACE
1514 ip2trace (PORTN, ITRC_CLOSE, 2, 1, 2 );
1515 #endif
1516 return;
1518 if ( tty->count > 1 ) { /* not the last close */
1519 MOD_DEC_USE_COUNT;
1520 #ifdef IP2DEBUG_TRACE
1521 ip2trace (PORTN, ITRC_CLOSE, 2, 1, 3 );
1522 #endif
1523 return;
1525 pCh->flags |= ASYNC_CLOSING; // last close actually
1528 * Save the termios structure, since this port may have separate termios
1529 * for callout and dialin.
1531 if (pCh->flags & ASYNC_NORMAL_ACTIVE)
1532 pCh->NormalTermios = *tty->termios;
1533 if (pCh->flags & ASYNC_CALLOUT_ACTIVE)
1534 pCh->CalloutTermios = *tty->termios;
1536 tty->closing = 1;
1538 if (pCh->ClosingWaitTime != ASYNC_CLOSING_WAIT_NONE) {
1540 * Before we drop DTR, make sure the transmitter has completely drained.
1541 * This uses an timeout, after which the close
1542 * completes.
1544 ip2_wait_until_sent(tty, pCh->ClosingWaitTime );
1547 * At this point we stop accepting input. Here we flush the channel
1548 * input buffer which will allow the board to send up more data. Any
1549 * additional input is tossed at interrupt/poll time.
1551 i2InputFlush( pCh );
1553 /* disable DSS reporting */
1554 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
1555 if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
1556 i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
1557 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1558 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1560 i2QueueCommands(PTYPE_INLINE, pCh, 100, 3,
1561 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1563 serviceOutgoingFifo ( pCh->pMyBord );
1565 if ( tty->driver.flush_buffer )
1566 tty->driver.flush_buffer(tty);
1567 if ( tty->ldisc.flush_buffer )
1568 tty->ldisc.flush_buffer(tty);
1569 tty->closing = 0;
1571 pCh->pTTY = NULL;
1573 if (pCh->wopen) {
1574 if (pCh->ClosingDelay) {
1575 current->state = TASK_INTERRUPTIBLE;
1576 schedule_timeout(pCh->ClosingDelay);
1578 wake_up_interruptible(&pCh->open_wait);
1581 pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
1582 wake_up_interruptible(&pCh->close_wait);
1584 #ifdef IP2DEBUG_OPEN
1585 DBG_CNT("ip2_close: after wakeups--");
1586 #endif
1588 MOD_DEC_USE_COUNT;
1590 #ifdef IP2DEBUG_TRACE
1591 ip2trace (PORTN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
1592 #endif
1593 return;
1596 /******************************************************************************/
1597 /* Function: ip2_hangup() */
1598 /* Parameters: Pointer to tty structure */
1599 /* Returns: Nothing */
1600 /* */
1601 /* Description: */
1602 /* */
1603 /* */
1604 /******************************************************************************/
1605 static void
1606 ip2_hangup ( PTTY tty )
1608 i2ChanStrPtr pCh = tty->driver_data;
1610 #ifdef IP2DEBUG_TRACE
1611 ip2trace (PORTN, ITRC_HANGUP, ITRC_ENTER, 0 );
1612 #endif
1614 ip2_flush_buffer(tty);
1616 /* disable DSS reporting */
1618 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_DCD_NREP);
1619 i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
1620 if ( !tty || (tty->termios->c_cflag & HUPCL) ) {
1621 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 2, CMD_RTSDN, CMD_DTRDN);
1622 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
1623 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
1625 i2QueueCommands(PTYPE_INLINE, pCh, 1, 3,
1626 CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP);
1627 serviceOutgoingFifo ( pCh->pMyBord );
1629 wake_up_interruptible ( &pCh->delta_msr_wait );
1631 pCh->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
1632 pCh->pTTY = NULL;
1633 wake_up_interruptible ( &pCh->open_wait );
1635 #ifdef IP2DEBUG_TRACE
1636 ip2trace (PORTN, ITRC_HANGUP, ITRC_RETURN, 0 );
1637 #endif
1640 /******************************************************************************/
1641 /******************************************************************************/
1642 /* Device Output Section */
1643 /******************************************************************************/
1644 /******************************************************************************/
1646 /******************************************************************************/
1647 /* Function: ip2_write() */
1648 /* Parameters: Pointer to tty structure */
1649 /* Flag denoting data is in user (1) or kernel (0) space */
1650 /* Pointer to data */
1651 /* Number of bytes to write */
1652 /* Returns: Number of bytes actually written */
1653 /* */
1654 /* Description: (MANDATORY) */
1655 /* */
1656 /* */
1657 /******************************************************************************/
1658 static int
1659 ip2_write( PTTY tty, int user, const unsigned char *pData, int count)
1661 i2ChanStrPtr pCh = tty->driver_data;
1662 int bytesSent = 0;
1663 unsigned long flags;
1665 #ifdef IP2DEBUG_TRACE
1666 ip2trace (PORTN, ITRC_WRITE, ITRC_ENTER, 2, count, -1 );
1667 #endif
1669 /* Flush out any buffered data left over from ip2_putchar() calls. */
1670 ip2_flush_chars( tty );
1672 /* This is the actual move bit. Make sure it does what we need!!!!! */
1673 WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1674 bytesSent = i2Output( pCh, pData, count, user );
1675 WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1677 #ifdef IP2DEBUG_TRACE
1678 ip2trace (PORTN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
1679 #endif
1680 return bytesSent > 0 ? bytesSent : 0;
1683 /******************************************************************************/
1684 /* Function: ip2_putchar() */
1685 /* Parameters: Pointer to tty structure */
1686 /* Character to write */
1687 /* Returns: Nothing */
1688 /* */
1689 /* Description: */
1690 /* */
1691 /* */
1692 /******************************************************************************/
1693 static void
1694 ip2_putchar( PTTY tty, unsigned char ch )
1696 i2ChanStrPtr pCh = tty->driver_data;
1697 unsigned long flags;
1699 #ifdef IP2DEBUG_TRACE
1700 // ip2trace (PORTN, ITRC_PUTC, ITRC_ENTER, 1, ch );
1701 #endif
1703 WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1704 pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
1705 if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
1706 WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1707 ip2_flush_chars( tty );
1708 } else
1709 WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1711 #ifdef IP2DEBUG_TRACE
1712 // ip2trace (PORTN, ITRC_PUTC, ITRC_RETURN, 1, ch );
1713 #endif
1716 /******************************************************************************/
1717 /* Function: ip2_flush_chars() */
1718 /* Parameters: Pointer to tty structure */
1719 /* Returns: Nothing */
1720 /* */
1721 /* Description: */
1722 /* */
1723 /******************************************************************************/
1724 static void
1725 ip2_flush_chars( PTTY tty )
1727 int strip;
1728 i2ChanStrPtr pCh = tty->driver_data;
1729 unsigned long flags;
1731 WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1732 if ( pCh->Pbuf_stuff ) {
1733 #ifdef IP2DEBUG_TRACE
1734 // ip2trace (PORTN, ITRC_PUTC, 10, 1, strip );
1735 #endif
1737 // We may need to restart i2Output if it does not fullfill this request
1739 strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff, 0 );
1740 if ( strip != pCh->Pbuf_stuff ) {
1741 memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
1743 pCh->Pbuf_stuff -= strip;
1745 WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1748 /******************************************************************************/
1749 /* Function: ip2_write_room() */
1750 /* Parameters: Pointer to tty structure */
1751 /* Returns: Number of bytes that the driver can accept */
1752 /* */
1753 /* Description: */
1754 /* */
1755 /******************************************************************************/
1756 static int
1757 ip2_write_room ( PTTY tty )
1759 int bytesFree;
1760 i2ChanStrPtr pCh = tty->driver_data;
1761 unsigned long flags;
1763 READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1764 bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
1765 READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1767 #ifdef IP2DEBUG_TRACE
1768 ip2trace (PORTN, ITRC_WRITE, 11, 1, bytesFree );
1769 #endif
1771 return ((bytesFree > 0) ? bytesFree : 0);
1774 /******************************************************************************/
1775 /* Function: ip2_chars_in_buf() */
1776 /* Parameters: Pointer to tty structure */
1777 /* Returns: Number of bytes queued for transmission */
1778 /* */
1779 /* Description: */
1780 /* */
1781 /* */
1782 /******************************************************************************/
1783 static int
1784 ip2_chars_in_buf ( PTTY tty )
1786 i2ChanStrPtr pCh = tty->driver_data;
1787 int rc;
1788 unsigned long flags;
1789 #ifdef IP2DEBUG_TRACE
1790 ip2trace (PORTN, ITRC_WRITE, 12, 1, pCh->Obuf_char_count + pCh->Pbuf_stuff );
1791 #endif
1792 #ifdef IP2DEBUG_WRITE
1793 printk (KERN_DEBUG "IP2: chars in buffer = %d (%d,%d)\n",
1794 pCh->Obuf_char_count + pCh->Pbuf_stuff,
1795 pCh->Obuf_char_count, pCh->Pbuf_stuff );
1796 #endif
1797 READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
1798 rc = pCh->Obuf_char_count;
1799 READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
1800 READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1801 rc += pCh->Pbuf_stuff;
1802 READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1803 return rc;
1806 /******************************************************************************/
1807 /* Function: ip2_flush_buffer() */
1808 /* Parameters: Pointer to tty structure */
1809 /* Returns: Nothing */
1810 /* */
1811 /* Description: */
1812 /* */
1813 /* */
1814 /******************************************************************************/
1815 static void
1816 ip2_flush_buffer( PTTY tty )
1818 i2ChanStrPtr pCh = tty->driver_data;
1819 unsigned long flags;
1821 #ifdef IP2DEBUG_TRACE
1822 ip2trace (PORTN, ITRC_FLUSH, ITRC_ENTER, 0 );
1823 #endif
1824 #ifdef IP2DEBUG_WRITE
1825 printk (KERN_DEBUG "IP2: flush buffer\n" );
1826 #endif
1827 WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
1828 pCh->Pbuf_stuff = 0;
1829 WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
1830 i2FlushOutput( pCh );
1831 ip2_owake(tty);
1832 #ifdef IP2DEBUG_TRACE
1833 ip2trace (PORTN, ITRC_FLUSH, ITRC_RETURN, 0 );
1834 #endif
1837 /******************************************************************************/
1838 /* Function: ip2_wait_until_sent() */
1839 /* Parameters: Pointer to tty structure */
1840 /* Timeout for wait. */
1841 /* Returns: Nothing */
1842 /* */
1843 /* Description: */
1844 /* This function is used in place of the normal tty_wait_until_sent, which */
1845 /* only waits for the driver buffers to be empty (or rather, those buffers */
1846 /* reported by chars_in_buffer) which doesn't work for IP2 due to the */
1847 /* indeterminate number of bytes buffered on the board. */
1848 /******************************************************************************/
1849 static void
1850 ip2_wait_until_sent ( PTTY tty, int timeout )
1852 int i = jiffies;
1853 i2ChanStrPtr pCh = tty->driver_data;
1855 tty_wait_until_sent(tty, timeout );
1856 if ( (i = timeout - (jiffies -i)) > 0)
1857 i2DrainOutput( pCh, i );
1860 /******************************************************************************/
1861 /******************************************************************************/
1862 /* Device Input Section */
1863 /******************************************************************************/
1864 /******************************************************************************/
1866 /******************************************************************************/
1867 /* Function: ip2_throttle() */
1868 /* Parameters: Pointer to tty structure */
1869 /* Returns: Nothing */
1870 /* */
1871 /* Description: */
1872 /* */
1873 /* */
1874 /******************************************************************************/
1875 static void
1876 ip2_throttle ( PTTY tty )
1878 i2ChanStrPtr pCh = tty->driver_data;
1880 #ifdef IP2DEBUG_READ
1881 printk (KERN_DEBUG "IP2: throttle\n" );
1882 #endif
1884 * Signal the poll/interrupt handlers not to forward incoming data to
1885 * the line discipline. This will cause the buffers to fill up in the
1886 * library and thus cause the library routines to send the flow control
1887 * stuff.
1889 pCh->throttled = 1;
1892 /******************************************************************************/
1893 /* Function: ip2_unthrottle() */
1894 /* Parameters: Pointer to tty structure */
1895 /* Returns: Nothing */
1896 /* */
1897 /* Description: */
1898 /* */
1899 /* */
1900 /******************************************************************************/
1901 static void
1902 ip2_unthrottle ( PTTY tty )
1904 i2ChanStrPtr pCh = tty->driver_data;
1905 unsigned long flags;
1907 #ifdef IP2DEBUG_READ
1908 printk (KERN_DEBUG "IP2: unthrottle\n" );
1909 #endif
1911 /* Pass incoming data up to the line discipline again. */
1912 pCh->throttled = 0;
1913 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
1914 serviceOutgoingFifo( pCh->pMyBord );
1915 READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
1916 if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
1917 READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
1918 #ifdef IP2DEBUG_READ
1919 printk (KERN_DEBUG "i2Input called from unthrottle\n" );
1920 #endif
1921 i2Input( pCh );
1922 } else
1923 READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
1926 static void
1927 ip2_start ( PTTY tty )
1929 i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
1931 i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
1932 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_UNSUSPEND);
1933 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_RESUME);
1934 #ifdef IP2DEBUG_WRITE
1935 printk (KERN_DEBUG "IP2: start tx\n" );
1936 #endif
1939 static void
1940 ip2_stop ( PTTY tty )
1942 i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
1944 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_SUSPEND);
1945 #ifdef IP2DEBUG_WRITE
1946 printk (KERN_DEBUG "IP2: stop tx\n" );
1947 #endif
1950 /******************************************************************************/
1951 /* Device Ioctl Section */
1952 /******************************************************************************/
1954 /******************************************************************************/
1955 /* Function: ip2_ioctl() */
1956 /* Parameters: Pointer to tty structure */
1957 /* Pointer to file structure */
1958 /* Command */
1959 /* Argument */
1960 /* Returns: Success or failure */
1961 /* */
1962 /* Description: */
1963 /* */
1964 /* */
1965 /******************************************************************************/
1966 static int
1967 ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
1969 i2ChanStrPtr pCh = DevTable[MINOR(tty->device)];
1970 struct async_icount cprev, cnow; /* kernel counter temps */
1971 struct serial_icounter_struct *p_cuser; /* user space */
1972 int rc = 0;
1974 if ( pCh == NULL ) {
1975 return -ENODEV;
1978 #ifdef IP2DEBUG_TRACE
1979 ip2trace (PORTN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
1980 #endif
1982 #ifdef IP2DEBUG_IOCTL
1983 printk(KERN_DEBUG "IP2: ioctl cmd (%x), arg (%lx)\n", cmd, arg );
1984 #endif
1986 switch(cmd) {
1987 case TIOCGSERIAL:
1988 #ifdef IP2DEBUG_TRACE
1989 ip2trace (PORTN, ITRC_IOCTL, 2, 1, rc );
1990 #endif
1991 rc = get_serial_info(pCh, (struct serial_struct *) arg);
1992 if (rc)
1993 return rc;
1994 break;
1996 case TIOCSSERIAL:
1997 #ifdef IP2DEBUG_TRACE
1998 ip2trace (PORTN, ITRC_IOCTL, 3, 1, rc );
1999 #endif
2000 rc = set_serial_info(pCh, (struct serial_struct *) arg);
2001 if (rc)
2002 return rc;
2003 break;
2005 case TCXONC:
2006 rc = tty_check_change(tty);
2007 if (rc)
2008 return rc;
2009 switch (arg) {
2010 case TCOOFF:
2011 //return -ENOIOCTLCMD;
2012 break;
2013 case TCOON:
2014 //return -ENOIOCTLCMD;
2015 break;
2016 case TCIOFF:
2017 if (STOP_CHAR(tty) != __DISABLED_CHAR) {
2018 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2019 CMD_XMIT_NOW(STOP_CHAR(tty)));
2021 break;
2022 case TCION:
2023 if (START_CHAR(tty) != __DISABLED_CHAR) {
2024 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 1,
2025 CMD_XMIT_NOW(START_CHAR(tty)));
2027 break;
2028 default:
2029 return -EINVAL;
2031 return 0;
2033 case TCSBRK: /* SVID version: non-zero arg --> no break */
2034 rc = tty_check_change(tty);
2035 #ifdef IP2DEBUG_TRACE
2036 ip2trace (PORTN, ITRC_IOCTL, 4, 1, rc );
2037 #endif
2038 if (!rc) {
2039 ip2_wait_until_sent(tty,0);
2040 if (!arg) {
2041 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SEND_BRK(250));
2042 serviceOutgoingFifo( pCh->pMyBord );
2045 break;
2047 case TCSBRKP: /* support for POSIX tcsendbreak() */
2048 rc = tty_check_change(tty);
2049 #ifdef IP2DEBUG_TRACE
2050 ip2trace (PORTN, ITRC_IOCTL, 5, 1, rc );
2051 #endif
2052 if (!rc) {
2053 ip2_wait_until_sent(tty,0);
2054 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2055 CMD_SEND_BRK(arg ? arg*100 : 250));
2056 serviceOutgoingFifo ( pCh->pMyBord );
2058 break;
2060 case TIOCGSOFTCAR:
2061 #ifdef IP2DEBUG_TRACE
2062 ip2trace (PORTN, ITRC_IOCTL, 6, 1, rc );
2063 #endif
2064 rc=put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
2065 if (rc)
2066 return rc;
2067 break;
2069 case TIOCSSOFTCAR:
2070 #ifdef IP2DEBUG_TRACE
2071 ip2trace (PORTN, ITRC_IOCTL, 7, 1, rc );
2072 #endif
2073 rc=get_user(arg,(unsigned long *) arg);
2074 if (rc)
2075 return rc;
2076 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
2077 | (arg ? CLOCAL : 0));
2079 break;
2081 case TIOCMGET:
2082 #ifdef IP2DEBUG_TRACE
2083 ip2trace (PORTN, ITRC_IOCTL, 8, 1, rc );
2084 #endif
2085 rc = get_modem_info(pCh, (unsigned int *) arg);
2086 if (rc)
2087 return rc;
2088 break;
2090 case TIOCMBIS:
2091 case TIOCMBIC:
2092 case TIOCMSET:
2093 #ifdef IP2DEBUG_TRACE
2094 ip2trace (PORTN, ITRC_IOCTL, 9, 0 );
2095 #endif
2096 rc = set_modem_info(pCh, cmd, (unsigned int *) arg);
2097 break;
2100 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - mask
2101 * passed in arg for lines of interest (use |'ed TIOCM_RNG/DSR/CD/CTS
2102 * for masking). Caller should use TIOCGICOUNT to see which one it was
2104 case TIOCMIWAIT:
2105 cprev = pCh->icount; /* note the counters on entry */
2106 for(;;) {
2107 #ifdef IP2DEBUG_TRACE
2108 ip2trace (PORTN, ITRC_IOCTL, 10, 0 );
2109 #endif
2110 interruptible_sleep_on(&pCh->delta_msr_wait);
2111 /* see if a signal did it */
2112 if (signal_pending(current)) {
2113 rc = -ERESTARTSYS;
2114 break;
2116 cnow = pCh->icount; /* atomic copy */
2117 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2118 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
2119 rc = -EIO; /* no change => rc */
2120 break;
2122 if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2123 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2124 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2125 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2126 rc = 0;
2127 break;
2129 cprev = cnow;
2131 /* NOTREACHED */
2132 break;
2135 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2136 * Return: write counters to the user passed counter struct
2137 * NB: both 1->0 and 0->1 transitions are counted except for RI where
2138 * only 0->1 is counted. The controller is quite capable of counting
2139 * both, but this done to preserve compatibility with the standard
2140 * serial driver.
2142 case TIOCGICOUNT:
2143 #ifdef IP2DEBUG_TRACE
2144 ip2trace (PORTN, ITRC_IOCTL, 11, 1, rc );
2145 #endif
2146 cnow = pCh->icount;
2147 p_cuser = (struct serial_icounter_struct *) arg;
2148 put_user(cnow.cts, &p_cuser->cts);
2149 put_user(cnow.dsr, &p_cuser->dsr);
2150 put_user(cnow.rng, &p_cuser->rng);
2151 put_user(cnow.dcd, &p_cuser->dcd);
2152 break;
2155 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
2156 * will be passed to the line discipline for it to handle.
2158 case TIOCSERCONFIG:
2159 case TIOCSERGWILD:
2160 case TIOCSERGETLSR:
2161 case TIOCSERSWILD:
2162 case TIOCSERGSTRUCT:
2163 case TIOCSERGETMULTI:
2164 case TIOCSERSETMULTI:
2166 default:
2167 #ifdef IP2DEBUG_TRACE
2168 ip2trace (PORTN, ITRC_IOCTL, 12, 0 );
2169 #endif
2170 rc = -ENOIOCTLCMD;
2171 break;
2173 #ifdef IP2DEBUG_TRACE
2174 ip2trace (PORTN, ITRC_IOCTL, ITRC_RETURN, 0 );
2175 #endif
2176 return rc;
2178 /******************************************************************************/
2179 /* Function: get_modem_info() */
2180 /* Parameters: Pointer to channel structure */
2181 /* Pointer to destination for data */
2182 /* Returns: Nothing */
2183 /* */
2184 /* Description: */
2185 /* This returns the current settings of the dataset signal inputs to the user */
2186 /* program. */
2187 /******************************************************************************/
2188 static int
2189 get_modem_info(i2ChanStrPtr pCh, unsigned int *value)
2191 unsigned short status;
2192 unsigned int result;
2193 int rc;
2195 status = pCh->dataSetIn; // snapshot settings
2196 result = ((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
2197 | ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
2198 | ((status & I2_DCD) ? TIOCM_CAR : 0)
2199 | ((status & I2_RI) ? TIOCM_RNG : 0)
2200 | ((status & I2_DSR) ? TIOCM_DSR : 0)
2201 | ((status & I2_CTS) ? TIOCM_CTS : 0);
2202 rc=put_user(result,value);
2203 return rc;
2206 /******************************************************************************/
2207 /* Function: set_modem_info() */
2208 /* Parameters: Pointer to channel structure */
2209 /* Specific ioctl command */
2210 /* Pointer to source for new settings */
2211 /* Returns: Nothing */
2212 /* */
2213 /* Description: */
2214 /* This returns the current settings of the dataset signal inputs to the user */
2215 /* program. */
2216 /******************************************************************************/
2217 static int
2218 set_modem_info(i2ChanStrPtr pCh, unsigned cmd, unsigned int *value)
2220 int rc;
2221 unsigned int arg;
2223 rc=get_user(arg,value);
2224 if (rc)
2225 return rc;
2226 switch(cmd) {
2227 case TIOCMBIS:
2228 if (arg & TIOCM_RTS) {
2229 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2230 pCh->dataSetOut |= I2_RTS;
2232 if (arg & TIOCM_DTR) {
2233 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2234 pCh->dataSetOut |= I2_DTR;
2236 break;
2237 case TIOCMBIC:
2238 if (arg & TIOCM_RTS) {
2239 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2240 pCh->dataSetOut &= ~I2_RTS;
2242 if (arg & TIOCM_DTR) {
2243 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2244 pCh->dataSetOut &= ~I2_DTR;
2246 break;
2247 case TIOCMSET:
2248 if ( (arg & TIOCM_RTS) && !(pCh->dataSetOut & I2_RTS) ) {
2249 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSUP);
2250 pCh->dataSetOut |= I2_RTS;
2251 } else if ( !(arg & TIOCM_RTS) && (pCh->dataSetOut & I2_RTS) ) {
2252 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_RTSDN);
2253 pCh->dataSetOut &= ~I2_RTS;
2255 if ( (arg & TIOCM_DTR) && !(pCh->dataSetOut & I2_DTR) ) {
2256 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRUP);
2257 pCh->dataSetOut |= I2_DTR;
2258 } else if ( !(arg & TIOCM_DTR) && (pCh->dataSetOut & I2_DTR) ) {
2259 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DTRDN);
2260 pCh->dataSetOut &= ~I2_DTR;
2262 break;
2263 default:
2264 return -EINVAL;
2266 serviceOutgoingFifo( pCh->pMyBord );
2267 return 0;
2270 /******************************************************************************/
2271 /* Function: GetSerialInfo() */
2272 /* Parameters: Pointer to channel structure */
2273 /* Pointer to old termios structure */
2274 /* Returns: Nothing */
2275 /* */
2276 /* Description: */
2277 /* This is to support the setserial command, and requires processing of the */
2278 /* standard Linux serial structure. */
2279 /******************************************************************************/
2280 static int
2281 get_serial_info ( i2ChanStrPtr pCh, struct serial_struct *retinfo )
2283 struct serial_struct tmp;
2284 int rc=0;
2286 if ( !retinfo ) {
2287 return -EFAULT;
2290 memset ( &tmp, 0, sizeof(tmp) );
2291 tmp.type = pCh->pMyBord->channelBtypes.bid_value[(pCh->port_index & (IP2_PORTS_PER_BOARD-1))/16];
2292 if (BID_HAS_654(tmp.type)) {
2293 tmp.type = PORT_16650;
2294 } else {
2295 tmp.type = PORT_CIRRUS;
2297 tmp.line = pCh->port_index;
2298 tmp.port = pCh->pMyBord->i2eBase;
2299 tmp.irq = ip2config.irq[pCh->port_index/64];
2300 tmp.flags = pCh->flags;
2301 tmp.baud_base = pCh->BaudBase;
2302 tmp.close_delay = pCh->ClosingDelay;
2303 tmp.closing_wait = pCh->ClosingWaitTime;
2304 tmp.custom_divisor = pCh->BaudDivisor;
2305 if(copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
2306 rc= -EFAULT;
2307 return rc;
2310 /******************************************************************************/
2311 /* Function: SetSerialInfo() */
2312 /* Parameters: Pointer to channel structure */
2313 /* Pointer to old termios structure */
2314 /* Returns: Nothing */
2315 /* */
2316 /* Description: */
2317 /* This function provides support for setserial, which uses the TIOCSSERIAL */
2318 /* ioctl. Not all setserial parameters are relevant. If the user attempts to */
2319 /* change the IRQ, address or type of the port the ioctl fails. */
2320 /******************************************************************************/
2321 static int
2322 set_serial_info( i2ChanStrPtr pCh, struct serial_struct *new_info )
2324 struct serial_struct ns;
2325 int old_flags, old_baud_divisor;
2326 int rc = 0;
2328 if ( !new_info ) {
2329 return -EFAULT;
2331 rc=copy_from_user(&ns, new_info, sizeof (ns) );
2332 if (rc) {
2333 return rc;
2336 * We don't allow setserial to change IRQ, board address, type or baud
2337 * base. Also line nunber as such is meaningless but we use it for our
2338 * array index so it is fixed also.
2340 if ( ns.irq != ip2config.irq
2341 || (int) ns.port != ((int) pCh->pMyBord->i2eBase)
2342 || ns.baud_base != pCh->BaudBase
2343 || ns.line != pCh->port_index ) {
2344 return -EINVAL;
2347 old_flags = pCh->flags;
2348 old_baud_divisor = pCh->BaudDivisor;
2350 if ( !suser() ) {
2351 if ( ( ns.close_delay != pCh->ClosingDelay ) ||
2352 ( (ns.flags & ~ASYNC_USR_MASK) !=
2353 (pCh->flags & ~ASYNC_USR_MASK) ) ) {
2354 return -EPERM;
2357 pCh->flags = (pCh->flags & ~ASYNC_USR_MASK) |
2358 (ns.flags & ASYNC_USR_MASK);
2359 pCh->BaudDivisor = ns.custom_divisor;
2360 } else {
2361 pCh->flags = (pCh->flags & ~ASYNC_FLAGS) |
2362 (ns.flags & ASYNC_FLAGS);
2363 pCh->BaudDivisor = ns.custom_divisor;
2364 pCh->ClosingDelay = ns.close_delay * HZ/100;
2365 pCh->ClosingWaitTime = ns.closing_wait * HZ/100;
2368 if ( ( (old_flags & ASYNC_SPD_MASK) != (pCh->flags & ASYNC_SPD_MASK) )
2369 || (old_baud_divisor != pCh->BaudDivisor) ) {
2370 // Invalidate speed and reset parameters
2371 set_params( pCh, NULL );
2374 return rc;
2377 /******************************************************************************/
2378 /* Function: ip2_set_termios() */
2379 /* Parameters: Pointer to tty structure */
2380 /* Pointer to old termios structure */
2381 /* Returns: Nothing */
2382 /* */
2383 /* Description: */
2384 /* */
2385 /* */
2386 /******************************************************************************/
2387 static void
2388 ip2_set_termios( PTTY tty, struct termios *old_termios )
2390 i2ChanStrPtr pCh = (i2ChanStrPtr)tty->driver_data;
2392 #ifdef IP2DEBUG_IOCTL
2393 printk (KERN_DEBUG "IP2: set termios %p\n", old_termios );
2394 #endif
2396 set_params( pCh, old_termios );
2399 /******************************************************************************/
2400 /* Function: ip2_set_line_discipline() */
2401 /* Parameters: Pointer to tty structure */
2402 /* Returns: Nothing */
2403 /* */
2404 /* Description: Does nothing */
2405 /* */
2406 /* */
2407 /******************************************************************************/
2408 static void
2409 ip2_set_line_discipline ( PTTY tty )
2411 #ifdef IP2DEBUG_IOCTL
2412 printk (KERN_DEBUG "IP2: set line discipline\n" );
2413 #endif
2414 #ifdef IP2DEBUG_TRACE
2415 ip2trace (((i2ChanStrPtr)tty->driver_data)->port_index, ITRC_IOCTL, 16, 0 );
2416 #endif
2419 /******************************************************************************/
2420 /* Function: SetLine Characteristics() */
2421 /* Parameters: Pointer to channel structure */
2422 /* Returns: Nothing */
2423 /* */
2424 /* Description: */
2425 /* This routine is called to update the channel structure with the new line */
2426 /* characteristics, and send the appropriate commands to the board when they */
2427 /* change. */
2428 /******************************************************************************/
2429 static void
2430 set_params( i2ChanStrPtr pCh, struct termios *o_tios )
2432 tcflag_t cflag, iflag, lflag;
2433 char stop_char, start_char;
2434 struct termios dummy;
2436 lflag = pCh->pTTY->termios->c_lflag;
2437 cflag = pCh->pTTY->termios->c_cflag;
2438 iflag = pCh->pTTY->termios->c_iflag;
2440 if (o_tios == NULL) {
2441 dummy.c_lflag = ~lflag;
2442 dummy.c_cflag = ~cflag;
2443 dummy.c_iflag = ~iflag;
2444 o_tios = &dummy;
2448 switch ( cflag & CBAUD ) {
2449 case B0:
2450 i2QueueCommands( PTYPE_BYPASS, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN);
2451 pCh->dataSetOut &= ~(I2_DTR | I2_RTS);
2452 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25));
2453 pCh->pTTY->termios->c_cflag |= (CBAUD & o_tios->c_cflag);
2454 goto service_it;
2455 break;
2456 case B38400:
2458 * This is the speed that is overloaded with all the other high
2459 * speeds, depending upon the flag settings.
2461 if ( ( pCh->flags & ASYNC_SPD_MASK ) == ASYNC_SPD_HI ) {
2462 pCh->speed = CBR_57600;
2463 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI ) {
2464 pCh->speed = CBR_115200;
2465 } else if ( (pCh->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST ) {
2466 pCh->speed = CBR_C1;
2467 } else {
2468 pCh->speed = CBR_38400;
2470 break;
2471 case B50: pCh->speed = CBR_50; break;
2472 case B75: pCh->speed = CBR_75; break;
2473 case B110: pCh->speed = CBR_110; break;
2474 case B134: pCh->speed = CBR_134; break;
2475 case B150: pCh->speed = CBR_150; break;
2476 case B200: pCh->speed = CBR_200; break;
2477 case B300: pCh->speed = CBR_300; break;
2478 case B600: pCh->speed = CBR_600; break;
2479 case B1200: pCh->speed = CBR_1200; break;
2480 case B1800: pCh->speed = CBR_1800; break;
2481 case B2400: pCh->speed = CBR_2400; break;
2482 case B4800: pCh->speed = CBR_4800; break;
2483 case B9600: pCh->speed = CBR_9600; break;
2484 case B19200: pCh->speed = CBR_19200; break;
2485 case B57600: pCh->speed = CBR_57600; break;
2486 case B115200: pCh->speed = CBR_115200; break;
2487 case B153600: pCh->speed = CBR_153600; break;
2488 case B230400: pCh->speed = CBR_230400; break;
2489 case B307200: pCh->speed = CBR_307200; break;
2490 case B460800: pCh->speed = CBR_460800; break;
2491 case B921600: pCh->speed = CBR_921600; break;
2492 default: pCh->speed = CBR_9600; break;
2494 if ( pCh->speed == CBR_C1 ) {
2495 // Process the custom speed parameters.
2496 int bps = pCh->BaudBase / pCh->BaudDivisor;
2497 if ( bps == 921600 ) {
2498 pCh->speed = CBR_921600;
2499 } else {
2500 bps = bps/10;
2501 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_BAUD_DEF1(bps) );
2504 i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_SETBAUD(pCh->speed));
2506 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
2507 pCh->dataSetOut |= (I2_DTR | I2_RTS);
2509 if ( (CSTOPB & cflag) ^ (CSTOPB & o_tios->c_cflag))
2511 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2512 CMD_SETSTOP( ( cflag & CSTOPB ) ? CST_2 : CST_1));
2514 if (((PARENB|PARODD) & cflag) ^ ((PARENB|PARODD) & o_tios->c_cflag))
2516 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1,
2517 CMD_SETPAR(
2518 (cflag & PARENB ? (cflag & PARODD ? CSP_OD : CSP_EV) : CSP_NP)
2522 /* byte size and parity */
2523 if ( (CSIZE & cflag)^(CSIZE & o_tios->c_cflag))
2525 int datasize;
2526 switch ( cflag & CSIZE ) {
2527 case CS5: datasize = CSZ_5; break;
2528 case CS6: datasize = CSZ_6; break;
2529 case CS7: datasize = CSZ_7; break;
2530 case CS8: datasize = CSZ_8; break;
2531 default: datasize = CSZ_5; break; /* as per serial.c */
2533 i2QueueCommands ( PTYPE_INLINE, pCh, 100, 1, CMD_SETBITS(datasize) );
2535 /* Process CTS flow control flag setting */
2536 if ( (cflag & CRTSCTS) ) {
2537 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2538 2, CMD_CTSFL_ENAB, CMD_RTSFL_ENAB);
2539 } else {
2540 i2QueueCommands(PTYPE_INLINE, pCh, 100,
2541 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
2544 // Process XON/XOFF flow control flags settings
2546 stop_char = STOP_CHAR(pCh->pTTY);
2547 start_char = START_CHAR(pCh->pTTY);
2549 //////////// can't be \000
2550 if (stop_char == __DISABLED_CHAR )
2552 stop_char = ~__DISABLED_CHAR;
2554 if (start_char == __DISABLED_CHAR )
2556 start_char = ~__DISABLED_CHAR;
2558 /////////////////////////////////
2560 if ( o_tios->c_cc[VSTART] != start_char )
2562 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXON(start_char));
2563 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXON(start_char));
2565 if ( o_tios->c_cc[VSTOP] != stop_char )
2567 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, CMD_DEF_IXOFF(stop_char));
2568 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DEF_OXOFF(stop_char));
2570 if (stop_char == __DISABLED_CHAR )
2572 stop_char = ~__DISABLED_CHAR; //TEST123
2573 goto no_xoff;
2575 if ((iflag & (IXOFF))^(o_tios->c_iflag & (IXOFF)))
2577 if ( iflag & IXOFF ) { // Enable XOFF output flow control
2578 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_XON));
2579 } else { // Disable XOFF output flow control
2580 no_xoff:
2581 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_OXON_OPT(COX_NONE));
2584 if (start_char == __DISABLED_CHAR )
2586 goto no_xon;
2588 if ((iflag & (IXON|IXANY)) ^ (o_tios->c_iflag & (IXON|IXANY)))
2590 if ( iflag & IXON ) {
2591 if ( iflag & IXANY ) { // Enable XON/XANY output flow control
2592 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XANY));
2593 } else { // Enable XON output flow control
2594 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_XON));
2596 } else { // Disable XON output flow control
2597 no_xon:
2598 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_IXON_OPT(CIX_NONE));
2601 if ( (iflag & ISTRIP) ^ ( o_tios->c_iflag & (ISTRIP)) )
2603 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2604 CMD_ISTRIP_OPT((iflag & ISTRIP ? 1 : 0)));
2606 if ( (iflag & INPCK) ^ ( o_tios->c_iflag & (INPCK)) )
2608 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1,
2609 CMD_PARCHK((iflag & INPCK) ? CPK_ENAB : CPK_DSAB));
2612 if ( (iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR))
2613 ^ ( o_tios->c_iflag & (IGNBRK|PARMRK|BRKINT|IGNPAR)) )
2615 char brkrpt = 0;
2616 char parrpt = 0;
2618 if ( iflag & IGNBRK ) { /* Ignore breaks altogether */
2619 /* Ignore breaks altogether */
2620 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_NREP);
2621 } else {
2622 if ( iflag & BRKINT ) {
2623 if ( iflag & PARMRK ) {
2624 brkrpt = 0x0a; // exception an inline triple
2625 } else {
2626 brkrpt = 0x1a; // exception and NULL
2628 brkrpt |= 0x04; // flush input
2629 } else {
2630 if ( iflag & PARMRK ) {
2631 brkrpt = 0x0b; //POSIX triple \0377 \0 \0
2632 } else {
2633 brkrpt = 0x01; // Null only
2636 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_BRK_REP(brkrpt));
2639 if (iflag & IGNPAR) {
2640 parrpt = 0x20;
2641 /* would be 2 for not cirrus bug */
2642 /* would be 0x20 cept for cirrus bug */
2643 } else {
2644 if ( iflag & PARMRK ) {
2646 * Replace error characters with 3-byte sequence (\0377,\0,char)
2648 parrpt = 0x04 ;
2649 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_ISTRIP_OPT((char)0));
2650 } else {
2651 parrpt = 0x03;
2654 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_SET_ERROR(parrpt));
2656 if (cflag & CLOCAL) {
2657 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_NREP);
2658 pCh->flags &= ~ASYNC_CHECK_CD;
2659 } else {
2660 i2QueueCommands(PTYPE_INLINE, pCh, 100, 1, CMD_DCD_REP);
2661 pCh->flags |= ASYNC_CHECK_CD;
2664 #ifdef XXX
2665 do_flags_thing: // This is a test, we don't do the flags thing
2667 if ( (cflag & CRTSCTS) ) {
2668 cflag |= 014000000000;
2670 i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1,
2671 CMD_UNIX_FLAGS(iflag,cflag,lflag));
2672 #endif
2674 service_it:
2675 i2DrainOutput( pCh, 100 );
2678 /******************************************************************************/
2679 /* IPL Device Section */
2680 /******************************************************************************/
2682 /******************************************************************************/
2683 /* Function: ip2_ipl_read() */
2684 /* Parameters: Pointer to device inode */
2685 /* Pointer to file structure */
2686 /* Pointer to data */
2687 /* Number of bytes to read */
2688 /* Returns: Success or failure */
2689 /* */
2690 /* Description: Ugly */
2691 /* */
2692 /* */
2693 /******************************************************************************/
2695 static
2696 ssize_t
2697 ip2_ipl_read(struct file *pFile, char *pData, size_t count, loff_t *off )
2699 unsigned int minor = MINOR( pFile->f_dentry->d_inode->i_rdev );
2700 int rc = 0;
2702 #ifdef IP2DEBUG_IPL
2703 printk (KERN_DEBUG "IP2IPL: read %p, %d bytes\n", pData, count );
2704 #endif
2706 switch( minor ) {
2707 case 0: // IPL device
2708 rc = -EINVAL;
2709 break;
2710 case 1: // Status dump
2711 rc = -EINVAL;
2712 break;
2713 case 2: // Ping device
2714 rc = -EINVAL;
2715 break;
2716 case 3: // Trace device
2717 rc = DumpTraceBuffer ( pData, count );
2718 break;
2719 case 4: // Trace device
2720 rc = DumpFifoBuffer ( pData, count );
2721 break;
2722 default:
2723 rc = -ENODEV;
2724 break;
2726 return rc;
2729 static int
2730 DumpFifoBuffer ( char *pData, int count )
2732 #ifdef DEBUG_FIFO
2733 int rc=0;
2734 if(copy_to_user(pData, DBGBuf, count))
2735 rc=-EFAULT;
2737 printk(KERN_DEBUG "Last index %d\n", I );
2739 return count;
2740 #endif /* DEBUG_FIFO */
2741 return 0;
2744 static int
2745 DumpTraceBuffer ( char *pData, int count )
2747 #ifdef IP2DEBUG_TRACE
2748 int rc;
2749 int dumpcount;
2750 int chunk;
2751 int *pIndex = (int*)pData;
2753 if ( count < (sizeof(int) * 6) ) {
2754 return -EIO;
2756 put_user(tracewrap, pIndex );
2757 put_user(TRACEMAX, ++pIndex );
2758 put_user(tracestrip, ++pIndex );
2759 put_user(tracestuff, ++pIndex );
2760 pData += sizeof(int) * 6;
2761 count -= sizeof(int) * 6;
2763 dumpcount = tracestuff - tracestrip;
2764 if ( dumpcount < 0 ) {
2765 dumpcount += TRACEMAX;
2767 if ( dumpcount > count ) {
2768 dumpcount = count;
2770 chunk = TRACEMAX - tracestrip;
2771 if ( dumpcount > chunk ) {
2772 rc=copy_to_user(pData, &tracebuf[tracestrip],
2773 chunk * sizeof(tracebuf[0]) )?-EFAULT:0;
2774 pData += chunk * sizeof(tracebuf[0]);
2775 tracestrip = 0;
2776 chunk = dumpcount - chunk;
2777 } else {
2778 chunk = dumpcount;
2780 rc=copy_to_user(pData, &tracebuf[tracestrip],
2781 chunk * sizeof(tracebuf[0]) )?-EFAULT:0
2782 tracestrip += chunk;
2783 tracewrap = 0;
2785 put_user(tracestrip, ++pIndex );
2786 put_user(tracestuff, ++pIndex );
2788 return dumpcount;
2789 #else
2790 return 0;
2791 #endif
2794 /******************************************************************************/
2795 /* Function: ip2_ipl_write() */
2796 /* Parameters: */
2797 /* Pointer to file structure */
2798 /* Pointer to data */
2799 /* Number of bytes to write */
2800 /* Returns: Success or failure */
2801 /* */
2802 /* Description: */
2803 /* */
2804 /* */
2805 /******************************************************************************/
2806 static ssize_t
2807 ip2_ipl_write(struct file *pFile, const char *pData, size_t count, loff_t *off)
2809 #ifdef IP2DEBUG_IPL
2810 printk (KERN_DEBUG "IP2IPL: write %p, %d bytes\n", pData, count );
2811 #endif
2812 return 0;
2815 /******************************************************************************/
2816 /* Function: ip2_ipl_ioctl() */
2817 /* Parameters: Pointer to device inode */
2818 /* Pointer to file structure */
2819 /* Command */
2820 /* Argument */
2821 /* Returns: Success or failure */
2822 /* */
2823 /* Description: */
2824 /* */
2825 /* */
2826 /******************************************************************************/
2827 static int
2828 ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
2830 unsigned int iplminor = MINOR(pInode->i_rdev);
2831 int rc = 0;
2832 ULONG *pIndex = (ULONG*)arg;
2833 i2eBordStrPtr pB = i2BoardPtrTable[iplminor / 4];
2834 i2ChanStrPtr pCh;
2836 #ifdef IP2DEBUG_IPL
2837 printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
2838 #endif
2840 switch ( iplminor ) {
2841 case 0: // IPL device
2842 rc = -EINVAL;
2843 break;
2844 case 1: // Status dump
2845 case 5:
2846 case 9:
2847 case 13:
2848 switch ( cmd ) {
2849 case 64: /* Driver - ip2stat */
2850 put_user(ref_count, pIndex++ );
2851 put_user(irq_counter, pIndex++ );
2852 put_user(bh_counter, pIndex++ );
2853 break;
2855 case 65: /* Board - ip2stat */
2856 if ( pB ) {
2857 if(copy_to_user((char*)arg, (char*)pB, sizeof(i2eBordStr) ))
2858 rc=-EFAULT;
2859 put_user(INB(pB->i2eStatus),
2860 (ULONG*)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
2861 } else {
2862 rc = -ENODEV;
2864 break;
2866 default:
2867 pCh = DevTable[cmd];
2868 if ( pCh )
2870 if(copy_to_user((char*)arg, (char*)pCh, sizeof(i2ChanStr) ))
2871 rc = -EFAULT;
2872 } else {
2873 rc = cmd < 64 ? -ENODEV : -EINVAL;
2876 break;
2878 case 2: // Ping device
2879 rc = -EINVAL;
2880 break;
2881 case 3: // Trace device
2882 if ( cmd == 1 ) {
2883 put_user(iiSendPendingMail, pIndex++ );
2884 put_user(i2InitChannels, pIndex++ );
2885 put_user(i2QueueNeeds, pIndex++ );
2886 put_user(i2QueueCommands, pIndex++ );
2887 put_user(i2GetStatus, pIndex++ );
2888 put_user(i2Input, pIndex++ );
2889 put_user(i2InputFlush, pIndex++ );
2890 put_user(i2Output, pIndex++ );
2891 put_user(i2FlushOutput, pIndex++ );
2892 put_user(i2DrainWakeup, pIndex++ );
2893 put_user(i2DrainOutput, pIndex++ );
2894 put_user(i2OutputFree, pIndex++ );
2895 put_user(i2StripFifo, pIndex++ );
2896 put_user(i2StuffFifoBypass, pIndex++ );
2897 put_user(i2StuffFifoFlow, pIndex++ );
2898 put_user(i2StuffFifoInline, pIndex++ );
2899 put_user(i2ServiceBoard, pIndex++ );
2900 put_user(serviceOutgoingFifo, pIndex++ );
2901 // put_user(ip2_init, pIndex++ );
2902 put_user(ip2_init_board, pIndex++ );
2903 put_user(find_eisa_board, pIndex++ );
2904 put_user(set_irq, pIndex++ );
2905 put_user(ip2_interrupt, pIndex++ );
2906 put_user(ip2_poll, pIndex++ );
2907 put_user(service_all_boards, pIndex++ );
2908 put_user(do_input, pIndex++ );
2909 put_user(do_status, pIndex++ );
2910 #ifndef IP2DEBUG_OPEN
2911 put_user(0, pIndex++ );
2912 #else
2913 put_user(open_sanity_check, pIndex++ );
2914 #endif
2915 put_user(ip2_open, pIndex++ );
2916 put_user(ip2_close, pIndex++ );
2917 put_user(ip2_hangup, pIndex++ );
2918 put_user(ip2_write, pIndex++ );
2919 put_user(ip2_putchar, pIndex++ );
2920 put_user(ip2_flush_chars, pIndex++ );
2921 put_user(ip2_write_room, pIndex++ );
2922 put_user(ip2_chars_in_buf, pIndex++ );
2923 put_user(ip2_flush_buffer, pIndex++ );
2925 //put_user(ip2_wait_until_sent, pIndex++ );
2926 put_user(0, pIndex++ );
2928 put_user(ip2_throttle, pIndex++ );
2929 put_user(ip2_unthrottle, pIndex++ );
2930 put_user(ip2_ioctl, pIndex++ );
2931 put_user(get_modem_info, pIndex++ );
2932 put_user(set_modem_info, pIndex++ );
2933 put_user(get_serial_info, pIndex++ );
2934 put_user(set_serial_info, pIndex++ );
2935 put_user(ip2_set_termios, pIndex++ );
2936 put_user(ip2_set_line_discipline, pIndex++ );
2937 put_user(set_params, pIndex++ );
2938 } else {
2939 rc = -EINVAL;
2942 break;
2944 default:
2945 rc = -ENODEV;
2946 break;
2948 return rc;
2951 /******************************************************************************/
2952 /* Function: ip2_ipl_open() */
2953 /* Parameters: Pointer to device inode */
2954 /* Pointer to file structure */
2955 /* Returns: Success or failure */
2956 /* */
2957 /* Description: */
2958 /* */
2959 /* */
2960 /******************************************************************************/
2961 static int
2962 ip2_ipl_open( struct inode *pInode, struct file *pFile )
2964 unsigned int iplminor = MINOR(pInode->i_rdev);
2965 i2eBordStrPtr pB;
2966 i2ChanStrPtr pCh;
2968 #ifdef IP2DEBUG_IPL
2969 printk (KERN_DEBUG "IP2IPL: open\n" );
2970 #endif
2972 //MOD_INC_USE_COUNT; // Needs close entry with decrement.
2974 switch(iplminor) {
2975 // These are the IPL devices
2976 case 0:
2977 case 4:
2978 case 8:
2979 case 12:
2980 break;
2982 // These are the status devices
2983 case 1:
2984 case 5:
2985 case 9:
2986 case 13:
2987 break;
2989 // These are the debug devices
2990 case 2:
2991 case 6:
2992 case 10:
2993 case 14:
2994 pB = i2BoardPtrTable[iplminor / 4];
2995 pCh = (i2ChanStrPtr) pB->i2eChannelPtr;
2996 break;
2998 // This is the trace device
2999 case 3:
3000 break;
3002 return 0;
3004 /******************************************************************************/
3005 /* Function: ip2_read_procmem */
3006 /* Parameters: */
3007 /* */
3008 /* Returns: Length of output */
3009 /* */
3010 /* Description: */
3011 /* Supplies some driver operating parameters */
3012 /* Not real useful unless your debugging the fifo */
3013 /* */
3014 /******************************************************************************/
3016 #define LIMIT (PAGE_SIZE - 120)
3019 ip2_read_procmem(char *buf, char **start, off_t offset, int len, int unused)
3021 i2eBordStrPtr pB;
3022 i2ChanStrPtr pCh;
3023 PTTY tty;
3024 int i;
3026 len = 0;
3028 #define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
3029 #define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
3030 #define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
3032 len += sprintf(buf+len,"\n");
3034 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3035 pB = i2BoardPtrTable[i];
3036 if ( pB ) {
3037 len += sprintf(buf+len,"board %d:\n",i);
3038 len += sprintf(buf+len,"\tFifo rem: %d mty: %x outM %x\n",
3039 pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
3043 len += sprintf(buf+len,"#: tty flags, port flags, cflags, iflags\n");
3044 for (i=0; i < IP2_MAX_PORTS; i++) {
3045 if (len > LIMIT)
3046 break;
3047 pCh = DevTable[i];
3048 if (pCh) {
3049 tty = pCh->pTTY;
3050 if (tty && tty->count) {
3051 len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags,
3052 tty->termios->c_cflag,tty->termios->c_iflag);
3054 len += sprintf(buf+len,FMTLIN2,
3055 pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
3056 len += sprintf(buf+len,FMTLIN3,pCh->infl.asof,pCh->infl.room);
3060 return len;
3064 * This is the handler for /proc/tty/driver/ip2
3066 * This stretch of code has been largely plagerized from at least three
3067 * different sources including ip2mkdev.c and a couple of other drivers.
3068 * The bugs are all mine. :-) =mhw=
3070 int ip2_read_proc(char *page, char **start, off_t off,
3071 int count, int *eof, void *data)
3073 int i, j, box;
3074 int len = 0;
3075 int boxes = 0;
3076 int ports = 0;
3077 int tports = 0;
3078 off_t begin = 0;
3079 i2eBordStrPtr pB;
3081 len += sprintf(page, "ip2info: 1.0 driver: %s\n", pcVersion );
3082 len += sprintf(page+len, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n",
3083 IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR,
3084 IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX);
3086 for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
3087 /* This need to be reset for a board by board count... */
3088 boxes = 0;
3089 pB = i2BoardPtrTable[i];
3090 if( pB ) {
3091 switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED )
3093 case POR_ID_FIIEX:
3094 len += sprintf( page+len, "Board %d: EX ports=", i );
3095 for( box = 0; box < ABS_MAX_BOXES; ++box )
3097 ports = 0;
3099 if( pB->i2eChannelMap[box] != 0 ) ++boxes;
3100 for( j = 0; j < ABS_BIGGEST_BOX; ++j )
3102 if( pB->i2eChannelMap[box] & 1<< j ) {
3103 ++ports;
3106 len += sprintf( page+len, "%d,", ports );
3107 tports += ports;
3110 --len; /* Backup over that last comma */
3112 len += sprintf( page+len, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8 );
3113 break;
3115 case POR_ID_II_4:
3116 len += sprintf(page+len, "Board %d: ISA-4 ports=4 boxes=1", i );
3117 tports = ports = 4;
3118 break;
3120 case POR_ID_II_8:
3121 len += sprintf(page+len, "Board %d: ISA-8-std ports=8 boxes=1", i );
3122 tports = ports = 8;
3123 break;
3125 case POR_ID_II_8R:
3126 len += sprintf(page+len, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i );
3127 tports = ports = 8;
3128 break;
3130 default:
3131 len += sprintf(page+len, "Board %d: unknown", i );
3132 /* Don't try and probe for minor numbers */
3133 tports = ports = 0;
3136 } else {
3137 /* Don't try and probe for minor numbers */
3138 len += sprintf(page+len, "Board %d: vacant", i );
3139 tports = ports = 0;
3142 if( tports ) {
3143 len += sprintf(page+len, " minors=" );
3145 for ( box = 0; box < ABS_MAX_BOXES; ++box )
3147 for ( j = 0; j < ABS_BIGGEST_BOX; ++j )
3149 if ( pB->i2eChannelMap[box] & (1 << j) )
3151 len += sprintf (page+len,"%d,",
3152 j + ABS_BIGGEST_BOX *
3153 (box+i*ABS_MAX_BOXES));
3158 page[ len - 1 ] = '\n'; /* Overwrite that last comma */
3159 } else {
3160 len += sprintf (page+len,"\n" );
3163 if (len+begin > off+count)
3164 break;
3165 if (len+begin < off) {
3166 begin += len;
3167 len = 0;
3171 if (i >= IP2_MAX_BOARDS)
3172 *eof = 1;
3173 if (off >= len+begin)
3174 return 0;
3176 *start = page + (begin-off);
3177 return ((count < begin+len-off) ? count : begin+len-off);
3180 /******************************************************************************/
3181 /* Function: ip2trace() */
3182 /* Parameters: Value to add to trace buffer */
3183 /* Returns: Nothing */
3184 /* */
3185 /* Description: */
3186 /* */
3187 /* */
3188 /******************************************************************************/
3189 void
3190 ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned long codes, ...)
3192 #ifdef IP2DEBUG_TRACE
3193 long flags;
3194 unsigned long *pCode = &codes;
3195 union ip2breadcrumb bc;
3196 i2ChanStrPtr pCh;
3199 tracebuf[tracestuff++] = jiffies;
3200 if ( tracestuff == TRACEMAX ) {
3201 tracestuff = 0;
3203 if ( tracestuff == tracestrip ) {
3204 if ( ++tracestrip == TRACEMAX ) {
3205 tracestrip = 0;
3207 ++tracewrap;
3210 bc.hdr.port = 0xff & pn;
3211 bc.hdr.cat = cat;
3212 bc.hdr.codes = (unsigned char)( codes & 0xff );
3213 bc.hdr.label = label;
3214 tracebuf[tracestuff++] = bc.value;
3216 for (;;) {
3217 if ( tracestuff == TRACEMAX ) {
3218 tracestuff = 0;
3220 if ( tracestuff == tracestrip ) {
3221 if ( ++tracestrip == TRACEMAX ) {
3222 tracestrip = 0;
3224 ++tracewrap;
3227 if ( !codes-- )
3228 break;
3230 tracebuf[tracestuff++] = *++pCode;
3232 #endif