1a6afd9f3SGreg Kroah-Hartman /* 2a6afd9f3SGreg Kroah-Hartman * Serial driver for the amiga builtin port. 3a6afd9f3SGreg Kroah-Hartman * 4a6afd9f3SGreg Kroah-Hartman * This code was created by taking serial.c version 4.30 from kernel 5a6afd9f3SGreg Kroah-Hartman * release 2.3.22, replacing all hardware related stuff with the 6a6afd9f3SGreg Kroah-Hartman * corresponding amiga hardware actions, and removing all irrelevant 7a6afd9f3SGreg Kroah-Hartman * code. As a consequence, it uses many of the constants and names 8a6afd9f3SGreg Kroah-Hartman * associated with the registers and bits of 16550 compatible UARTS - 9a6afd9f3SGreg Kroah-Hartman * but only to keep track of status, etc in the state variables. It 10a6afd9f3SGreg Kroah-Hartman * was done this was to make it easier to keep the code in line with 11a6afd9f3SGreg Kroah-Hartman * (non hardware specific) changes to serial.c. 12a6afd9f3SGreg Kroah-Hartman * 13a6afd9f3SGreg Kroah-Hartman * The port is registered with the tty driver as minor device 64, and 14a6afd9f3SGreg Kroah-Hartman * therefore other ports should should only use 65 upwards. 15a6afd9f3SGreg Kroah-Hartman * 16a6afd9f3SGreg Kroah-Hartman * Richard Lucock 28/12/99 17a6afd9f3SGreg Kroah-Hartman * 18a6afd9f3SGreg Kroah-Hartman * Copyright (C) 1991, 1992 Linus Torvalds 19a6afd9f3SGreg Kroah-Hartman * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 20a6afd9f3SGreg Kroah-Hartman * 1998, 1999 Theodore Ts'o 21a6afd9f3SGreg Kroah-Hartman * 22a6afd9f3SGreg Kroah-Hartman */ 23a6afd9f3SGreg Kroah-Hartman 24a6afd9f3SGreg Kroah-Hartman /* 25a6afd9f3SGreg Kroah-Hartman * Serial driver configuration section. Here are the various options: 26a6afd9f3SGreg Kroah-Hartman * 27a6afd9f3SGreg Kroah-Hartman * SERIAL_PARANOIA_CHECK 28a6afd9f3SGreg Kroah-Hartman * Check the magic number for the async_structure where 29a6afd9f3SGreg Kroah-Hartman * ever possible. 30a6afd9f3SGreg Kroah-Hartman */ 31a6afd9f3SGreg Kroah-Hartman 32a6afd9f3SGreg Kroah-Hartman #include <linux/delay.h> 33a6afd9f3SGreg Kroah-Hartman 34a6afd9f3SGreg Kroah-Hartman #undef SERIAL_PARANOIA_CHECK 35a6afd9f3SGreg Kroah-Hartman #define SERIAL_DO_RESTART 36a6afd9f3SGreg Kroah-Hartman 37a6afd9f3SGreg Kroah-Hartman /* Set of debugging defines */ 38a6afd9f3SGreg Kroah-Hartman 39a6afd9f3SGreg Kroah-Hartman #undef SERIAL_DEBUG_INTR 40a6afd9f3SGreg Kroah-Hartman #undef SERIAL_DEBUG_OPEN 41a6afd9f3SGreg Kroah-Hartman #undef SERIAL_DEBUG_FLOW 42a6afd9f3SGreg Kroah-Hartman #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT 43a6afd9f3SGreg Kroah-Hartman 44a6afd9f3SGreg Kroah-Hartman /* Sanity checks */ 45a6afd9f3SGreg Kroah-Hartman 46a6afd9f3SGreg Kroah-Hartman #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) 47a6afd9f3SGreg Kroah-Hartman #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ 48916b7656SJiri Slaby tty->name, (info->flags), serial_driver->refcount,info->count,tty->count,s) 49a6afd9f3SGreg Kroah-Hartman #else 50a6afd9f3SGreg Kroah-Hartman #define DBG_CNT(s) 51a6afd9f3SGreg Kroah-Hartman #endif 52a6afd9f3SGreg Kroah-Hartman 53a6afd9f3SGreg Kroah-Hartman /* 54a6afd9f3SGreg Kroah-Hartman * End of serial driver configuration section. 55a6afd9f3SGreg Kroah-Hartman */ 56a6afd9f3SGreg Kroah-Hartman 57a6afd9f3SGreg Kroah-Hartman #include <linux/module.h> 58a6afd9f3SGreg Kroah-Hartman 59a6afd9f3SGreg Kroah-Hartman #include <linux/types.h> 60a6afd9f3SGreg Kroah-Hartman #include <linux/serial.h> 61a6afd9f3SGreg Kroah-Hartman #include <linux/serialP.h> 62a6afd9f3SGreg Kroah-Hartman #include <linux/serial_reg.h> 63a6afd9f3SGreg Kroah-Hartman static char *serial_version = "4.30"; 64a6afd9f3SGreg Kroah-Hartman 65a6afd9f3SGreg Kroah-Hartman #include <linux/errno.h> 66a6afd9f3SGreg Kroah-Hartman #include <linux/signal.h> 67a6afd9f3SGreg Kroah-Hartman #include <linux/sched.h> 68a6afd9f3SGreg Kroah-Hartman #include <linux/kernel.h> 69a6afd9f3SGreg Kroah-Hartman #include <linux/timer.h> 70a6afd9f3SGreg Kroah-Hartman #include <linux/interrupt.h> 71a6afd9f3SGreg Kroah-Hartman #include <linux/tty.h> 72a6afd9f3SGreg Kroah-Hartman #include <linux/tty_flip.h> 73a6afd9f3SGreg Kroah-Hartman #include <linux/console.h> 74a6afd9f3SGreg Kroah-Hartman #include <linux/major.h> 75a6afd9f3SGreg Kroah-Hartman #include <linux/string.h> 76a6afd9f3SGreg Kroah-Hartman #include <linux/fcntl.h> 77a6afd9f3SGreg Kroah-Hartman #include <linux/ptrace.h> 78a6afd9f3SGreg Kroah-Hartman #include <linux/ioport.h> 79a6afd9f3SGreg Kroah-Hartman #include <linux/mm.h> 80a6afd9f3SGreg Kroah-Hartman #include <linux/seq_file.h> 81a6afd9f3SGreg Kroah-Hartman #include <linux/slab.h> 82a6afd9f3SGreg Kroah-Hartman #include <linux/init.h> 83a6afd9f3SGreg Kroah-Hartman #include <linux/bitops.h> 84a6afd9f3SGreg Kroah-Hartman #include <linux/platform_device.h> 85a6afd9f3SGreg Kroah-Hartman 86a6afd9f3SGreg Kroah-Hartman #include <asm/setup.h> 87a6afd9f3SGreg Kroah-Hartman 88a6afd9f3SGreg Kroah-Hartman #include <asm/system.h> 89a6afd9f3SGreg Kroah-Hartman 90a6afd9f3SGreg Kroah-Hartman #include <asm/irq.h> 91a6afd9f3SGreg Kroah-Hartman 92a6afd9f3SGreg Kroah-Hartman #include <asm/amigahw.h> 93a6afd9f3SGreg Kroah-Hartman #include <asm/amigaints.h> 94a6afd9f3SGreg Kroah-Hartman 95a6afd9f3SGreg Kroah-Hartman #define custom amiga_custom 96a6afd9f3SGreg Kroah-Hartman static char *serial_name = "Amiga-builtin serial driver"; 97a6afd9f3SGreg Kroah-Hartman 98a6afd9f3SGreg Kroah-Hartman static struct tty_driver *serial_driver; 99a6afd9f3SGreg Kroah-Hartman 100a6afd9f3SGreg Kroah-Hartman /* number of characters left in xmit buffer before we ask for more */ 101a6afd9f3SGreg Kroah-Hartman #define WAKEUP_CHARS 256 102a6afd9f3SGreg Kroah-Hartman 103a6afd9f3SGreg Kroah-Hartman static unsigned char current_ctl_bits; 104a6afd9f3SGreg Kroah-Hartman 105588993ddSJiri Slaby static void change_speed(struct tty_struct *tty, struct serial_state *info, 106588993ddSJiri Slaby struct ktermios *old); 107a6afd9f3SGreg Kroah-Hartman static void rs_wait_until_sent(struct tty_struct *tty, int timeout); 108a6afd9f3SGreg Kroah-Hartman 109a6afd9f3SGreg Kroah-Hartman 110a6afd9f3SGreg Kroah-Hartman static struct serial_state rs_table[1]; 111a6afd9f3SGreg Kroah-Hartman 112a6afd9f3SGreg Kroah-Hartman #define NR_PORTS ARRAY_SIZE(rs_table) 113a6afd9f3SGreg Kroah-Hartman 114a6afd9f3SGreg Kroah-Hartman #include <asm/uaccess.h> 115a6afd9f3SGreg Kroah-Hartman 116a6afd9f3SGreg Kroah-Hartman #define serial_isroot() (capable(CAP_SYS_ADMIN)) 117a6afd9f3SGreg Kroah-Hartman 118a6afd9f3SGreg Kroah-Hartman 119916b7656SJiri Slaby static inline int serial_paranoia_check(struct serial_state *info, 120a6afd9f3SGreg Kroah-Hartman char *name, const char *routine) 121a6afd9f3SGreg Kroah-Hartman { 122a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_PARANOIA_CHECK 123a6afd9f3SGreg Kroah-Hartman static const char *badmagic = 124a6afd9f3SGreg Kroah-Hartman "Warning: bad magic number for serial struct (%s) in %s\n"; 125a6afd9f3SGreg Kroah-Hartman static const char *badinfo = 126a6afd9f3SGreg Kroah-Hartman "Warning: null async_struct for (%s) in %s\n"; 127a6afd9f3SGreg Kroah-Hartman 128a6afd9f3SGreg Kroah-Hartman if (!info) { 129a6afd9f3SGreg Kroah-Hartman printk(badinfo, name, routine); 130a6afd9f3SGreg Kroah-Hartman return 1; 131a6afd9f3SGreg Kroah-Hartman } 132a6afd9f3SGreg Kroah-Hartman if (info->magic != SERIAL_MAGIC) { 133a6afd9f3SGreg Kroah-Hartman printk(badmagic, name, routine); 134a6afd9f3SGreg Kroah-Hartman return 1; 135a6afd9f3SGreg Kroah-Hartman } 136a6afd9f3SGreg Kroah-Hartman #endif 137a6afd9f3SGreg Kroah-Hartman return 0; 138a6afd9f3SGreg Kroah-Hartman } 139a6afd9f3SGreg Kroah-Hartman 140a6afd9f3SGreg Kroah-Hartman /* some serial hardware definitions */ 141a6afd9f3SGreg Kroah-Hartman #define SDR_OVRUN (1<<15) 142a6afd9f3SGreg Kroah-Hartman #define SDR_RBF (1<<14) 143a6afd9f3SGreg Kroah-Hartman #define SDR_TBE (1<<13) 144a6afd9f3SGreg Kroah-Hartman #define SDR_TSRE (1<<12) 145a6afd9f3SGreg Kroah-Hartman 146a6afd9f3SGreg Kroah-Hartman #define SERPER_PARENB (1<<15) 147a6afd9f3SGreg Kroah-Hartman 148a6afd9f3SGreg Kroah-Hartman #define AC_SETCLR (1<<15) 149a6afd9f3SGreg Kroah-Hartman #define AC_UARTBRK (1<<11) 150a6afd9f3SGreg Kroah-Hartman 151a6afd9f3SGreg Kroah-Hartman #define SER_DTR (1<<7) 152a6afd9f3SGreg Kroah-Hartman #define SER_RTS (1<<6) 153a6afd9f3SGreg Kroah-Hartman #define SER_DCD (1<<5) 154a6afd9f3SGreg Kroah-Hartman #define SER_CTS (1<<4) 155a6afd9f3SGreg Kroah-Hartman #define SER_DSR (1<<3) 156a6afd9f3SGreg Kroah-Hartman 157a6afd9f3SGreg Kroah-Hartman static __inline__ void rtsdtr_ctrl(int bits) 158a6afd9f3SGreg Kroah-Hartman { 159a6afd9f3SGreg Kroah-Hartman ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR)); 160a6afd9f3SGreg Kroah-Hartman } 161a6afd9f3SGreg Kroah-Hartman 162a6afd9f3SGreg Kroah-Hartman /* 163a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 164a6afd9f3SGreg Kroah-Hartman * rs_stop() and rs_start() 165a6afd9f3SGreg Kroah-Hartman * 166a6afd9f3SGreg Kroah-Hartman * This routines are called before setting or resetting tty->stopped. 167a6afd9f3SGreg Kroah-Hartman * They enable or disable transmitter interrupts, as necessary. 168a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 169a6afd9f3SGreg Kroah-Hartman */ 170a6afd9f3SGreg Kroah-Hartman static void rs_stop(struct tty_struct *tty) 171a6afd9f3SGreg Kroah-Hartman { 172916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 173a6afd9f3SGreg Kroah-Hartman unsigned long flags; 174a6afd9f3SGreg Kroah-Hartman 175a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_stop")) 176a6afd9f3SGreg Kroah-Hartman return; 177a6afd9f3SGreg Kroah-Hartman 178a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 179a6afd9f3SGreg Kroah-Hartman if (info->IER & UART_IER_THRI) { 180a6afd9f3SGreg Kroah-Hartman info->IER &= ~UART_IER_THRI; 181a6afd9f3SGreg Kroah-Hartman /* disable Tx interrupt and remove any pending interrupts */ 182a6afd9f3SGreg Kroah-Hartman custom.intena = IF_TBE; 183a6afd9f3SGreg Kroah-Hartman mb(); 184a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_TBE; 185a6afd9f3SGreg Kroah-Hartman mb(); 186a6afd9f3SGreg Kroah-Hartman } 187a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 188a6afd9f3SGreg Kroah-Hartman } 189a6afd9f3SGreg Kroah-Hartman 190a6afd9f3SGreg Kroah-Hartman static void rs_start(struct tty_struct *tty) 191a6afd9f3SGreg Kroah-Hartman { 192916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 193a6afd9f3SGreg Kroah-Hartman unsigned long flags; 194a6afd9f3SGreg Kroah-Hartman 195a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_start")) 196a6afd9f3SGreg Kroah-Hartman return; 197a6afd9f3SGreg Kroah-Hartman 198a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 199a6afd9f3SGreg Kroah-Hartman if (info->xmit.head != info->xmit.tail 200a6afd9f3SGreg Kroah-Hartman && info->xmit.buf 201a6afd9f3SGreg Kroah-Hartman && !(info->IER & UART_IER_THRI)) { 202a6afd9f3SGreg Kroah-Hartman info->IER |= UART_IER_THRI; 203a6afd9f3SGreg Kroah-Hartman custom.intena = IF_SETCLR | IF_TBE; 204a6afd9f3SGreg Kroah-Hartman mb(); 205a6afd9f3SGreg Kroah-Hartman /* set a pending Tx Interrupt, transmitter should restart now */ 206a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_SETCLR | IF_TBE; 207a6afd9f3SGreg Kroah-Hartman mb(); 208a6afd9f3SGreg Kroah-Hartman } 209a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 210a6afd9f3SGreg Kroah-Hartman } 211a6afd9f3SGreg Kroah-Hartman 212a6afd9f3SGreg Kroah-Hartman /* 213a6afd9f3SGreg Kroah-Hartman * ---------------------------------------------------------------------- 214a6afd9f3SGreg Kroah-Hartman * 215a6afd9f3SGreg Kroah-Hartman * Here starts the interrupt handling routines. All of the following 216a6afd9f3SGreg Kroah-Hartman * subroutines are declared as inline and are folded into 217a6afd9f3SGreg Kroah-Hartman * rs_interrupt(). They were separated out for readability's sake. 218a6afd9f3SGreg Kroah-Hartman * 219a6afd9f3SGreg Kroah-Hartman * Note: rs_interrupt() is a "fast" interrupt, which means that it 220a6afd9f3SGreg Kroah-Hartman * runs with interrupts turned off. People who may want to modify 221a6afd9f3SGreg Kroah-Hartman * rs_interrupt() should try to keep the interrupt handler as fast as 222a6afd9f3SGreg Kroah-Hartman * possible. After you are done making modifications, it is not a bad 223a6afd9f3SGreg Kroah-Hartman * idea to do: 224a6afd9f3SGreg Kroah-Hartman * 225a6afd9f3SGreg Kroah-Hartman * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c 226a6afd9f3SGreg Kroah-Hartman * 227a6afd9f3SGreg Kroah-Hartman * and look at the resulting assemble code in serial.s. 228a6afd9f3SGreg Kroah-Hartman * 229a6afd9f3SGreg Kroah-Hartman * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 230a6afd9f3SGreg Kroah-Hartman * ----------------------------------------------------------------------- 231a6afd9f3SGreg Kroah-Hartman */ 232a6afd9f3SGreg Kroah-Hartman 233916b7656SJiri Slaby static void receive_chars(struct serial_state *info) 234a6afd9f3SGreg Kroah-Hartman { 235a6afd9f3SGreg Kroah-Hartman int status; 236a6afd9f3SGreg Kroah-Hartman int serdatr; 237*87758791SJiri Slaby struct tty_struct *tty = info->tport.tty; 238a6afd9f3SGreg Kroah-Hartman unsigned char ch, flag; 239a6afd9f3SGreg Kroah-Hartman struct async_icount *icount; 240a6afd9f3SGreg Kroah-Hartman int oe = 0; 241a6afd9f3SGreg Kroah-Hartman 242916b7656SJiri Slaby icount = &info->icount; 243a6afd9f3SGreg Kroah-Hartman 244a6afd9f3SGreg Kroah-Hartman status = UART_LSR_DR; /* We obviously have a character! */ 245a6afd9f3SGreg Kroah-Hartman serdatr = custom.serdatr; 246a6afd9f3SGreg Kroah-Hartman mb(); 247a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_RBF; 248a6afd9f3SGreg Kroah-Hartman mb(); 249a6afd9f3SGreg Kroah-Hartman 250a6afd9f3SGreg Kroah-Hartman if((serdatr & 0x1ff) == 0) 251a6afd9f3SGreg Kroah-Hartman status |= UART_LSR_BI; 252a6afd9f3SGreg Kroah-Hartman if(serdatr & SDR_OVRUN) 253a6afd9f3SGreg Kroah-Hartman status |= UART_LSR_OE; 254a6afd9f3SGreg Kroah-Hartman 255a6afd9f3SGreg Kroah-Hartman ch = serdatr & 0xff; 256a6afd9f3SGreg Kroah-Hartman icount->rx++; 257a6afd9f3SGreg Kroah-Hartman 258a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_INTR 259a6afd9f3SGreg Kroah-Hartman printk("DR%02x:%02x...", ch, status); 260a6afd9f3SGreg Kroah-Hartman #endif 261a6afd9f3SGreg Kroah-Hartman flag = TTY_NORMAL; 262a6afd9f3SGreg Kroah-Hartman 263a6afd9f3SGreg Kroah-Hartman /* 264a6afd9f3SGreg Kroah-Hartman * We don't handle parity or frame errors - but I have left 265a6afd9f3SGreg Kroah-Hartman * the code in, since I'm not sure that the errors can't be 266a6afd9f3SGreg Kroah-Hartman * detected. 267a6afd9f3SGreg Kroah-Hartman */ 268a6afd9f3SGreg Kroah-Hartman 269a6afd9f3SGreg Kroah-Hartman if (status & (UART_LSR_BI | UART_LSR_PE | 270a6afd9f3SGreg Kroah-Hartman UART_LSR_FE | UART_LSR_OE)) { 271a6afd9f3SGreg Kroah-Hartman /* 272a6afd9f3SGreg Kroah-Hartman * For statistics only 273a6afd9f3SGreg Kroah-Hartman */ 274a6afd9f3SGreg Kroah-Hartman if (status & UART_LSR_BI) { 275a6afd9f3SGreg Kroah-Hartman status &= ~(UART_LSR_FE | UART_LSR_PE); 276a6afd9f3SGreg Kroah-Hartman icount->brk++; 277a6afd9f3SGreg Kroah-Hartman } else if (status & UART_LSR_PE) 278a6afd9f3SGreg Kroah-Hartman icount->parity++; 279a6afd9f3SGreg Kroah-Hartman else if (status & UART_LSR_FE) 280a6afd9f3SGreg Kroah-Hartman icount->frame++; 281a6afd9f3SGreg Kroah-Hartman if (status & UART_LSR_OE) 282a6afd9f3SGreg Kroah-Hartman icount->overrun++; 283a6afd9f3SGreg Kroah-Hartman 284a6afd9f3SGreg Kroah-Hartman /* 285a6afd9f3SGreg Kroah-Hartman * Now check to see if character should be 286a6afd9f3SGreg Kroah-Hartman * ignored, and mask off conditions which 287a6afd9f3SGreg Kroah-Hartman * should be ignored. 288a6afd9f3SGreg Kroah-Hartman */ 289a6afd9f3SGreg Kroah-Hartman if (status & info->ignore_status_mask) 290a6afd9f3SGreg Kroah-Hartman goto out; 291a6afd9f3SGreg Kroah-Hartman 292a6afd9f3SGreg Kroah-Hartman status &= info->read_status_mask; 293a6afd9f3SGreg Kroah-Hartman 294a6afd9f3SGreg Kroah-Hartman if (status & (UART_LSR_BI)) { 295a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_INTR 296a6afd9f3SGreg Kroah-Hartman printk("handling break...."); 297a6afd9f3SGreg Kroah-Hartman #endif 298a6afd9f3SGreg Kroah-Hartman flag = TTY_BREAK; 299916b7656SJiri Slaby if (info->flags & ASYNC_SAK) 300a6afd9f3SGreg Kroah-Hartman do_SAK(tty); 301a6afd9f3SGreg Kroah-Hartman } else if (status & UART_LSR_PE) 302a6afd9f3SGreg Kroah-Hartman flag = TTY_PARITY; 303a6afd9f3SGreg Kroah-Hartman else if (status & UART_LSR_FE) 304a6afd9f3SGreg Kroah-Hartman flag = TTY_FRAME; 305a6afd9f3SGreg Kroah-Hartman if (status & UART_LSR_OE) { 306a6afd9f3SGreg Kroah-Hartman /* 307a6afd9f3SGreg Kroah-Hartman * Overrun is special, since it's 308a6afd9f3SGreg Kroah-Hartman * reported immediately, and doesn't 309a6afd9f3SGreg Kroah-Hartman * affect the current character 310a6afd9f3SGreg Kroah-Hartman */ 311a6afd9f3SGreg Kroah-Hartman oe = 1; 312a6afd9f3SGreg Kroah-Hartman } 313a6afd9f3SGreg Kroah-Hartman } 314a6afd9f3SGreg Kroah-Hartman tty_insert_flip_char(tty, ch, flag); 315a6afd9f3SGreg Kroah-Hartman if (oe == 1) 316a6afd9f3SGreg Kroah-Hartman tty_insert_flip_char(tty, 0, TTY_OVERRUN); 317a6afd9f3SGreg Kroah-Hartman tty_flip_buffer_push(tty); 318a6afd9f3SGreg Kroah-Hartman out: 319a6afd9f3SGreg Kroah-Hartman return; 320a6afd9f3SGreg Kroah-Hartman } 321a6afd9f3SGreg Kroah-Hartman 322916b7656SJiri Slaby static void transmit_chars(struct serial_state *info) 323a6afd9f3SGreg Kroah-Hartman { 324a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_TBE; 325a6afd9f3SGreg Kroah-Hartman mb(); 326a6afd9f3SGreg Kroah-Hartman if (info->x_char) { 327a6afd9f3SGreg Kroah-Hartman custom.serdat = info->x_char | 0x100; 328a6afd9f3SGreg Kroah-Hartman mb(); 329916b7656SJiri Slaby info->icount.tx++; 330a6afd9f3SGreg Kroah-Hartman info->x_char = 0; 331a6afd9f3SGreg Kroah-Hartman return; 332a6afd9f3SGreg Kroah-Hartman } 333a6afd9f3SGreg Kroah-Hartman if (info->xmit.head == info->xmit.tail 334*87758791SJiri Slaby || info->tport.tty->stopped 335*87758791SJiri Slaby || info->tport.tty->hw_stopped) { 336a6afd9f3SGreg Kroah-Hartman info->IER &= ~UART_IER_THRI; 337a6afd9f3SGreg Kroah-Hartman custom.intena = IF_TBE; 338a6afd9f3SGreg Kroah-Hartman mb(); 339a6afd9f3SGreg Kroah-Hartman return; 340a6afd9f3SGreg Kroah-Hartman } 341a6afd9f3SGreg Kroah-Hartman 342a6afd9f3SGreg Kroah-Hartman custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100; 343a6afd9f3SGreg Kroah-Hartman mb(); 344a6afd9f3SGreg Kroah-Hartman info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); 345916b7656SJiri Slaby info->icount.tx++; 346a6afd9f3SGreg Kroah-Hartman 347a6afd9f3SGreg Kroah-Hartman if (CIRC_CNT(info->xmit.head, 348a6afd9f3SGreg Kroah-Hartman info->xmit.tail, 349a6afd9f3SGreg Kroah-Hartman SERIAL_XMIT_SIZE) < WAKEUP_CHARS) 350*87758791SJiri Slaby tty_wakeup(info->tport.tty); 351a6afd9f3SGreg Kroah-Hartman 352a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_INTR 353a6afd9f3SGreg Kroah-Hartman printk("THRE..."); 354a6afd9f3SGreg Kroah-Hartman #endif 355a6afd9f3SGreg Kroah-Hartman if (info->xmit.head == info->xmit.tail) { 356a6afd9f3SGreg Kroah-Hartman custom.intena = IF_TBE; 357a6afd9f3SGreg Kroah-Hartman mb(); 358a6afd9f3SGreg Kroah-Hartman info->IER &= ~UART_IER_THRI; 359a6afd9f3SGreg Kroah-Hartman } 360a6afd9f3SGreg Kroah-Hartman } 361a6afd9f3SGreg Kroah-Hartman 362916b7656SJiri Slaby static void check_modem_status(struct serial_state *info) 363a6afd9f3SGreg Kroah-Hartman { 364a6afd9f3SGreg Kroah-Hartman unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); 365a6afd9f3SGreg Kroah-Hartman unsigned char dstatus; 366a6afd9f3SGreg Kroah-Hartman struct async_icount *icount; 367a6afd9f3SGreg Kroah-Hartman 368a6afd9f3SGreg Kroah-Hartman /* Determine bits that have changed */ 369a6afd9f3SGreg Kroah-Hartman dstatus = status ^ current_ctl_bits; 370a6afd9f3SGreg Kroah-Hartman current_ctl_bits = status; 371a6afd9f3SGreg Kroah-Hartman 372a6afd9f3SGreg Kroah-Hartman if (dstatus) { 373916b7656SJiri Slaby icount = &info->icount; 374a6afd9f3SGreg Kroah-Hartman /* update input line counters */ 375a6afd9f3SGreg Kroah-Hartman if (dstatus & SER_DSR) 376a6afd9f3SGreg Kroah-Hartman icount->dsr++; 377a6afd9f3SGreg Kroah-Hartman if (dstatus & SER_DCD) { 378a6afd9f3SGreg Kroah-Hartman icount->dcd++; 379a6afd9f3SGreg Kroah-Hartman #ifdef CONFIG_HARD_PPS 380916b7656SJiri Slaby if ((info->flags & ASYNC_HARDPPS_CD) && 381a6afd9f3SGreg Kroah-Hartman !(status & SER_DCD)) 382a6afd9f3SGreg Kroah-Hartman hardpps(); 383a6afd9f3SGreg Kroah-Hartman #endif 384a6afd9f3SGreg Kroah-Hartman } 385a6afd9f3SGreg Kroah-Hartman if (dstatus & SER_CTS) 386a6afd9f3SGreg Kroah-Hartman icount->cts++; 387*87758791SJiri Slaby wake_up_interruptible(&info->tport.delta_msr_wait); 388a6afd9f3SGreg Kroah-Hartman } 389a6afd9f3SGreg Kroah-Hartman 390916b7656SJiri Slaby if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { 391a6afd9f3SGreg Kroah-Hartman #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) 392a6afd9f3SGreg Kroah-Hartman printk("ttyS%d CD now %s...", info->line, 393a6afd9f3SGreg Kroah-Hartman (!(status & SER_DCD)) ? "on" : "off"); 394a6afd9f3SGreg Kroah-Hartman #endif 395a6afd9f3SGreg Kroah-Hartman if (!(status & SER_DCD)) 396*87758791SJiri Slaby wake_up_interruptible(&info->tport.open_wait); 397a6afd9f3SGreg Kroah-Hartman else { 398a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 399a6afd9f3SGreg Kroah-Hartman printk("doing serial hangup..."); 400a6afd9f3SGreg Kroah-Hartman #endif 401*87758791SJiri Slaby if (info->tport.tty) 402*87758791SJiri Slaby tty_hangup(info->tport.tty); 403a6afd9f3SGreg Kroah-Hartman } 404a6afd9f3SGreg Kroah-Hartman } 405916b7656SJiri Slaby if (info->flags & ASYNC_CTS_FLOW) { 406*87758791SJiri Slaby if (info->tport.tty->hw_stopped) { 407a6afd9f3SGreg Kroah-Hartman if (!(status & SER_CTS)) { 408a6afd9f3SGreg Kroah-Hartman #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) 409a6afd9f3SGreg Kroah-Hartman printk("CTS tx start..."); 410a6afd9f3SGreg Kroah-Hartman #endif 411*87758791SJiri Slaby info->tport.tty->hw_stopped = 0; 412a6afd9f3SGreg Kroah-Hartman info->IER |= UART_IER_THRI; 413a6afd9f3SGreg Kroah-Hartman custom.intena = IF_SETCLR | IF_TBE; 414a6afd9f3SGreg Kroah-Hartman mb(); 415a6afd9f3SGreg Kroah-Hartman /* set a pending Tx Interrupt, transmitter should restart now */ 416a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_SETCLR | IF_TBE; 417a6afd9f3SGreg Kroah-Hartman mb(); 418*87758791SJiri Slaby tty_wakeup(info->tport.tty); 419a6afd9f3SGreg Kroah-Hartman return; 420a6afd9f3SGreg Kroah-Hartman } 421a6afd9f3SGreg Kroah-Hartman } else { 422a6afd9f3SGreg Kroah-Hartman if ((status & SER_CTS)) { 423a6afd9f3SGreg Kroah-Hartman #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) 424a6afd9f3SGreg Kroah-Hartman printk("CTS tx stop..."); 425a6afd9f3SGreg Kroah-Hartman #endif 426*87758791SJiri Slaby info->tport.tty->hw_stopped = 1; 427a6afd9f3SGreg Kroah-Hartman info->IER &= ~UART_IER_THRI; 428a6afd9f3SGreg Kroah-Hartman /* disable Tx interrupt and remove any pending interrupts */ 429a6afd9f3SGreg Kroah-Hartman custom.intena = IF_TBE; 430a6afd9f3SGreg Kroah-Hartman mb(); 431a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_TBE; 432a6afd9f3SGreg Kroah-Hartman mb(); 433a6afd9f3SGreg Kroah-Hartman } 434a6afd9f3SGreg Kroah-Hartman } 435a6afd9f3SGreg Kroah-Hartman } 436a6afd9f3SGreg Kroah-Hartman } 437a6afd9f3SGreg Kroah-Hartman 438a6afd9f3SGreg Kroah-Hartman static irqreturn_t ser_vbl_int( int irq, void *data) 439a6afd9f3SGreg Kroah-Hartman { 440a6afd9f3SGreg Kroah-Hartman /* vbl is just a periodic interrupt we tie into to update modem status */ 441916b7656SJiri Slaby struct serial_state *info = data; 442a6afd9f3SGreg Kroah-Hartman /* 443a6afd9f3SGreg Kroah-Hartman * TBD - is it better to unregister from this interrupt or to 444a6afd9f3SGreg Kroah-Hartman * ignore it if MSI is clear ? 445a6afd9f3SGreg Kroah-Hartman */ 446a6afd9f3SGreg Kroah-Hartman if(info->IER & UART_IER_MSI) 447a6afd9f3SGreg Kroah-Hartman check_modem_status(info); 448a6afd9f3SGreg Kroah-Hartman return IRQ_HANDLED; 449a6afd9f3SGreg Kroah-Hartman } 450a6afd9f3SGreg Kroah-Hartman 451a6afd9f3SGreg Kroah-Hartman static irqreturn_t ser_rx_int(int irq, void *dev_id) 452a6afd9f3SGreg Kroah-Hartman { 453916b7656SJiri Slaby struct serial_state *info = dev_id; 454a6afd9f3SGreg Kroah-Hartman 455a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_INTR 456a6afd9f3SGreg Kroah-Hartman printk("ser_rx_int..."); 457a6afd9f3SGreg Kroah-Hartman #endif 458a6afd9f3SGreg Kroah-Hartman 459*87758791SJiri Slaby if (!info->tport.tty) 460a6afd9f3SGreg Kroah-Hartman return IRQ_NONE; 461a6afd9f3SGreg Kroah-Hartman 462a6afd9f3SGreg Kroah-Hartman receive_chars(info); 463a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_INTR 464a6afd9f3SGreg Kroah-Hartman printk("end.\n"); 465a6afd9f3SGreg Kroah-Hartman #endif 466a6afd9f3SGreg Kroah-Hartman return IRQ_HANDLED; 467a6afd9f3SGreg Kroah-Hartman } 468a6afd9f3SGreg Kroah-Hartman 469a6afd9f3SGreg Kroah-Hartman static irqreturn_t ser_tx_int(int irq, void *dev_id) 470a6afd9f3SGreg Kroah-Hartman { 471916b7656SJiri Slaby struct serial_state *info = dev_id; 472a6afd9f3SGreg Kroah-Hartman 473a6afd9f3SGreg Kroah-Hartman if (custom.serdatr & SDR_TBE) { 474a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_INTR 475a6afd9f3SGreg Kroah-Hartman printk("ser_tx_int..."); 476a6afd9f3SGreg Kroah-Hartman #endif 477a6afd9f3SGreg Kroah-Hartman 478*87758791SJiri Slaby if (!info->tport.tty) 479a6afd9f3SGreg Kroah-Hartman return IRQ_NONE; 480a6afd9f3SGreg Kroah-Hartman 481a6afd9f3SGreg Kroah-Hartman transmit_chars(info); 482a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_INTR 483a6afd9f3SGreg Kroah-Hartman printk("end.\n"); 484a6afd9f3SGreg Kroah-Hartman #endif 485a6afd9f3SGreg Kroah-Hartman } 486a6afd9f3SGreg Kroah-Hartman return IRQ_HANDLED; 487a6afd9f3SGreg Kroah-Hartman } 488a6afd9f3SGreg Kroah-Hartman 489a6afd9f3SGreg Kroah-Hartman /* 490a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------------- 491a6afd9f3SGreg Kroah-Hartman * Here ends the serial interrupt routines. 492a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------------- 493a6afd9f3SGreg Kroah-Hartman */ 494a6afd9f3SGreg Kroah-Hartman 495a6afd9f3SGreg Kroah-Hartman /* 496a6afd9f3SGreg Kroah-Hartman * --------------------------------------------------------------- 497a6afd9f3SGreg Kroah-Hartman * Low level utility subroutines for the serial driver: routines to 498a6afd9f3SGreg Kroah-Hartman * figure out the appropriate timeout for an interrupt chain, routines 499a6afd9f3SGreg Kroah-Hartman * to initialize and startup a serial port, and routines to shutdown a 500a6afd9f3SGreg Kroah-Hartman * serial port. Useful stuff like that. 501a6afd9f3SGreg Kroah-Hartman * --------------------------------------------------------------- 502a6afd9f3SGreg Kroah-Hartman */ 503a6afd9f3SGreg Kroah-Hartman 504588993ddSJiri Slaby static int startup(struct tty_struct *tty, struct serial_state *info) 505a6afd9f3SGreg Kroah-Hartman { 506a6afd9f3SGreg Kroah-Hartman unsigned long flags; 507a6afd9f3SGreg Kroah-Hartman int retval=0; 508a6afd9f3SGreg Kroah-Hartman unsigned long page; 509a6afd9f3SGreg Kroah-Hartman 510a6afd9f3SGreg Kroah-Hartman page = get_zeroed_page(GFP_KERNEL); 511a6afd9f3SGreg Kroah-Hartman if (!page) 512a6afd9f3SGreg Kroah-Hartman return -ENOMEM; 513a6afd9f3SGreg Kroah-Hartman 514a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 515a6afd9f3SGreg Kroah-Hartman 516916b7656SJiri Slaby if (info->flags & ASYNC_INITIALIZED) { 517a6afd9f3SGreg Kroah-Hartman free_page(page); 518a6afd9f3SGreg Kroah-Hartman goto errout; 519a6afd9f3SGreg Kroah-Hartman } 520a6afd9f3SGreg Kroah-Hartman 521a6afd9f3SGreg Kroah-Hartman if (info->xmit.buf) 522a6afd9f3SGreg Kroah-Hartman free_page(page); 523a6afd9f3SGreg Kroah-Hartman else 524a6afd9f3SGreg Kroah-Hartman info->xmit.buf = (unsigned char *) page; 525a6afd9f3SGreg Kroah-Hartman 526a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 527a6afd9f3SGreg Kroah-Hartman printk("starting up ttys%d ...", info->line); 528a6afd9f3SGreg Kroah-Hartman #endif 529a6afd9f3SGreg Kroah-Hartman 530a6afd9f3SGreg Kroah-Hartman /* Clear anything in the input buffer */ 531a6afd9f3SGreg Kroah-Hartman 532a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_RBF; 533a6afd9f3SGreg Kroah-Hartman mb(); 534a6afd9f3SGreg Kroah-Hartman 535a6afd9f3SGreg Kroah-Hartman retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info); 536a6afd9f3SGreg Kroah-Hartman if (retval) { 537a6afd9f3SGreg Kroah-Hartman if (serial_isroot()) { 538588993ddSJiri Slaby set_bit(TTY_IO_ERROR, &tty->flags); 539a6afd9f3SGreg Kroah-Hartman retval = 0; 540a6afd9f3SGreg Kroah-Hartman } 541a6afd9f3SGreg Kroah-Hartman goto errout; 542a6afd9f3SGreg Kroah-Hartman } 543a6afd9f3SGreg Kroah-Hartman 544a6afd9f3SGreg Kroah-Hartman /* enable both Rx and Tx interrupts */ 545a6afd9f3SGreg Kroah-Hartman custom.intena = IF_SETCLR | IF_RBF | IF_TBE; 546a6afd9f3SGreg Kroah-Hartman mb(); 547a6afd9f3SGreg Kroah-Hartman info->IER = UART_IER_MSI; 548a6afd9f3SGreg Kroah-Hartman 549a6afd9f3SGreg Kroah-Hartman /* remember current state of the DCD and CTS bits */ 550a6afd9f3SGreg Kroah-Hartman current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); 551a6afd9f3SGreg Kroah-Hartman 552a6afd9f3SGreg Kroah-Hartman info->MCR = 0; 553588993ddSJiri Slaby if (C_BAUD(tty)) 554a6afd9f3SGreg Kroah-Hartman info->MCR = SER_DTR | SER_RTS; 555a6afd9f3SGreg Kroah-Hartman rtsdtr_ctrl(info->MCR); 556a6afd9f3SGreg Kroah-Hartman 557588993ddSJiri Slaby clear_bit(TTY_IO_ERROR, &tty->flags); 558a6afd9f3SGreg Kroah-Hartman info->xmit.head = info->xmit.tail = 0; 559a6afd9f3SGreg Kroah-Hartman 560a6afd9f3SGreg Kroah-Hartman /* 561a6afd9f3SGreg Kroah-Hartman * Set up the tty->alt_speed kludge 562a6afd9f3SGreg Kroah-Hartman */ 563916b7656SJiri Slaby if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) 564588993ddSJiri Slaby tty->alt_speed = 57600; 565916b7656SJiri Slaby if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) 566588993ddSJiri Slaby tty->alt_speed = 115200; 567916b7656SJiri Slaby if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) 568588993ddSJiri Slaby tty->alt_speed = 230400; 569916b7656SJiri Slaby if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) 570588993ddSJiri Slaby tty->alt_speed = 460800; 571a6afd9f3SGreg Kroah-Hartman 572a6afd9f3SGreg Kroah-Hartman /* 573a6afd9f3SGreg Kroah-Hartman * and set the speed of the serial port 574a6afd9f3SGreg Kroah-Hartman */ 575588993ddSJiri Slaby change_speed(tty, info, NULL); 576a6afd9f3SGreg Kroah-Hartman 577916b7656SJiri Slaby info->flags |= ASYNC_INITIALIZED; 578a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 579a6afd9f3SGreg Kroah-Hartman return 0; 580a6afd9f3SGreg Kroah-Hartman 581a6afd9f3SGreg Kroah-Hartman errout: 582a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 583a6afd9f3SGreg Kroah-Hartman return retval; 584a6afd9f3SGreg Kroah-Hartman } 585a6afd9f3SGreg Kroah-Hartman 586a6afd9f3SGreg Kroah-Hartman /* 587a6afd9f3SGreg Kroah-Hartman * This routine will shutdown a serial port; interrupts are disabled, and 588a6afd9f3SGreg Kroah-Hartman * DTR is dropped if the hangup on close termio flag is on. 589a6afd9f3SGreg Kroah-Hartman */ 590588993ddSJiri Slaby static void shutdown(struct tty_struct *tty, struct serial_state *info) 591a6afd9f3SGreg Kroah-Hartman { 592a6afd9f3SGreg Kroah-Hartman unsigned long flags; 593a6afd9f3SGreg Kroah-Hartman struct serial_state *state; 594a6afd9f3SGreg Kroah-Hartman 595916b7656SJiri Slaby if (!(info->flags & ASYNC_INITIALIZED)) 596a6afd9f3SGreg Kroah-Hartman return; 597a6afd9f3SGreg Kroah-Hartman 598916b7656SJiri Slaby state = info; 599a6afd9f3SGreg Kroah-Hartman 600a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 601a6afd9f3SGreg Kroah-Hartman printk("Shutting down serial port %d ....\n", info->line); 602a6afd9f3SGreg Kroah-Hartman #endif 603a6afd9f3SGreg Kroah-Hartman 604a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); /* Disable interrupts */ 605a6afd9f3SGreg Kroah-Hartman 606a6afd9f3SGreg Kroah-Hartman /* 607a6afd9f3SGreg Kroah-Hartman * clear delta_msr_wait queue to avoid mem leaks: we may free the irq 608a6afd9f3SGreg Kroah-Hartman * here so the queue might never be waken up 609a6afd9f3SGreg Kroah-Hartman */ 610*87758791SJiri Slaby wake_up_interruptible(&info->tport.delta_msr_wait); 611a6afd9f3SGreg Kroah-Hartman 612a6afd9f3SGreg Kroah-Hartman /* 613a6afd9f3SGreg Kroah-Hartman * Free the IRQ, if necessary 614a6afd9f3SGreg Kroah-Hartman */ 615a6afd9f3SGreg Kroah-Hartman free_irq(IRQ_AMIGA_VERTB, info); 616a6afd9f3SGreg Kroah-Hartman 617a6afd9f3SGreg Kroah-Hartman if (info->xmit.buf) { 618a6afd9f3SGreg Kroah-Hartman free_page((unsigned long) info->xmit.buf); 619a6afd9f3SGreg Kroah-Hartman info->xmit.buf = NULL; 620a6afd9f3SGreg Kroah-Hartman } 621a6afd9f3SGreg Kroah-Hartman 622a6afd9f3SGreg Kroah-Hartman info->IER = 0; 623a6afd9f3SGreg Kroah-Hartman custom.intena = IF_RBF | IF_TBE; 624a6afd9f3SGreg Kroah-Hartman mb(); 625a6afd9f3SGreg Kroah-Hartman 626a6afd9f3SGreg Kroah-Hartman /* disable break condition */ 627a6afd9f3SGreg Kroah-Hartman custom.adkcon = AC_UARTBRK; 628a6afd9f3SGreg Kroah-Hartman mb(); 629a6afd9f3SGreg Kroah-Hartman 630588993ddSJiri Slaby if (tty->termios->c_cflag & HUPCL) 631a6afd9f3SGreg Kroah-Hartman info->MCR &= ~(SER_DTR|SER_RTS); 632a6afd9f3SGreg Kroah-Hartman rtsdtr_ctrl(info->MCR); 633a6afd9f3SGreg Kroah-Hartman 634588993ddSJiri Slaby set_bit(TTY_IO_ERROR, &tty->flags); 635a6afd9f3SGreg Kroah-Hartman 636916b7656SJiri Slaby info->flags &= ~ASYNC_INITIALIZED; 637a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 638a6afd9f3SGreg Kroah-Hartman } 639a6afd9f3SGreg Kroah-Hartman 640a6afd9f3SGreg Kroah-Hartman 641a6afd9f3SGreg Kroah-Hartman /* 642a6afd9f3SGreg Kroah-Hartman * This routine is called to set the UART divisor registers to match 643a6afd9f3SGreg Kroah-Hartman * the specified baud rate for a serial port. 644a6afd9f3SGreg Kroah-Hartman */ 645588993ddSJiri Slaby static void change_speed(struct tty_struct *tty, struct serial_state *info, 646a6afd9f3SGreg Kroah-Hartman struct ktermios *old_termios) 647a6afd9f3SGreg Kroah-Hartman { 648a6afd9f3SGreg Kroah-Hartman int quot = 0, baud_base, baud; 649a6afd9f3SGreg Kroah-Hartman unsigned cflag, cval = 0; 650a6afd9f3SGreg Kroah-Hartman int bits; 651a6afd9f3SGreg Kroah-Hartman unsigned long flags; 652a6afd9f3SGreg Kroah-Hartman 653588993ddSJiri Slaby cflag = tty->termios->c_cflag; 654a6afd9f3SGreg Kroah-Hartman 655a6afd9f3SGreg Kroah-Hartman /* Byte size is always 8 bits plus parity bit if requested */ 656a6afd9f3SGreg Kroah-Hartman 657a6afd9f3SGreg Kroah-Hartman cval = 3; bits = 10; 658a6afd9f3SGreg Kroah-Hartman if (cflag & CSTOPB) { 659a6afd9f3SGreg Kroah-Hartman cval |= 0x04; 660a6afd9f3SGreg Kroah-Hartman bits++; 661a6afd9f3SGreg Kroah-Hartman } 662a6afd9f3SGreg Kroah-Hartman if (cflag & PARENB) { 663a6afd9f3SGreg Kroah-Hartman cval |= UART_LCR_PARITY; 664a6afd9f3SGreg Kroah-Hartman bits++; 665a6afd9f3SGreg Kroah-Hartman } 666a6afd9f3SGreg Kroah-Hartman if (!(cflag & PARODD)) 667a6afd9f3SGreg Kroah-Hartman cval |= UART_LCR_EPAR; 668a6afd9f3SGreg Kroah-Hartman #ifdef CMSPAR 669a6afd9f3SGreg Kroah-Hartman if (cflag & CMSPAR) 670a6afd9f3SGreg Kroah-Hartman cval |= UART_LCR_SPAR; 671a6afd9f3SGreg Kroah-Hartman #endif 672a6afd9f3SGreg Kroah-Hartman 673a6afd9f3SGreg Kroah-Hartman /* Determine divisor based on baud rate */ 674588993ddSJiri Slaby baud = tty_get_baud_rate(tty); 675a6afd9f3SGreg Kroah-Hartman if (!baud) 676a6afd9f3SGreg Kroah-Hartman baud = 9600; /* B0 transition handled in rs_set_termios */ 677916b7656SJiri Slaby baud_base = info->baud_base; 678a6afd9f3SGreg Kroah-Hartman if (baud == 38400 && 679916b7656SJiri Slaby ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) 680916b7656SJiri Slaby quot = info->custom_divisor; 681a6afd9f3SGreg Kroah-Hartman else { 682a6afd9f3SGreg Kroah-Hartman if (baud == 134) 683a6afd9f3SGreg Kroah-Hartman /* Special case since 134 is really 134.5 */ 684a6afd9f3SGreg Kroah-Hartman quot = (2*baud_base / 269); 685a6afd9f3SGreg Kroah-Hartman else if (baud) 686a6afd9f3SGreg Kroah-Hartman quot = baud_base / baud; 687a6afd9f3SGreg Kroah-Hartman } 688a6afd9f3SGreg Kroah-Hartman /* If the quotient is zero refuse the change */ 689a6afd9f3SGreg Kroah-Hartman if (!quot && old_termios) { 690a6afd9f3SGreg Kroah-Hartman /* FIXME: Will need updating for new tty in the end */ 691588993ddSJiri Slaby tty->termios->c_cflag &= ~CBAUD; 692588993ddSJiri Slaby tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); 693588993ddSJiri Slaby baud = tty_get_baud_rate(tty); 694a6afd9f3SGreg Kroah-Hartman if (!baud) 695a6afd9f3SGreg Kroah-Hartman baud = 9600; 696a6afd9f3SGreg Kroah-Hartman if (baud == 38400 && 697916b7656SJiri Slaby ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) 698916b7656SJiri Slaby quot = info->custom_divisor; 699a6afd9f3SGreg Kroah-Hartman else { 700a6afd9f3SGreg Kroah-Hartman if (baud == 134) 701a6afd9f3SGreg Kroah-Hartman /* Special case since 134 is really 134.5 */ 702a6afd9f3SGreg Kroah-Hartman quot = (2*baud_base / 269); 703a6afd9f3SGreg Kroah-Hartman else if (baud) 704a6afd9f3SGreg Kroah-Hartman quot = baud_base / baud; 705a6afd9f3SGreg Kroah-Hartman } 706a6afd9f3SGreg Kroah-Hartman } 707a6afd9f3SGreg Kroah-Hartman /* As a last resort, if the quotient is zero, default to 9600 bps */ 708a6afd9f3SGreg Kroah-Hartman if (!quot) 709a6afd9f3SGreg Kroah-Hartman quot = baud_base / 9600; 710a6afd9f3SGreg Kroah-Hartman info->quot = quot; 711916b7656SJiri Slaby info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); 712a6afd9f3SGreg Kroah-Hartman info->timeout += HZ/50; /* Add .02 seconds of slop */ 713a6afd9f3SGreg Kroah-Hartman 714a6afd9f3SGreg Kroah-Hartman /* CTS flow control flag and modem status interrupts */ 715a6afd9f3SGreg Kroah-Hartman info->IER &= ~UART_IER_MSI; 716916b7656SJiri Slaby if (info->flags & ASYNC_HARDPPS_CD) 717a6afd9f3SGreg Kroah-Hartman info->IER |= UART_IER_MSI; 718a6afd9f3SGreg Kroah-Hartman if (cflag & CRTSCTS) { 719916b7656SJiri Slaby info->flags |= ASYNC_CTS_FLOW; 720a6afd9f3SGreg Kroah-Hartman info->IER |= UART_IER_MSI; 721a6afd9f3SGreg Kroah-Hartman } else 722916b7656SJiri Slaby info->flags &= ~ASYNC_CTS_FLOW; 723a6afd9f3SGreg Kroah-Hartman if (cflag & CLOCAL) 724916b7656SJiri Slaby info->flags &= ~ASYNC_CHECK_CD; 725a6afd9f3SGreg Kroah-Hartman else { 726916b7656SJiri Slaby info->flags |= ASYNC_CHECK_CD; 727a6afd9f3SGreg Kroah-Hartman info->IER |= UART_IER_MSI; 728a6afd9f3SGreg Kroah-Hartman } 729a6afd9f3SGreg Kroah-Hartman /* TBD: 730a6afd9f3SGreg Kroah-Hartman * Does clearing IER_MSI imply that we should disable the VBL interrupt ? 731a6afd9f3SGreg Kroah-Hartman */ 732a6afd9f3SGreg Kroah-Hartman 733a6afd9f3SGreg Kroah-Hartman /* 734a6afd9f3SGreg Kroah-Hartman * Set up parity check flag 735a6afd9f3SGreg Kroah-Hartman */ 736a6afd9f3SGreg Kroah-Hartman 737a6afd9f3SGreg Kroah-Hartman info->read_status_mask = UART_LSR_OE | UART_LSR_DR; 738588993ddSJiri Slaby if (I_INPCK(tty)) 739a6afd9f3SGreg Kroah-Hartman info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; 740588993ddSJiri Slaby if (I_BRKINT(tty) || I_PARMRK(tty)) 741a6afd9f3SGreg Kroah-Hartman info->read_status_mask |= UART_LSR_BI; 742a6afd9f3SGreg Kroah-Hartman 743a6afd9f3SGreg Kroah-Hartman /* 744a6afd9f3SGreg Kroah-Hartman * Characters to ignore 745a6afd9f3SGreg Kroah-Hartman */ 746a6afd9f3SGreg Kroah-Hartman info->ignore_status_mask = 0; 747588993ddSJiri Slaby if (I_IGNPAR(tty)) 748a6afd9f3SGreg Kroah-Hartman info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; 749588993ddSJiri Slaby if (I_IGNBRK(tty)) { 750a6afd9f3SGreg Kroah-Hartman info->ignore_status_mask |= UART_LSR_BI; 751a6afd9f3SGreg Kroah-Hartman /* 752a6afd9f3SGreg Kroah-Hartman * If we're ignore parity and break indicators, ignore 753a6afd9f3SGreg Kroah-Hartman * overruns too. (For real raw support). 754a6afd9f3SGreg Kroah-Hartman */ 755588993ddSJiri Slaby if (I_IGNPAR(tty)) 756a6afd9f3SGreg Kroah-Hartman info->ignore_status_mask |= UART_LSR_OE; 757a6afd9f3SGreg Kroah-Hartman } 758a6afd9f3SGreg Kroah-Hartman /* 759a6afd9f3SGreg Kroah-Hartman * !!! ignore all characters if CREAD is not set 760a6afd9f3SGreg Kroah-Hartman */ 761a6afd9f3SGreg Kroah-Hartman if ((cflag & CREAD) == 0) 762a6afd9f3SGreg Kroah-Hartman info->ignore_status_mask |= UART_LSR_DR; 763a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 764a6afd9f3SGreg Kroah-Hartman 765a6afd9f3SGreg Kroah-Hartman { 766a6afd9f3SGreg Kroah-Hartman short serper; 767a6afd9f3SGreg Kroah-Hartman 768a6afd9f3SGreg Kroah-Hartman /* Set up the baud rate */ 769a6afd9f3SGreg Kroah-Hartman serper = quot - 1; 770a6afd9f3SGreg Kroah-Hartman 771a6afd9f3SGreg Kroah-Hartman /* Enable or disable parity bit */ 772a6afd9f3SGreg Kroah-Hartman 773a6afd9f3SGreg Kroah-Hartman if(cval & UART_LCR_PARITY) 774a6afd9f3SGreg Kroah-Hartman serper |= (SERPER_PARENB); 775a6afd9f3SGreg Kroah-Hartman 776a6afd9f3SGreg Kroah-Hartman custom.serper = serper; 777a6afd9f3SGreg Kroah-Hartman mb(); 778a6afd9f3SGreg Kroah-Hartman } 779a6afd9f3SGreg Kroah-Hartman 780a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 781a6afd9f3SGreg Kroah-Hartman } 782a6afd9f3SGreg Kroah-Hartman 783a6afd9f3SGreg Kroah-Hartman static int rs_put_char(struct tty_struct *tty, unsigned char ch) 784a6afd9f3SGreg Kroah-Hartman { 785916b7656SJiri Slaby struct serial_state *info; 786a6afd9f3SGreg Kroah-Hartman unsigned long flags; 787a6afd9f3SGreg Kroah-Hartman 788a6afd9f3SGreg Kroah-Hartman info = tty->driver_data; 789a6afd9f3SGreg Kroah-Hartman 790a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_put_char")) 791a6afd9f3SGreg Kroah-Hartman return 0; 792a6afd9f3SGreg Kroah-Hartman 793a6afd9f3SGreg Kroah-Hartman if (!info->xmit.buf) 794a6afd9f3SGreg Kroah-Hartman return 0; 795a6afd9f3SGreg Kroah-Hartman 796a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 797a6afd9f3SGreg Kroah-Hartman if (CIRC_SPACE(info->xmit.head, 798a6afd9f3SGreg Kroah-Hartman info->xmit.tail, 799a6afd9f3SGreg Kroah-Hartman SERIAL_XMIT_SIZE) == 0) { 800a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 801a6afd9f3SGreg Kroah-Hartman return 0; 802a6afd9f3SGreg Kroah-Hartman } 803a6afd9f3SGreg Kroah-Hartman 804a6afd9f3SGreg Kroah-Hartman info->xmit.buf[info->xmit.head++] = ch; 805a6afd9f3SGreg Kroah-Hartman info->xmit.head &= SERIAL_XMIT_SIZE-1; 806a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 807a6afd9f3SGreg Kroah-Hartman return 1; 808a6afd9f3SGreg Kroah-Hartman } 809a6afd9f3SGreg Kroah-Hartman 810a6afd9f3SGreg Kroah-Hartman static void rs_flush_chars(struct tty_struct *tty) 811a6afd9f3SGreg Kroah-Hartman { 812916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 813a6afd9f3SGreg Kroah-Hartman unsigned long flags; 814a6afd9f3SGreg Kroah-Hartman 815a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) 816a6afd9f3SGreg Kroah-Hartman return; 817a6afd9f3SGreg Kroah-Hartman 818a6afd9f3SGreg Kroah-Hartman if (info->xmit.head == info->xmit.tail 819a6afd9f3SGreg Kroah-Hartman || tty->stopped 820a6afd9f3SGreg Kroah-Hartman || tty->hw_stopped 821a6afd9f3SGreg Kroah-Hartman || !info->xmit.buf) 822a6afd9f3SGreg Kroah-Hartman return; 823a6afd9f3SGreg Kroah-Hartman 824a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 825a6afd9f3SGreg Kroah-Hartman info->IER |= UART_IER_THRI; 826a6afd9f3SGreg Kroah-Hartman custom.intena = IF_SETCLR | IF_TBE; 827a6afd9f3SGreg Kroah-Hartman mb(); 828a6afd9f3SGreg Kroah-Hartman /* set a pending Tx Interrupt, transmitter should restart now */ 829a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_SETCLR | IF_TBE; 830a6afd9f3SGreg Kroah-Hartman mb(); 831a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 832a6afd9f3SGreg Kroah-Hartman } 833a6afd9f3SGreg Kroah-Hartman 834a6afd9f3SGreg Kroah-Hartman static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count) 835a6afd9f3SGreg Kroah-Hartman { 836a6afd9f3SGreg Kroah-Hartman int c, ret = 0; 837916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 838a6afd9f3SGreg Kroah-Hartman unsigned long flags; 839a6afd9f3SGreg Kroah-Hartman 840a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_write")) 841a6afd9f3SGreg Kroah-Hartman return 0; 842a6afd9f3SGreg Kroah-Hartman 843a6afd9f3SGreg Kroah-Hartman if (!info->xmit.buf) 844a6afd9f3SGreg Kroah-Hartman return 0; 845a6afd9f3SGreg Kroah-Hartman 846a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 847a6afd9f3SGreg Kroah-Hartman while (1) { 848a6afd9f3SGreg Kroah-Hartman c = CIRC_SPACE_TO_END(info->xmit.head, 849a6afd9f3SGreg Kroah-Hartman info->xmit.tail, 850a6afd9f3SGreg Kroah-Hartman SERIAL_XMIT_SIZE); 851a6afd9f3SGreg Kroah-Hartman if (count < c) 852a6afd9f3SGreg Kroah-Hartman c = count; 853a6afd9f3SGreg Kroah-Hartman if (c <= 0) { 854a6afd9f3SGreg Kroah-Hartman break; 855a6afd9f3SGreg Kroah-Hartman } 856a6afd9f3SGreg Kroah-Hartman memcpy(info->xmit.buf + info->xmit.head, buf, c); 857a6afd9f3SGreg Kroah-Hartman info->xmit.head = ((info->xmit.head + c) & 858a6afd9f3SGreg Kroah-Hartman (SERIAL_XMIT_SIZE-1)); 859a6afd9f3SGreg Kroah-Hartman buf += c; 860a6afd9f3SGreg Kroah-Hartman count -= c; 861a6afd9f3SGreg Kroah-Hartman ret += c; 862a6afd9f3SGreg Kroah-Hartman } 863a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 864a6afd9f3SGreg Kroah-Hartman 865a6afd9f3SGreg Kroah-Hartman if (info->xmit.head != info->xmit.tail 866a6afd9f3SGreg Kroah-Hartman && !tty->stopped 867a6afd9f3SGreg Kroah-Hartman && !tty->hw_stopped 868a6afd9f3SGreg Kroah-Hartman && !(info->IER & UART_IER_THRI)) { 869a6afd9f3SGreg Kroah-Hartman info->IER |= UART_IER_THRI; 870a6afd9f3SGreg Kroah-Hartman local_irq_disable(); 871a6afd9f3SGreg Kroah-Hartman custom.intena = IF_SETCLR | IF_TBE; 872a6afd9f3SGreg Kroah-Hartman mb(); 873a6afd9f3SGreg Kroah-Hartman /* set a pending Tx Interrupt, transmitter should restart now */ 874a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_SETCLR | IF_TBE; 875a6afd9f3SGreg Kroah-Hartman mb(); 876a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 877a6afd9f3SGreg Kroah-Hartman } 878a6afd9f3SGreg Kroah-Hartman return ret; 879a6afd9f3SGreg Kroah-Hartman } 880a6afd9f3SGreg Kroah-Hartman 881a6afd9f3SGreg Kroah-Hartman static int rs_write_room(struct tty_struct *tty) 882a6afd9f3SGreg Kroah-Hartman { 883916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 884a6afd9f3SGreg Kroah-Hartman 885a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_write_room")) 886a6afd9f3SGreg Kroah-Hartman return 0; 887a6afd9f3SGreg Kroah-Hartman return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 888a6afd9f3SGreg Kroah-Hartman } 889a6afd9f3SGreg Kroah-Hartman 890a6afd9f3SGreg Kroah-Hartman static int rs_chars_in_buffer(struct tty_struct *tty) 891a6afd9f3SGreg Kroah-Hartman { 892916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 893a6afd9f3SGreg Kroah-Hartman 894a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) 895a6afd9f3SGreg Kroah-Hartman return 0; 896a6afd9f3SGreg Kroah-Hartman return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); 897a6afd9f3SGreg Kroah-Hartman } 898a6afd9f3SGreg Kroah-Hartman 899a6afd9f3SGreg Kroah-Hartman static void rs_flush_buffer(struct tty_struct *tty) 900a6afd9f3SGreg Kroah-Hartman { 901916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 902a6afd9f3SGreg Kroah-Hartman unsigned long flags; 903a6afd9f3SGreg Kroah-Hartman 904a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) 905a6afd9f3SGreg Kroah-Hartman return; 906a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 907a6afd9f3SGreg Kroah-Hartman info->xmit.head = info->xmit.tail = 0; 908a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 909a6afd9f3SGreg Kroah-Hartman tty_wakeup(tty); 910a6afd9f3SGreg Kroah-Hartman } 911a6afd9f3SGreg Kroah-Hartman 912a6afd9f3SGreg Kroah-Hartman /* 913a6afd9f3SGreg Kroah-Hartman * This function is used to send a high-priority XON/XOFF character to 914a6afd9f3SGreg Kroah-Hartman * the device 915a6afd9f3SGreg Kroah-Hartman */ 916a6afd9f3SGreg Kroah-Hartman static void rs_send_xchar(struct tty_struct *tty, char ch) 917a6afd9f3SGreg Kroah-Hartman { 918916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 919a6afd9f3SGreg Kroah-Hartman unsigned long flags; 920a6afd9f3SGreg Kroah-Hartman 921a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_send_char")) 922a6afd9f3SGreg Kroah-Hartman return; 923a6afd9f3SGreg Kroah-Hartman 924a6afd9f3SGreg Kroah-Hartman info->x_char = ch; 925a6afd9f3SGreg Kroah-Hartman if (ch) { 926a6afd9f3SGreg Kroah-Hartman /* Make sure transmit interrupts are on */ 927a6afd9f3SGreg Kroah-Hartman 928a6afd9f3SGreg Kroah-Hartman /* Check this ! */ 929a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 930a6afd9f3SGreg Kroah-Hartman if(!(custom.intenar & IF_TBE)) { 931a6afd9f3SGreg Kroah-Hartman custom.intena = IF_SETCLR | IF_TBE; 932a6afd9f3SGreg Kroah-Hartman mb(); 933a6afd9f3SGreg Kroah-Hartman /* set a pending Tx Interrupt, transmitter should restart now */ 934a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_SETCLR | IF_TBE; 935a6afd9f3SGreg Kroah-Hartman mb(); 936a6afd9f3SGreg Kroah-Hartman } 937a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 938a6afd9f3SGreg Kroah-Hartman 939a6afd9f3SGreg Kroah-Hartman info->IER |= UART_IER_THRI; 940a6afd9f3SGreg Kroah-Hartman } 941a6afd9f3SGreg Kroah-Hartman } 942a6afd9f3SGreg Kroah-Hartman 943a6afd9f3SGreg Kroah-Hartman /* 944a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 945a6afd9f3SGreg Kroah-Hartman * rs_throttle() 946a6afd9f3SGreg Kroah-Hartman * 947a6afd9f3SGreg Kroah-Hartman * This routine is called by the upper-layer tty layer to signal that 948a6afd9f3SGreg Kroah-Hartman * incoming characters should be throttled. 949a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 950a6afd9f3SGreg Kroah-Hartman */ 951a6afd9f3SGreg Kroah-Hartman static void rs_throttle(struct tty_struct * tty) 952a6afd9f3SGreg Kroah-Hartman { 953916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 954a6afd9f3SGreg Kroah-Hartman unsigned long flags; 955a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_THROTTLE 956a6afd9f3SGreg Kroah-Hartman char buf[64]; 957a6afd9f3SGreg Kroah-Hartman 958a6afd9f3SGreg Kroah-Hartman printk("throttle %s: %d....\n", tty_name(tty, buf), 959a6afd9f3SGreg Kroah-Hartman tty->ldisc.chars_in_buffer(tty)); 960a6afd9f3SGreg Kroah-Hartman #endif 961a6afd9f3SGreg Kroah-Hartman 962a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_throttle")) 963a6afd9f3SGreg Kroah-Hartman return; 964a6afd9f3SGreg Kroah-Hartman 965a6afd9f3SGreg Kroah-Hartman if (I_IXOFF(tty)) 966a6afd9f3SGreg Kroah-Hartman rs_send_xchar(tty, STOP_CHAR(tty)); 967a6afd9f3SGreg Kroah-Hartman 968a6afd9f3SGreg Kroah-Hartman if (tty->termios->c_cflag & CRTSCTS) 969a6afd9f3SGreg Kroah-Hartman info->MCR &= ~SER_RTS; 970a6afd9f3SGreg Kroah-Hartman 971a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 972a6afd9f3SGreg Kroah-Hartman rtsdtr_ctrl(info->MCR); 973a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 974a6afd9f3SGreg Kroah-Hartman } 975a6afd9f3SGreg Kroah-Hartman 976a6afd9f3SGreg Kroah-Hartman static void rs_unthrottle(struct tty_struct * tty) 977a6afd9f3SGreg Kroah-Hartman { 978916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 979a6afd9f3SGreg Kroah-Hartman unsigned long flags; 980a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_THROTTLE 981a6afd9f3SGreg Kroah-Hartman char buf[64]; 982a6afd9f3SGreg Kroah-Hartman 983a6afd9f3SGreg Kroah-Hartman printk("unthrottle %s: %d....\n", tty_name(tty, buf), 984a6afd9f3SGreg Kroah-Hartman tty->ldisc.chars_in_buffer(tty)); 985a6afd9f3SGreg Kroah-Hartman #endif 986a6afd9f3SGreg Kroah-Hartman 987a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) 988a6afd9f3SGreg Kroah-Hartman return; 989a6afd9f3SGreg Kroah-Hartman 990a6afd9f3SGreg Kroah-Hartman if (I_IXOFF(tty)) { 991a6afd9f3SGreg Kroah-Hartman if (info->x_char) 992a6afd9f3SGreg Kroah-Hartman info->x_char = 0; 993a6afd9f3SGreg Kroah-Hartman else 994a6afd9f3SGreg Kroah-Hartman rs_send_xchar(tty, START_CHAR(tty)); 995a6afd9f3SGreg Kroah-Hartman } 996a6afd9f3SGreg Kroah-Hartman if (tty->termios->c_cflag & CRTSCTS) 997a6afd9f3SGreg Kroah-Hartman info->MCR |= SER_RTS; 998a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 999a6afd9f3SGreg Kroah-Hartman rtsdtr_ctrl(info->MCR); 1000a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1001a6afd9f3SGreg Kroah-Hartman } 1002a6afd9f3SGreg Kroah-Hartman 1003a6afd9f3SGreg Kroah-Hartman /* 1004a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 1005a6afd9f3SGreg Kroah-Hartman * rs_ioctl() and friends 1006a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 1007a6afd9f3SGreg Kroah-Hartman */ 1008a6afd9f3SGreg Kroah-Hartman 1009916b7656SJiri Slaby static int get_serial_info(struct serial_state *state, 1010a6afd9f3SGreg Kroah-Hartman struct serial_struct __user * retinfo) 1011a6afd9f3SGreg Kroah-Hartman { 1012a6afd9f3SGreg Kroah-Hartman struct serial_struct tmp; 1013a6afd9f3SGreg Kroah-Hartman 1014a6afd9f3SGreg Kroah-Hartman if (!retinfo) 1015a6afd9f3SGreg Kroah-Hartman return -EFAULT; 1016a6afd9f3SGreg Kroah-Hartman memset(&tmp, 0, sizeof(tmp)); 1017a6afd9f3SGreg Kroah-Hartman tty_lock(); 1018a6afd9f3SGreg Kroah-Hartman tmp.type = state->type; 1019a6afd9f3SGreg Kroah-Hartman tmp.line = state->line; 1020a6afd9f3SGreg Kroah-Hartman tmp.port = state->port; 1021a6afd9f3SGreg Kroah-Hartman tmp.irq = state->irq; 1022a6afd9f3SGreg Kroah-Hartman tmp.flags = state->flags; 1023a6afd9f3SGreg Kroah-Hartman tmp.xmit_fifo_size = state->xmit_fifo_size; 1024a6afd9f3SGreg Kroah-Hartman tmp.baud_base = state->baud_base; 1025a6afd9f3SGreg Kroah-Hartman tmp.close_delay = state->close_delay; 1026a6afd9f3SGreg Kroah-Hartman tmp.closing_wait = state->closing_wait; 1027a6afd9f3SGreg Kroah-Hartman tmp.custom_divisor = state->custom_divisor; 1028a6afd9f3SGreg Kroah-Hartman tty_unlock(); 1029a6afd9f3SGreg Kroah-Hartman if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) 1030a6afd9f3SGreg Kroah-Hartman return -EFAULT; 1031a6afd9f3SGreg Kroah-Hartman return 0; 1032a6afd9f3SGreg Kroah-Hartman } 1033a6afd9f3SGreg Kroah-Hartman 1034588993ddSJiri Slaby static int set_serial_info(struct tty_struct *tty, struct serial_state *state, 1035a6afd9f3SGreg Kroah-Hartman struct serial_struct __user * new_info) 1036a6afd9f3SGreg Kroah-Hartman { 1037a6afd9f3SGreg Kroah-Hartman struct serial_struct new_serial; 10380f9b9684SJiri Slaby bool change_spd; 1039a6afd9f3SGreg Kroah-Hartman int retval = 0; 1040a6afd9f3SGreg Kroah-Hartman 1041a6afd9f3SGreg Kroah-Hartman if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) 1042a6afd9f3SGreg Kroah-Hartman return -EFAULT; 1043a6afd9f3SGreg Kroah-Hartman 1044a6afd9f3SGreg Kroah-Hartman tty_lock(); 10450f9b9684SJiri Slaby change_spd = ((new_serial.flags ^ state->flags) & ASYNC_SPD_MASK) || 10460f9b9684SJiri Slaby new_serial.custom_divisor != state->custom_divisor; 10470f9b9684SJiri Slaby if (new_serial.irq != state->irq || new_serial.port != state->port || 10480f9b9684SJiri Slaby new_serial.xmit_fifo_size != state->xmit_fifo_size) { 1049a6afd9f3SGreg Kroah-Hartman tty_unlock(); 1050a6afd9f3SGreg Kroah-Hartman return -EINVAL; 1051a6afd9f3SGreg Kroah-Hartman } 1052a6afd9f3SGreg Kroah-Hartman 1053a6afd9f3SGreg Kroah-Hartman if (!serial_isroot()) { 1054a6afd9f3SGreg Kroah-Hartman if ((new_serial.baud_base != state->baud_base) || 1055a6afd9f3SGreg Kroah-Hartman (new_serial.close_delay != state->close_delay) || 1056a6afd9f3SGreg Kroah-Hartman (new_serial.xmit_fifo_size != state->xmit_fifo_size) || 1057a6afd9f3SGreg Kroah-Hartman ((new_serial.flags & ~ASYNC_USR_MASK) != 1058a6afd9f3SGreg Kroah-Hartman (state->flags & ~ASYNC_USR_MASK))) 1059a6afd9f3SGreg Kroah-Hartman return -EPERM; 1060a6afd9f3SGreg Kroah-Hartman state->flags = ((state->flags & ~ASYNC_USR_MASK) | 1061a6afd9f3SGreg Kroah-Hartman (new_serial.flags & ASYNC_USR_MASK)); 1062a6afd9f3SGreg Kroah-Hartman state->custom_divisor = new_serial.custom_divisor; 1063a6afd9f3SGreg Kroah-Hartman goto check_and_exit; 1064a6afd9f3SGreg Kroah-Hartman } 1065a6afd9f3SGreg Kroah-Hartman 1066a6afd9f3SGreg Kroah-Hartman if (new_serial.baud_base < 9600) { 1067a6afd9f3SGreg Kroah-Hartman tty_unlock(); 1068a6afd9f3SGreg Kroah-Hartman return -EINVAL; 1069a6afd9f3SGreg Kroah-Hartman } 1070a6afd9f3SGreg Kroah-Hartman 1071a6afd9f3SGreg Kroah-Hartman /* 1072a6afd9f3SGreg Kroah-Hartman * OK, past this point, all the error checking has been done. 1073a6afd9f3SGreg Kroah-Hartman * At this point, we start making changes..... 1074a6afd9f3SGreg Kroah-Hartman */ 1075a6afd9f3SGreg Kroah-Hartman 1076a6afd9f3SGreg Kroah-Hartman state->baud_base = new_serial.baud_base; 1077a6afd9f3SGreg Kroah-Hartman state->flags = ((state->flags & ~ASYNC_FLAGS) | 1078a6afd9f3SGreg Kroah-Hartman (new_serial.flags & ASYNC_FLAGS)); 1079a6afd9f3SGreg Kroah-Hartman state->custom_divisor = new_serial.custom_divisor; 1080a6afd9f3SGreg Kroah-Hartman state->close_delay = new_serial.close_delay * HZ/100; 1081a6afd9f3SGreg Kroah-Hartman state->closing_wait = new_serial.closing_wait * HZ/100; 1082588993ddSJiri Slaby tty->low_latency = (state->flags & ASYNC_LOW_LATENCY) ? 1 : 0; 1083a6afd9f3SGreg Kroah-Hartman 1084a6afd9f3SGreg Kroah-Hartman check_and_exit: 1085fef21073SJiri Slaby if (state->flags & ASYNC_INITIALIZED) { 10860f9b9684SJiri Slaby if (change_spd) { 1087a6afd9f3SGreg Kroah-Hartman if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) 1088588993ddSJiri Slaby tty->alt_speed = 57600; 1089a6afd9f3SGreg Kroah-Hartman if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) 1090588993ddSJiri Slaby tty->alt_speed = 115200; 1091a6afd9f3SGreg Kroah-Hartman if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) 1092588993ddSJiri Slaby tty->alt_speed = 230400; 1093a6afd9f3SGreg Kroah-Hartman if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) 1094588993ddSJiri Slaby tty->alt_speed = 460800; 1095588993ddSJiri Slaby change_speed(tty, state, NULL); 1096a6afd9f3SGreg Kroah-Hartman } 1097a6afd9f3SGreg Kroah-Hartman } else 1098588993ddSJiri Slaby retval = startup(tty, state); 1099a6afd9f3SGreg Kroah-Hartman tty_unlock(); 1100a6afd9f3SGreg Kroah-Hartman return retval; 1101a6afd9f3SGreg Kroah-Hartman } 1102a6afd9f3SGreg Kroah-Hartman 1103a6afd9f3SGreg Kroah-Hartman 1104a6afd9f3SGreg Kroah-Hartman /* 1105a6afd9f3SGreg Kroah-Hartman * get_lsr_info - get line status register info 1106a6afd9f3SGreg Kroah-Hartman * 1107a6afd9f3SGreg Kroah-Hartman * Purpose: Let user call ioctl() to get info when the UART physically 1108a6afd9f3SGreg Kroah-Hartman * is emptied. On bus types like RS485, the transmitter must 1109a6afd9f3SGreg Kroah-Hartman * release the bus after transmitting. This must be done when 1110a6afd9f3SGreg Kroah-Hartman * the transmit shift register is empty, not be done when the 1111a6afd9f3SGreg Kroah-Hartman * transmit holding register is empty. This functionality 1112a6afd9f3SGreg Kroah-Hartman * allows an RS485 driver to be written in user space. 1113a6afd9f3SGreg Kroah-Hartman */ 1114916b7656SJiri Slaby static int get_lsr_info(struct serial_state *info, unsigned int __user *value) 1115a6afd9f3SGreg Kroah-Hartman { 1116a6afd9f3SGreg Kroah-Hartman unsigned char status; 1117a6afd9f3SGreg Kroah-Hartman unsigned int result; 1118a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1119a6afd9f3SGreg Kroah-Hartman 1120a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1121a6afd9f3SGreg Kroah-Hartman status = custom.serdatr; 1122a6afd9f3SGreg Kroah-Hartman mb(); 1123a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1124a6afd9f3SGreg Kroah-Hartman result = ((status & SDR_TSRE) ? TIOCSER_TEMT : 0); 1125a6afd9f3SGreg Kroah-Hartman if (copy_to_user(value, &result, sizeof(int))) 1126a6afd9f3SGreg Kroah-Hartman return -EFAULT; 1127a6afd9f3SGreg Kroah-Hartman return 0; 1128a6afd9f3SGreg Kroah-Hartman } 1129a6afd9f3SGreg Kroah-Hartman 1130a6afd9f3SGreg Kroah-Hartman 1131a6afd9f3SGreg Kroah-Hartman static int rs_tiocmget(struct tty_struct *tty) 1132a6afd9f3SGreg Kroah-Hartman { 1133916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 1134a6afd9f3SGreg Kroah-Hartman unsigned char control, status; 1135a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1136a6afd9f3SGreg Kroah-Hartman 1137a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_ioctl")) 1138a6afd9f3SGreg Kroah-Hartman return -ENODEV; 1139a6afd9f3SGreg Kroah-Hartman if (tty->flags & (1 << TTY_IO_ERROR)) 1140a6afd9f3SGreg Kroah-Hartman return -EIO; 1141a6afd9f3SGreg Kroah-Hartman 1142a6afd9f3SGreg Kroah-Hartman control = info->MCR; 1143a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1144a6afd9f3SGreg Kroah-Hartman status = ciab.pra; 1145a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1146a6afd9f3SGreg Kroah-Hartman return ((control & SER_RTS) ? TIOCM_RTS : 0) 1147a6afd9f3SGreg Kroah-Hartman | ((control & SER_DTR) ? TIOCM_DTR : 0) 1148a6afd9f3SGreg Kroah-Hartman | (!(status & SER_DCD) ? TIOCM_CAR : 0) 1149a6afd9f3SGreg Kroah-Hartman | (!(status & SER_DSR) ? TIOCM_DSR : 0) 1150a6afd9f3SGreg Kroah-Hartman | (!(status & SER_CTS) ? TIOCM_CTS : 0); 1151a6afd9f3SGreg Kroah-Hartman } 1152a6afd9f3SGreg Kroah-Hartman 1153a6afd9f3SGreg Kroah-Hartman static int rs_tiocmset(struct tty_struct *tty, unsigned int set, 1154a6afd9f3SGreg Kroah-Hartman unsigned int clear) 1155a6afd9f3SGreg Kroah-Hartman { 1156916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 1157a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1158a6afd9f3SGreg Kroah-Hartman 1159a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_ioctl")) 1160a6afd9f3SGreg Kroah-Hartman return -ENODEV; 1161a6afd9f3SGreg Kroah-Hartman if (tty->flags & (1 << TTY_IO_ERROR)) 1162a6afd9f3SGreg Kroah-Hartman return -EIO; 1163a6afd9f3SGreg Kroah-Hartman 1164a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1165a6afd9f3SGreg Kroah-Hartman if (set & TIOCM_RTS) 1166a6afd9f3SGreg Kroah-Hartman info->MCR |= SER_RTS; 1167a6afd9f3SGreg Kroah-Hartman if (set & TIOCM_DTR) 1168a6afd9f3SGreg Kroah-Hartman info->MCR |= SER_DTR; 1169a6afd9f3SGreg Kroah-Hartman if (clear & TIOCM_RTS) 1170a6afd9f3SGreg Kroah-Hartman info->MCR &= ~SER_RTS; 1171a6afd9f3SGreg Kroah-Hartman if (clear & TIOCM_DTR) 1172a6afd9f3SGreg Kroah-Hartman info->MCR &= ~SER_DTR; 1173a6afd9f3SGreg Kroah-Hartman rtsdtr_ctrl(info->MCR); 1174a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1175a6afd9f3SGreg Kroah-Hartman return 0; 1176a6afd9f3SGreg Kroah-Hartman } 1177a6afd9f3SGreg Kroah-Hartman 1178a6afd9f3SGreg Kroah-Hartman /* 1179a6afd9f3SGreg Kroah-Hartman * rs_break() --- routine which turns the break handling on or off 1180a6afd9f3SGreg Kroah-Hartman */ 1181a6afd9f3SGreg Kroah-Hartman static int rs_break(struct tty_struct *tty, int break_state) 1182a6afd9f3SGreg Kroah-Hartman { 1183916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 1184a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1185a6afd9f3SGreg Kroah-Hartman 1186a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_break")) 1187a6afd9f3SGreg Kroah-Hartman return -EINVAL; 1188a6afd9f3SGreg Kroah-Hartman 1189a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1190a6afd9f3SGreg Kroah-Hartman if (break_state == -1) 1191a6afd9f3SGreg Kroah-Hartman custom.adkcon = AC_SETCLR | AC_UARTBRK; 1192a6afd9f3SGreg Kroah-Hartman else 1193a6afd9f3SGreg Kroah-Hartman custom.adkcon = AC_UARTBRK; 1194a6afd9f3SGreg Kroah-Hartman mb(); 1195a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1196a6afd9f3SGreg Kroah-Hartman return 0; 1197a6afd9f3SGreg Kroah-Hartman } 1198a6afd9f3SGreg Kroah-Hartman 1199a6afd9f3SGreg Kroah-Hartman /* 1200a6afd9f3SGreg Kroah-Hartman * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) 1201a6afd9f3SGreg Kroah-Hartman * Return: write counters to the user passed counter struct 1202a6afd9f3SGreg Kroah-Hartman * NB: both 1->0 and 0->1 transitions are counted except for 1203a6afd9f3SGreg Kroah-Hartman * RI where only 0->1 is counted. 1204a6afd9f3SGreg Kroah-Hartman */ 1205a6afd9f3SGreg Kroah-Hartman static int rs_get_icount(struct tty_struct *tty, 1206a6afd9f3SGreg Kroah-Hartman struct serial_icounter_struct *icount) 1207a6afd9f3SGreg Kroah-Hartman { 1208916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 1209a6afd9f3SGreg Kroah-Hartman struct async_icount cnow; 1210a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1211a6afd9f3SGreg Kroah-Hartman 1212a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1213916b7656SJiri Slaby cnow = info->icount; 1214a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1215a6afd9f3SGreg Kroah-Hartman icount->cts = cnow.cts; 1216a6afd9f3SGreg Kroah-Hartman icount->dsr = cnow.dsr; 1217a6afd9f3SGreg Kroah-Hartman icount->rng = cnow.rng; 1218a6afd9f3SGreg Kroah-Hartman icount->dcd = cnow.dcd; 1219a6afd9f3SGreg Kroah-Hartman icount->rx = cnow.rx; 1220a6afd9f3SGreg Kroah-Hartman icount->tx = cnow.tx; 1221a6afd9f3SGreg Kroah-Hartman icount->frame = cnow.frame; 1222a6afd9f3SGreg Kroah-Hartman icount->overrun = cnow.overrun; 1223a6afd9f3SGreg Kroah-Hartman icount->parity = cnow.parity; 1224a6afd9f3SGreg Kroah-Hartman icount->brk = cnow.brk; 1225a6afd9f3SGreg Kroah-Hartman icount->buf_overrun = cnow.buf_overrun; 1226a6afd9f3SGreg Kroah-Hartman 1227a6afd9f3SGreg Kroah-Hartman return 0; 1228a6afd9f3SGreg Kroah-Hartman } 1229a6afd9f3SGreg Kroah-Hartman 1230a6afd9f3SGreg Kroah-Hartman static int rs_ioctl(struct tty_struct *tty, 1231a6afd9f3SGreg Kroah-Hartman unsigned int cmd, unsigned long arg) 1232a6afd9f3SGreg Kroah-Hartman { 1233916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 1234a6afd9f3SGreg Kroah-Hartman struct async_icount cprev, cnow; /* kernel counter temps */ 1235a6afd9f3SGreg Kroah-Hartman void __user *argp = (void __user *)arg; 1236a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1237a6afd9f3SGreg Kroah-Hartman 1238a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_ioctl")) 1239a6afd9f3SGreg Kroah-Hartman return -ENODEV; 1240a6afd9f3SGreg Kroah-Hartman 1241a6afd9f3SGreg Kroah-Hartman if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && 1242a6afd9f3SGreg Kroah-Hartman (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && 1243a6afd9f3SGreg Kroah-Hartman (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { 1244a6afd9f3SGreg Kroah-Hartman if (tty->flags & (1 << TTY_IO_ERROR)) 1245a6afd9f3SGreg Kroah-Hartman return -EIO; 1246a6afd9f3SGreg Kroah-Hartman } 1247a6afd9f3SGreg Kroah-Hartman 1248a6afd9f3SGreg Kroah-Hartman switch (cmd) { 1249a6afd9f3SGreg Kroah-Hartman case TIOCGSERIAL: 1250a6afd9f3SGreg Kroah-Hartman return get_serial_info(info, argp); 1251a6afd9f3SGreg Kroah-Hartman case TIOCSSERIAL: 1252588993ddSJiri Slaby return set_serial_info(tty, info, argp); 1253a6afd9f3SGreg Kroah-Hartman case TIOCSERCONFIG: 1254a6afd9f3SGreg Kroah-Hartman return 0; 1255a6afd9f3SGreg Kroah-Hartman 1256a6afd9f3SGreg Kroah-Hartman case TIOCSERGETLSR: /* Get line status register */ 1257a6afd9f3SGreg Kroah-Hartman return get_lsr_info(info, argp); 1258a6afd9f3SGreg Kroah-Hartman 1259a6afd9f3SGreg Kroah-Hartman case TIOCSERGSTRUCT: 1260a6afd9f3SGreg Kroah-Hartman if (copy_to_user(argp, 1261916b7656SJiri Slaby info, sizeof(struct serial_state))) 1262a6afd9f3SGreg Kroah-Hartman return -EFAULT; 1263a6afd9f3SGreg Kroah-Hartman return 0; 1264a6afd9f3SGreg Kroah-Hartman 1265a6afd9f3SGreg Kroah-Hartman /* 1266a6afd9f3SGreg Kroah-Hartman * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change 1267a6afd9f3SGreg Kroah-Hartman * - mask passed in arg for lines of interest 1268a6afd9f3SGreg Kroah-Hartman * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) 1269a6afd9f3SGreg Kroah-Hartman * Caller should use TIOCGICOUNT to see which one it was 1270a6afd9f3SGreg Kroah-Hartman */ 1271a6afd9f3SGreg Kroah-Hartman case TIOCMIWAIT: 1272a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1273a6afd9f3SGreg Kroah-Hartman /* note the counters on entry */ 1274916b7656SJiri Slaby cprev = info->icount; 1275a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1276a6afd9f3SGreg Kroah-Hartman while (1) { 1277*87758791SJiri Slaby interruptible_sleep_on(&info->tport.delta_msr_wait); 1278a6afd9f3SGreg Kroah-Hartman /* see if a signal did it */ 1279a6afd9f3SGreg Kroah-Hartman if (signal_pending(current)) 1280a6afd9f3SGreg Kroah-Hartman return -ERESTARTSYS; 1281a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1282916b7656SJiri Slaby cnow = info->icount; /* atomic copy */ 1283a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1284a6afd9f3SGreg Kroah-Hartman if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 1285a6afd9f3SGreg Kroah-Hartman cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) 1286a6afd9f3SGreg Kroah-Hartman return -EIO; /* no change => error */ 1287a6afd9f3SGreg Kroah-Hartman if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || 1288a6afd9f3SGreg Kroah-Hartman ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || 1289a6afd9f3SGreg Kroah-Hartman ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || 1290a6afd9f3SGreg Kroah-Hartman ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { 1291a6afd9f3SGreg Kroah-Hartman return 0; 1292a6afd9f3SGreg Kroah-Hartman } 1293a6afd9f3SGreg Kroah-Hartman cprev = cnow; 1294a6afd9f3SGreg Kroah-Hartman } 1295a6afd9f3SGreg Kroah-Hartman /* NOTREACHED */ 1296a6afd9f3SGreg Kroah-Hartman 1297a6afd9f3SGreg Kroah-Hartman case TIOCSERGWILD: 1298a6afd9f3SGreg Kroah-Hartman case TIOCSERSWILD: 1299a6afd9f3SGreg Kroah-Hartman /* "setserial -W" is called in Debian boot */ 1300a6afd9f3SGreg Kroah-Hartman printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); 1301a6afd9f3SGreg Kroah-Hartman return 0; 1302a6afd9f3SGreg Kroah-Hartman 1303a6afd9f3SGreg Kroah-Hartman default: 1304a6afd9f3SGreg Kroah-Hartman return -ENOIOCTLCMD; 1305a6afd9f3SGreg Kroah-Hartman } 1306a6afd9f3SGreg Kroah-Hartman return 0; 1307a6afd9f3SGreg Kroah-Hartman } 1308a6afd9f3SGreg Kroah-Hartman 1309a6afd9f3SGreg Kroah-Hartman static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) 1310a6afd9f3SGreg Kroah-Hartman { 1311916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 1312a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1313a6afd9f3SGreg Kroah-Hartman unsigned int cflag = tty->termios->c_cflag; 1314a6afd9f3SGreg Kroah-Hartman 1315588993ddSJiri Slaby change_speed(tty, info, old_termios); 1316a6afd9f3SGreg Kroah-Hartman 1317a6afd9f3SGreg Kroah-Hartman /* Handle transition to B0 status */ 1318a6afd9f3SGreg Kroah-Hartman if ((old_termios->c_cflag & CBAUD) && 1319a6afd9f3SGreg Kroah-Hartman !(cflag & CBAUD)) { 1320a6afd9f3SGreg Kroah-Hartman info->MCR &= ~(SER_DTR|SER_RTS); 1321a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1322a6afd9f3SGreg Kroah-Hartman rtsdtr_ctrl(info->MCR); 1323a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1324a6afd9f3SGreg Kroah-Hartman } 1325a6afd9f3SGreg Kroah-Hartman 1326a6afd9f3SGreg Kroah-Hartman /* Handle transition away from B0 status */ 1327a6afd9f3SGreg Kroah-Hartman if (!(old_termios->c_cflag & CBAUD) && 1328a6afd9f3SGreg Kroah-Hartman (cflag & CBAUD)) { 1329a6afd9f3SGreg Kroah-Hartman info->MCR |= SER_DTR; 1330a6afd9f3SGreg Kroah-Hartman if (!(tty->termios->c_cflag & CRTSCTS) || 1331a6afd9f3SGreg Kroah-Hartman !test_bit(TTY_THROTTLED, &tty->flags)) { 1332a6afd9f3SGreg Kroah-Hartman info->MCR |= SER_RTS; 1333a6afd9f3SGreg Kroah-Hartman } 1334a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1335a6afd9f3SGreg Kroah-Hartman rtsdtr_ctrl(info->MCR); 1336a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1337a6afd9f3SGreg Kroah-Hartman } 1338a6afd9f3SGreg Kroah-Hartman 1339a6afd9f3SGreg Kroah-Hartman /* Handle turning off CRTSCTS */ 1340a6afd9f3SGreg Kroah-Hartman if ((old_termios->c_cflag & CRTSCTS) && 1341a6afd9f3SGreg Kroah-Hartman !(tty->termios->c_cflag & CRTSCTS)) { 1342a6afd9f3SGreg Kroah-Hartman tty->hw_stopped = 0; 1343a6afd9f3SGreg Kroah-Hartman rs_start(tty); 1344a6afd9f3SGreg Kroah-Hartman } 1345a6afd9f3SGreg Kroah-Hartman 1346a6afd9f3SGreg Kroah-Hartman #if 0 1347a6afd9f3SGreg Kroah-Hartman /* 1348a6afd9f3SGreg Kroah-Hartman * No need to wake up processes in open wait, since they 1349a6afd9f3SGreg Kroah-Hartman * sample the CLOCAL flag once, and don't recheck it. 1350a6afd9f3SGreg Kroah-Hartman * XXX It's not clear whether the current behavior is correct 1351a6afd9f3SGreg Kroah-Hartman * or not. Hence, this may change..... 1352a6afd9f3SGreg Kroah-Hartman */ 1353a6afd9f3SGreg Kroah-Hartman if (!(old_termios->c_cflag & CLOCAL) && 1354a6afd9f3SGreg Kroah-Hartman (tty->termios->c_cflag & CLOCAL)) 1355a6afd9f3SGreg Kroah-Hartman wake_up_interruptible(&info->open_wait); 1356a6afd9f3SGreg Kroah-Hartman #endif 1357a6afd9f3SGreg Kroah-Hartman } 1358a6afd9f3SGreg Kroah-Hartman 1359a6afd9f3SGreg Kroah-Hartman /* 1360a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 1361a6afd9f3SGreg Kroah-Hartman * rs_close() 1362a6afd9f3SGreg Kroah-Hartman * 1363a6afd9f3SGreg Kroah-Hartman * This routine is called when the serial port gets closed. First, we 1364a6afd9f3SGreg Kroah-Hartman * wait for the last remaining data to be sent. Then, we unlink its 1365a6afd9f3SGreg Kroah-Hartman * async structure from the interrupt chain if necessary, and we free 1366a6afd9f3SGreg Kroah-Hartman * that IRQ if nothing is left in the chain. 1367a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 1368a6afd9f3SGreg Kroah-Hartman */ 1369a6afd9f3SGreg Kroah-Hartman static void rs_close(struct tty_struct *tty, struct file * filp) 1370a6afd9f3SGreg Kroah-Hartman { 1371916b7656SJiri Slaby struct serial_state *state = tty->driver_data; 1372a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1373a6afd9f3SGreg Kroah-Hartman 1374916b7656SJiri Slaby if (!state || serial_paranoia_check(state, tty->name, "rs_close")) 1375a6afd9f3SGreg Kroah-Hartman return; 1376a6afd9f3SGreg Kroah-Hartman 1377a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1378a6afd9f3SGreg Kroah-Hartman 1379a6afd9f3SGreg Kroah-Hartman if (tty_hung_up_p(filp)) { 1380a6afd9f3SGreg Kroah-Hartman DBG_CNT("before DEC-hung"); 1381a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1382a6afd9f3SGreg Kroah-Hartman return; 1383a6afd9f3SGreg Kroah-Hartman } 1384a6afd9f3SGreg Kroah-Hartman 1385a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 1386916b7656SJiri Slaby printk("rs_close ttys%d, count = %d\n", state->line, state->count); 1387a6afd9f3SGreg Kroah-Hartman #endif 1388a6afd9f3SGreg Kroah-Hartman if ((tty->count == 1) && (state->count != 1)) { 1389a6afd9f3SGreg Kroah-Hartman /* 1390a6afd9f3SGreg Kroah-Hartman * Uh, oh. tty->count is 1, which means that the tty 1391a6afd9f3SGreg Kroah-Hartman * structure will be freed. state->count should always 1392a6afd9f3SGreg Kroah-Hartman * be one in these conditions. If it's greater than 1393a6afd9f3SGreg Kroah-Hartman * one, we've got real problems, since it means the 1394a6afd9f3SGreg Kroah-Hartman * serial port won't be shutdown. 1395a6afd9f3SGreg Kroah-Hartman */ 1396a6afd9f3SGreg Kroah-Hartman printk("rs_close: bad serial port count; tty->count is 1, " 1397a6afd9f3SGreg Kroah-Hartman "state->count is %d\n", state->count); 1398a6afd9f3SGreg Kroah-Hartman state->count = 1; 1399a6afd9f3SGreg Kroah-Hartman } 1400a6afd9f3SGreg Kroah-Hartman if (--state->count < 0) { 1401a6afd9f3SGreg Kroah-Hartman printk("rs_close: bad serial port count for ttys%d: %d\n", 1402d8522563SJiri Slaby state->line, state->count); 1403a6afd9f3SGreg Kroah-Hartman state->count = 0; 1404a6afd9f3SGreg Kroah-Hartman } 1405a6afd9f3SGreg Kroah-Hartman if (state->count) { 1406a6afd9f3SGreg Kroah-Hartman DBG_CNT("before DEC-2"); 1407a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1408a6afd9f3SGreg Kroah-Hartman return; 1409a6afd9f3SGreg Kroah-Hartman } 1410fef21073SJiri Slaby state->flags |= ASYNC_CLOSING; 1411a6afd9f3SGreg Kroah-Hartman /* 1412a6afd9f3SGreg Kroah-Hartman * Now we wait for the transmit buffer to clear; and we notify 1413a6afd9f3SGreg Kroah-Hartman * the line discipline to only process XON/XOFF characters. 1414a6afd9f3SGreg Kroah-Hartman */ 1415a6afd9f3SGreg Kroah-Hartman tty->closing = 1; 1416d8522563SJiri Slaby if (state->closing_wait != ASYNC_CLOSING_WAIT_NONE) 1417d8522563SJiri Slaby tty_wait_until_sent(tty, state->closing_wait); 1418a6afd9f3SGreg Kroah-Hartman /* 1419a6afd9f3SGreg Kroah-Hartman * At this point we stop accepting input. To do this, we 1420a6afd9f3SGreg Kroah-Hartman * disable the receive line status interrupts, and tell the 1421a6afd9f3SGreg Kroah-Hartman * interrupt driver to stop checking the data ready bit in the 1422a6afd9f3SGreg Kroah-Hartman * line status register. 1423a6afd9f3SGreg Kroah-Hartman */ 1424916b7656SJiri Slaby state->read_status_mask &= ~UART_LSR_DR; 1425fef21073SJiri Slaby if (state->flags & ASYNC_INITIALIZED) { 1426a6afd9f3SGreg Kroah-Hartman /* disable receive interrupts */ 1427a6afd9f3SGreg Kroah-Hartman custom.intena = IF_RBF; 1428a6afd9f3SGreg Kroah-Hartman mb(); 1429a6afd9f3SGreg Kroah-Hartman /* clear any pending receive interrupt */ 1430a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_RBF; 1431a6afd9f3SGreg Kroah-Hartman mb(); 1432a6afd9f3SGreg Kroah-Hartman 1433a6afd9f3SGreg Kroah-Hartman /* 1434a6afd9f3SGreg Kroah-Hartman * Before we drop DTR, make sure the UART transmitter 1435a6afd9f3SGreg Kroah-Hartman * has completely drained; this is especially 1436a6afd9f3SGreg Kroah-Hartman * important if there is a transmit FIFO! 1437a6afd9f3SGreg Kroah-Hartman */ 1438916b7656SJiri Slaby rs_wait_until_sent(tty, state->timeout); 1439a6afd9f3SGreg Kroah-Hartman } 1440588993ddSJiri Slaby shutdown(tty, state); 1441a6afd9f3SGreg Kroah-Hartman rs_flush_buffer(tty); 1442a6afd9f3SGreg Kroah-Hartman 1443a6afd9f3SGreg Kroah-Hartman tty_ldisc_flush(tty); 1444a6afd9f3SGreg Kroah-Hartman tty->closing = 0; 1445*87758791SJiri Slaby state->tport.tty = NULL; 1446*87758791SJiri Slaby if (state->tport.blocked_open) { 1447d8522563SJiri Slaby if (state->close_delay) { 1448d8522563SJiri Slaby msleep_interruptible(jiffies_to_msecs(state->close_delay)); 1449a6afd9f3SGreg Kroah-Hartman } 1450*87758791SJiri Slaby wake_up_interruptible(&state->tport.open_wait); 1451a6afd9f3SGreg Kroah-Hartman } 1452fef21073SJiri Slaby state->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); 1453*87758791SJiri Slaby wake_up_interruptible(&state->tport.close_wait); 1454a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1455a6afd9f3SGreg Kroah-Hartman } 1456a6afd9f3SGreg Kroah-Hartman 1457a6afd9f3SGreg Kroah-Hartman /* 1458a6afd9f3SGreg Kroah-Hartman * rs_wait_until_sent() --- wait until the transmitter is empty 1459a6afd9f3SGreg Kroah-Hartman */ 1460a6afd9f3SGreg Kroah-Hartman static void rs_wait_until_sent(struct tty_struct *tty, int timeout) 1461a6afd9f3SGreg Kroah-Hartman { 1462916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 1463a6afd9f3SGreg Kroah-Hartman unsigned long orig_jiffies, char_time; 1464a6afd9f3SGreg Kroah-Hartman int lsr; 1465a6afd9f3SGreg Kroah-Hartman 1466a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) 1467a6afd9f3SGreg Kroah-Hartman return; 1468a6afd9f3SGreg Kroah-Hartman 1469916b7656SJiri Slaby if (info->xmit_fifo_size == 0) 1470a6afd9f3SGreg Kroah-Hartman return; /* Just in case.... */ 1471a6afd9f3SGreg Kroah-Hartman 1472a6afd9f3SGreg Kroah-Hartman orig_jiffies = jiffies; 1473a6afd9f3SGreg Kroah-Hartman 1474a6afd9f3SGreg Kroah-Hartman /* 1475a6afd9f3SGreg Kroah-Hartman * Set the check interval to be 1/5 of the estimated time to 1476a6afd9f3SGreg Kroah-Hartman * send a single character, and make it at least 1. The check 1477a6afd9f3SGreg Kroah-Hartman * interval should also be less than the timeout. 1478a6afd9f3SGreg Kroah-Hartman * 1479a6afd9f3SGreg Kroah-Hartman * Note: we have to use pretty tight timings here to satisfy 1480a6afd9f3SGreg Kroah-Hartman * the NIST-PCTS. 1481a6afd9f3SGreg Kroah-Hartman */ 1482916b7656SJiri Slaby char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; 1483a6afd9f3SGreg Kroah-Hartman char_time = char_time / 5; 1484a6afd9f3SGreg Kroah-Hartman if (char_time == 0) 1485a6afd9f3SGreg Kroah-Hartman char_time = 1; 1486a6afd9f3SGreg Kroah-Hartman if (timeout) 1487a6afd9f3SGreg Kroah-Hartman char_time = min_t(unsigned long, char_time, timeout); 1488a6afd9f3SGreg Kroah-Hartman /* 1489a6afd9f3SGreg Kroah-Hartman * If the transmitter hasn't cleared in twice the approximate 1490a6afd9f3SGreg Kroah-Hartman * amount of time to send the entire FIFO, it probably won't 1491a6afd9f3SGreg Kroah-Hartman * ever clear. This assumes the UART isn't doing flow 1492a6afd9f3SGreg Kroah-Hartman * control, which is currently the case. Hence, if it ever 1493a6afd9f3SGreg Kroah-Hartman * takes longer than info->timeout, this is probably due to a 1494a6afd9f3SGreg Kroah-Hartman * UART bug of some kind. So, we clamp the timeout parameter at 1495a6afd9f3SGreg Kroah-Hartman * 2*info->timeout. 1496a6afd9f3SGreg Kroah-Hartman */ 1497a6afd9f3SGreg Kroah-Hartman if (!timeout || timeout > 2*info->timeout) 1498a6afd9f3SGreg Kroah-Hartman timeout = 2*info->timeout; 1499a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT 1500a6afd9f3SGreg Kroah-Hartman printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); 1501a6afd9f3SGreg Kroah-Hartman printk("jiff=%lu...", jiffies); 1502a6afd9f3SGreg Kroah-Hartman #endif 1503a6afd9f3SGreg Kroah-Hartman while(!((lsr = custom.serdatr) & SDR_TSRE)) { 1504a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT 1505a6afd9f3SGreg Kroah-Hartman printk("serdatr = %d (jiff=%lu)...", lsr, jiffies); 1506a6afd9f3SGreg Kroah-Hartman #endif 1507a6afd9f3SGreg Kroah-Hartman msleep_interruptible(jiffies_to_msecs(char_time)); 1508a6afd9f3SGreg Kroah-Hartman if (signal_pending(current)) 1509a6afd9f3SGreg Kroah-Hartman break; 1510a6afd9f3SGreg Kroah-Hartman if (timeout && time_after(jiffies, orig_jiffies + timeout)) 1511a6afd9f3SGreg Kroah-Hartman break; 1512a6afd9f3SGreg Kroah-Hartman } 1513a6afd9f3SGreg Kroah-Hartman __set_current_state(TASK_RUNNING); 1514eff4b0b9SJiri Slaby 1515a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT 1516a6afd9f3SGreg Kroah-Hartman printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); 1517a6afd9f3SGreg Kroah-Hartman #endif 1518a6afd9f3SGreg Kroah-Hartman } 1519a6afd9f3SGreg Kroah-Hartman 1520a6afd9f3SGreg Kroah-Hartman /* 1521a6afd9f3SGreg Kroah-Hartman * rs_hangup() --- called by tty_hangup() when a hangup is signaled. 1522a6afd9f3SGreg Kroah-Hartman */ 1523a6afd9f3SGreg Kroah-Hartman static void rs_hangup(struct tty_struct *tty) 1524a6afd9f3SGreg Kroah-Hartman { 1525916b7656SJiri Slaby struct serial_state *info = tty->driver_data; 1526a6afd9f3SGreg Kroah-Hartman 1527a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_hangup")) 1528a6afd9f3SGreg Kroah-Hartman return; 1529a6afd9f3SGreg Kroah-Hartman 1530a6afd9f3SGreg Kroah-Hartman rs_flush_buffer(tty); 1531588993ddSJiri Slaby shutdown(tty, info); 1532916b7656SJiri Slaby info->count = 0; 1533916b7656SJiri Slaby info->flags &= ~ASYNC_NORMAL_ACTIVE; 1534*87758791SJiri Slaby info->tport.tty = NULL; 1535*87758791SJiri Slaby wake_up_interruptible(&info->tport.open_wait); 1536a6afd9f3SGreg Kroah-Hartman } 1537a6afd9f3SGreg Kroah-Hartman 1538a6afd9f3SGreg Kroah-Hartman /* 1539a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 1540a6afd9f3SGreg Kroah-Hartman * rs_open() and friends 1541a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 1542a6afd9f3SGreg Kroah-Hartman */ 1543a6afd9f3SGreg Kroah-Hartman static int block_til_ready(struct tty_struct *tty, struct file * filp, 1544916b7656SJiri Slaby struct serial_state *info) 1545a6afd9f3SGreg Kroah-Hartman { 1546a6afd9f3SGreg Kroah-Hartman #ifdef DECLARE_WAITQUEUE 1547a6afd9f3SGreg Kroah-Hartman DECLARE_WAITQUEUE(wait, current); 1548a6afd9f3SGreg Kroah-Hartman #else 1549a6afd9f3SGreg Kroah-Hartman struct wait_queue wait = { current, NULL }; 1550a6afd9f3SGreg Kroah-Hartman #endif 1551a6afd9f3SGreg Kroah-Hartman int retval; 1552a6afd9f3SGreg Kroah-Hartman int do_clocal = 0, extra_count = 0; 1553a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1554a6afd9f3SGreg Kroah-Hartman 1555a6afd9f3SGreg Kroah-Hartman /* 1556a6afd9f3SGreg Kroah-Hartman * If the device is in the middle of being closed, then block 1557a6afd9f3SGreg Kroah-Hartman * until it's done, and then try again. 1558a6afd9f3SGreg Kroah-Hartman */ 1559a6afd9f3SGreg Kroah-Hartman if (tty_hung_up_p(filp) || 1560916b7656SJiri Slaby (info->flags & ASYNC_CLOSING)) { 1561916b7656SJiri Slaby if (info->flags & ASYNC_CLOSING) 1562*87758791SJiri Slaby interruptible_sleep_on(&info->tport.close_wait); 1563a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DO_RESTART 1564916b7656SJiri Slaby return ((info->flags & ASYNC_HUP_NOTIFY) ? 1565a6afd9f3SGreg Kroah-Hartman -EAGAIN : -ERESTARTSYS); 1566a6afd9f3SGreg Kroah-Hartman #else 1567a6afd9f3SGreg Kroah-Hartman return -EAGAIN; 1568a6afd9f3SGreg Kroah-Hartman #endif 1569a6afd9f3SGreg Kroah-Hartman } 1570a6afd9f3SGreg Kroah-Hartman 1571a6afd9f3SGreg Kroah-Hartman /* 1572a6afd9f3SGreg Kroah-Hartman * If non-blocking mode is set, or the port is not enabled, 1573a6afd9f3SGreg Kroah-Hartman * then make the check up front and then exit. 1574a6afd9f3SGreg Kroah-Hartman */ 1575a6afd9f3SGreg Kroah-Hartman if ((filp->f_flags & O_NONBLOCK) || 1576a6afd9f3SGreg Kroah-Hartman (tty->flags & (1 << TTY_IO_ERROR))) { 1577916b7656SJiri Slaby info->flags |= ASYNC_NORMAL_ACTIVE; 1578a6afd9f3SGreg Kroah-Hartman return 0; 1579a6afd9f3SGreg Kroah-Hartman } 1580a6afd9f3SGreg Kroah-Hartman 1581a6afd9f3SGreg Kroah-Hartman if (tty->termios->c_cflag & CLOCAL) 1582a6afd9f3SGreg Kroah-Hartman do_clocal = 1; 1583a6afd9f3SGreg Kroah-Hartman 1584a6afd9f3SGreg Kroah-Hartman /* 1585a6afd9f3SGreg Kroah-Hartman * Block waiting for the carrier detect and the line to become 1586a6afd9f3SGreg Kroah-Hartman * free (i.e., not in use by the callout). While we are in 1587916b7656SJiri Slaby * this loop, info->count is dropped by one, so that 1588a6afd9f3SGreg Kroah-Hartman * rs_close() knows when to free things. We restore it upon 1589a6afd9f3SGreg Kroah-Hartman * exit, either normal or abnormal. 1590a6afd9f3SGreg Kroah-Hartman */ 1591a6afd9f3SGreg Kroah-Hartman retval = 0; 1592*87758791SJiri Slaby add_wait_queue(&info->tport.open_wait, &wait); 1593a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 1594a6afd9f3SGreg Kroah-Hartman printk("block_til_ready before block: ttys%d, count = %d\n", 1595916b7656SJiri Slaby info->line, info->count); 1596a6afd9f3SGreg Kroah-Hartman #endif 1597a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1598a6afd9f3SGreg Kroah-Hartman if (!tty_hung_up_p(filp)) { 1599a6afd9f3SGreg Kroah-Hartman extra_count = 1; 1600916b7656SJiri Slaby info->count--; 1601a6afd9f3SGreg Kroah-Hartman } 1602a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1603*87758791SJiri Slaby info->tport.blocked_open++; 1604a6afd9f3SGreg Kroah-Hartman while (1) { 1605a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1606a6afd9f3SGreg Kroah-Hartman if (tty->termios->c_cflag & CBAUD) 1607a6afd9f3SGreg Kroah-Hartman rtsdtr_ctrl(SER_DTR|SER_RTS); 1608a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1609a6afd9f3SGreg Kroah-Hartman set_current_state(TASK_INTERRUPTIBLE); 1610a6afd9f3SGreg Kroah-Hartman if (tty_hung_up_p(filp) || 1611916b7656SJiri Slaby !(info->flags & ASYNC_INITIALIZED)) { 1612a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DO_RESTART 1613916b7656SJiri Slaby if (info->flags & ASYNC_HUP_NOTIFY) 1614a6afd9f3SGreg Kroah-Hartman retval = -EAGAIN; 1615a6afd9f3SGreg Kroah-Hartman else 1616a6afd9f3SGreg Kroah-Hartman retval = -ERESTARTSYS; 1617a6afd9f3SGreg Kroah-Hartman #else 1618a6afd9f3SGreg Kroah-Hartman retval = -EAGAIN; 1619a6afd9f3SGreg Kroah-Hartman #endif 1620a6afd9f3SGreg Kroah-Hartman break; 1621a6afd9f3SGreg Kroah-Hartman } 1622916b7656SJiri Slaby if (!(info->flags & ASYNC_CLOSING) && 1623a6afd9f3SGreg Kroah-Hartman (do_clocal || (!(ciab.pra & SER_DCD)) )) 1624a6afd9f3SGreg Kroah-Hartman break; 1625a6afd9f3SGreg Kroah-Hartman if (signal_pending(current)) { 1626a6afd9f3SGreg Kroah-Hartman retval = -ERESTARTSYS; 1627a6afd9f3SGreg Kroah-Hartman break; 1628a6afd9f3SGreg Kroah-Hartman } 1629a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 1630a6afd9f3SGreg Kroah-Hartman printk("block_til_ready blocking: ttys%d, count = %d\n", 1631916b7656SJiri Slaby info->line, info->count); 1632a6afd9f3SGreg Kroah-Hartman #endif 1633a6afd9f3SGreg Kroah-Hartman tty_unlock(); 1634a6afd9f3SGreg Kroah-Hartman schedule(); 1635a6afd9f3SGreg Kroah-Hartman tty_lock(); 1636a6afd9f3SGreg Kroah-Hartman } 1637a6afd9f3SGreg Kroah-Hartman __set_current_state(TASK_RUNNING); 1638*87758791SJiri Slaby remove_wait_queue(&info->tport.open_wait, &wait); 1639a6afd9f3SGreg Kroah-Hartman if (extra_count) 1640916b7656SJiri Slaby info->count++; 1641*87758791SJiri Slaby info->tport.blocked_open--; 1642a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 1643a6afd9f3SGreg Kroah-Hartman printk("block_til_ready after blocking: ttys%d, count = %d\n", 1644916b7656SJiri Slaby info->line, info->count); 1645a6afd9f3SGreg Kroah-Hartman #endif 1646a6afd9f3SGreg Kroah-Hartman if (retval) 1647a6afd9f3SGreg Kroah-Hartman return retval; 1648916b7656SJiri Slaby info->flags |= ASYNC_NORMAL_ACTIVE; 1649a6afd9f3SGreg Kroah-Hartman return 0; 1650a6afd9f3SGreg Kroah-Hartman } 1651a6afd9f3SGreg Kroah-Hartman 1652a6afd9f3SGreg Kroah-Hartman /* 1653a6afd9f3SGreg Kroah-Hartman * This routine is called whenever a serial port is opened. It 1654a6afd9f3SGreg Kroah-Hartman * enables interrupts for a serial port, linking in its async structure into 1655a6afd9f3SGreg Kroah-Hartman * the IRQ chain. It also performs the serial-specific 1656a6afd9f3SGreg Kroah-Hartman * initialization for the tty structure. 1657a6afd9f3SGreg Kroah-Hartman */ 1658a6afd9f3SGreg Kroah-Hartman static int rs_open(struct tty_struct *tty, struct file * filp) 1659a6afd9f3SGreg Kroah-Hartman { 1660916b7656SJiri Slaby struct serial_state *info = rs_table + tty->index; 1661410235fdSJiri Slaby int retval; 1662a6afd9f3SGreg Kroah-Hartman 1663916b7656SJiri Slaby info->count++; 1664*87758791SJiri Slaby info->tport.tty = tty; 1665916b7656SJiri Slaby tty->driver_data = info; 1666*87758791SJiri Slaby tty->port = &info->tport; 1667a6afd9f3SGreg Kroah-Hartman if (serial_paranoia_check(info, tty->name, "rs_open")) 1668a6afd9f3SGreg Kroah-Hartman return -ENODEV; 1669a6afd9f3SGreg Kroah-Hartman 1670a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 1671916b7656SJiri Slaby printk("rs_open %s, count = %d\n", tty->name, info->count); 1672a6afd9f3SGreg Kroah-Hartman #endif 1673916b7656SJiri Slaby tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; 1674a6afd9f3SGreg Kroah-Hartman 1675a6afd9f3SGreg Kroah-Hartman /* 1676a6afd9f3SGreg Kroah-Hartman * If the port is the middle of closing, bail out now 1677a6afd9f3SGreg Kroah-Hartman */ 1678a6afd9f3SGreg Kroah-Hartman if (tty_hung_up_p(filp) || 1679916b7656SJiri Slaby (info->flags & ASYNC_CLOSING)) { 1680916b7656SJiri Slaby if (info->flags & ASYNC_CLOSING) 1681*87758791SJiri Slaby interruptible_sleep_on(&info->tport.close_wait); 1682a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DO_RESTART 1683916b7656SJiri Slaby return ((info->flags & ASYNC_HUP_NOTIFY) ? 1684a6afd9f3SGreg Kroah-Hartman -EAGAIN : -ERESTARTSYS); 1685a6afd9f3SGreg Kroah-Hartman #else 1686a6afd9f3SGreg Kroah-Hartman return -EAGAIN; 1687a6afd9f3SGreg Kroah-Hartman #endif 1688a6afd9f3SGreg Kroah-Hartman } 1689a6afd9f3SGreg Kroah-Hartman 1690a6afd9f3SGreg Kroah-Hartman /* 1691a6afd9f3SGreg Kroah-Hartman * Start up serial port 1692a6afd9f3SGreg Kroah-Hartman */ 1693588993ddSJiri Slaby retval = startup(tty, info); 1694a6afd9f3SGreg Kroah-Hartman if (retval) { 1695a6afd9f3SGreg Kroah-Hartman return retval; 1696a6afd9f3SGreg Kroah-Hartman } 1697a6afd9f3SGreg Kroah-Hartman 1698a6afd9f3SGreg Kroah-Hartman retval = block_til_ready(tty, filp, info); 1699a6afd9f3SGreg Kroah-Hartman if (retval) { 1700a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 1701a6afd9f3SGreg Kroah-Hartman printk("rs_open returning after block_til_ready with %d\n", 1702a6afd9f3SGreg Kroah-Hartman retval); 1703a6afd9f3SGreg Kroah-Hartman #endif 1704a6afd9f3SGreg Kroah-Hartman return retval; 1705a6afd9f3SGreg Kroah-Hartman } 1706a6afd9f3SGreg Kroah-Hartman 1707a6afd9f3SGreg Kroah-Hartman #ifdef SERIAL_DEBUG_OPEN 1708a6afd9f3SGreg Kroah-Hartman printk("rs_open %s successful...", tty->name); 1709a6afd9f3SGreg Kroah-Hartman #endif 1710a6afd9f3SGreg Kroah-Hartman return 0; 1711a6afd9f3SGreg Kroah-Hartman } 1712a6afd9f3SGreg Kroah-Hartman 1713a6afd9f3SGreg Kroah-Hartman /* 1714a6afd9f3SGreg Kroah-Hartman * /proc fs routines.... 1715a6afd9f3SGreg Kroah-Hartman */ 1716a6afd9f3SGreg Kroah-Hartman 1717a6afd9f3SGreg Kroah-Hartman static inline void line_info(struct seq_file *m, struct serial_state *state) 1718a6afd9f3SGreg Kroah-Hartman { 1719a6afd9f3SGreg Kroah-Hartman char stat_buf[30], control, status; 1720a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1721a6afd9f3SGreg Kroah-Hartman 1722a6afd9f3SGreg Kroah-Hartman seq_printf(m, "%d: uart:amiga_builtin",state->line); 1723a6afd9f3SGreg Kroah-Hartman 1724a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1725a6afd9f3SGreg Kroah-Hartman status = ciab.pra; 1726916b7656SJiri Slaby control = (state->flags & ASYNC_INITIALIZED) ? state->MCR : status; 1727a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1728a6afd9f3SGreg Kroah-Hartman 1729a6afd9f3SGreg Kroah-Hartman stat_buf[0] = 0; 1730a6afd9f3SGreg Kroah-Hartman stat_buf[1] = 0; 1731a6afd9f3SGreg Kroah-Hartman if(!(control & SER_RTS)) 1732a6afd9f3SGreg Kroah-Hartman strcat(stat_buf, "|RTS"); 1733a6afd9f3SGreg Kroah-Hartman if(!(status & SER_CTS)) 1734a6afd9f3SGreg Kroah-Hartman strcat(stat_buf, "|CTS"); 1735a6afd9f3SGreg Kroah-Hartman if(!(control & SER_DTR)) 1736a6afd9f3SGreg Kroah-Hartman strcat(stat_buf, "|DTR"); 1737a6afd9f3SGreg Kroah-Hartman if(!(status & SER_DSR)) 1738a6afd9f3SGreg Kroah-Hartman strcat(stat_buf, "|DSR"); 1739a6afd9f3SGreg Kroah-Hartman if(!(status & SER_DCD)) 1740a6afd9f3SGreg Kroah-Hartman strcat(stat_buf, "|CD"); 1741a6afd9f3SGreg Kroah-Hartman 1742916b7656SJiri Slaby if (state->quot) 1743916b7656SJiri Slaby seq_printf(m, " baud:%d", state->baud_base / state->quot); 1744a6afd9f3SGreg Kroah-Hartman 1745a6afd9f3SGreg Kroah-Hartman seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx); 1746a6afd9f3SGreg Kroah-Hartman 1747a6afd9f3SGreg Kroah-Hartman if (state->icount.frame) 1748a6afd9f3SGreg Kroah-Hartman seq_printf(m, " fe:%d", state->icount.frame); 1749a6afd9f3SGreg Kroah-Hartman 1750a6afd9f3SGreg Kroah-Hartman if (state->icount.parity) 1751a6afd9f3SGreg Kroah-Hartman seq_printf(m, " pe:%d", state->icount.parity); 1752a6afd9f3SGreg Kroah-Hartman 1753a6afd9f3SGreg Kroah-Hartman if (state->icount.brk) 1754a6afd9f3SGreg Kroah-Hartman seq_printf(m, " brk:%d", state->icount.brk); 1755a6afd9f3SGreg Kroah-Hartman 1756a6afd9f3SGreg Kroah-Hartman if (state->icount.overrun) 1757a6afd9f3SGreg Kroah-Hartman seq_printf(m, " oe:%d", state->icount.overrun); 1758a6afd9f3SGreg Kroah-Hartman 1759a6afd9f3SGreg Kroah-Hartman /* 1760a6afd9f3SGreg Kroah-Hartman * Last thing is the RS-232 status lines 1761a6afd9f3SGreg Kroah-Hartman */ 1762a6afd9f3SGreg Kroah-Hartman seq_printf(m, " %s\n", stat_buf+1); 1763a6afd9f3SGreg Kroah-Hartman } 1764a6afd9f3SGreg Kroah-Hartman 1765a6afd9f3SGreg Kroah-Hartman static int rs_proc_show(struct seq_file *m, void *v) 1766a6afd9f3SGreg Kroah-Hartman { 1767a6afd9f3SGreg Kroah-Hartman seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); 1768a6afd9f3SGreg Kroah-Hartman line_info(m, &rs_table[0]); 1769a6afd9f3SGreg Kroah-Hartman return 0; 1770a6afd9f3SGreg Kroah-Hartman } 1771a6afd9f3SGreg Kroah-Hartman 1772a6afd9f3SGreg Kroah-Hartman static int rs_proc_open(struct inode *inode, struct file *file) 1773a6afd9f3SGreg Kroah-Hartman { 1774a6afd9f3SGreg Kroah-Hartman return single_open(file, rs_proc_show, NULL); 1775a6afd9f3SGreg Kroah-Hartman } 1776a6afd9f3SGreg Kroah-Hartman 1777a6afd9f3SGreg Kroah-Hartman static const struct file_operations rs_proc_fops = { 1778a6afd9f3SGreg Kroah-Hartman .owner = THIS_MODULE, 1779a6afd9f3SGreg Kroah-Hartman .open = rs_proc_open, 1780a6afd9f3SGreg Kroah-Hartman .read = seq_read, 1781a6afd9f3SGreg Kroah-Hartman .llseek = seq_lseek, 1782a6afd9f3SGreg Kroah-Hartman .release = single_release, 1783a6afd9f3SGreg Kroah-Hartman }; 1784a6afd9f3SGreg Kroah-Hartman 1785a6afd9f3SGreg Kroah-Hartman /* 1786a6afd9f3SGreg Kroah-Hartman * --------------------------------------------------------------------- 1787a6afd9f3SGreg Kroah-Hartman * rs_init() and friends 1788a6afd9f3SGreg Kroah-Hartman * 1789a6afd9f3SGreg Kroah-Hartman * rs_init() is called at boot-time to initialize the serial driver. 1790a6afd9f3SGreg Kroah-Hartman * --------------------------------------------------------------------- 1791a6afd9f3SGreg Kroah-Hartman */ 1792a6afd9f3SGreg Kroah-Hartman 1793a6afd9f3SGreg Kroah-Hartman /* 1794a6afd9f3SGreg Kroah-Hartman * This routine prints out the appropriate serial driver version 1795a6afd9f3SGreg Kroah-Hartman * number, and identifies which options were configured into this 1796a6afd9f3SGreg Kroah-Hartman * driver. 1797a6afd9f3SGreg Kroah-Hartman */ 1798a6afd9f3SGreg Kroah-Hartman static void show_serial_version(void) 1799a6afd9f3SGreg Kroah-Hartman { 1800a6afd9f3SGreg Kroah-Hartman printk(KERN_INFO "%s version %s\n", serial_name, serial_version); 1801a6afd9f3SGreg Kroah-Hartman } 1802a6afd9f3SGreg Kroah-Hartman 1803a6afd9f3SGreg Kroah-Hartman 1804a6afd9f3SGreg Kroah-Hartman static const struct tty_operations serial_ops = { 1805a6afd9f3SGreg Kroah-Hartman .open = rs_open, 1806a6afd9f3SGreg Kroah-Hartman .close = rs_close, 1807a6afd9f3SGreg Kroah-Hartman .write = rs_write, 1808a6afd9f3SGreg Kroah-Hartman .put_char = rs_put_char, 1809a6afd9f3SGreg Kroah-Hartman .flush_chars = rs_flush_chars, 1810a6afd9f3SGreg Kroah-Hartman .write_room = rs_write_room, 1811a6afd9f3SGreg Kroah-Hartman .chars_in_buffer = rs_chars_in_buffer, 1812a6afd9f3SGreg Kroah-Hartman .flush_buffer = rs_flush_buffer, 1813a6afd9f3SGreg Kroah-Hartman .ioctl = rs_ioctl, 1814a6afd9f3SGreg Kroah-Hartman .throttle = rs_throttle, 1815a6afd9f3SGreg Kroah-Hartman .unthrottle = rs_unthrottle, 1816a6afd9f3SGreg Kroah-Hartman .set_termios = rs_set_termios, 1817a6afd9f3SGreg Kroah-Hartman .stop = rs_stop, 1818a6afd9f3SGreg Kroah-Hartman .start = rs_start, 1819a6afd9f3SGreg Kroah-Hartman .hangup = rs_hangup, 1820a6afd9f3SGreg Kroah-Hartman .break_ctl = rs_break, 1821a6afd9f3SGreg Kroah-Hartman .send_xchar = rs_send_xchar, 1822a6afd9f3SGreg Kroah-Hartman .wait_until_sent = rs_wait_until_sent, 1823a6afd9f3SGreg Kroah-Hartman .tiocmget = rs_tiocmget, 1824a6afd9f3SGreg Kroah-Hartman .tiocmset = rs_tiocmset, 1825a6afd9f3SGreg Kroah-Hartman .get_icount = rs_get_icount, 1826a6afd9f3SGreg Kroah-Hartman .proc_fops = &rs_proc_fops, 1827a6afd9f3SGreg Kroah-Hartman }; 1828a6afd9f3SGreg Kroah-Hartman 1829a6afd9f3SGreg Kroah-Hartman /* 1830a6afd9f3SGreg Kroah-Hartman * The serial driver boot-time initialization code! 1831a6afd9f3SGreg Kroah-Hartman */ 1832a6afd9f3SGreg Kroah-Hartman static int __init amiga_serial_probe(struct platform_device *pdev) 1833a6afd9f3SGreg Kroah-Hartman { 1834a6afd9f3SGreg Kroah-Hartman unsigned long flags; 1835a6afd9f3SGreg Kroah-Hartman struct serial_state * state; 1836a6afd9f3SGreg Kroah-Hartman int error; 1837a6afd9f3SGreg Kroah-Hartman 1838410235fdSJiri Slaby serial_driver = alloc_tty_driver(NR_PORTS); 1839a6afd9f3SGreg Kroah-Hartman if (!serial_driver) 1840a6afd9f3SGreg Kroah-Hartman return -ENOMEM; 1841a6afd9f3SGreg Kroah-Hartman 1842a6afd9f3SGreg Kroah-Hartman show_serial_version(); 1843a6afd9f3SGreg Kroah-Hartman 1844a6afd9f3SGreg Kroah-Hartman /* Initialize the tty_driver structure */ 1845a6afd9f3SGreg Kroah-Hartman 1846a6afd9f3SGreg Kroah-Hartman serial_driver->driver_name = "amiserial"; 1847a6afd9f3SGreg Kroah-Hartman serial_driver->name = "ttyS"; 1848a6afd9f3SGreg Kroah-Hartman serial_driver->major = TTY_MAJOR; 1849a6afd9f3SGreg Kroah-Hartman serial_driver->minor_start = 64; 1850a6afd9f3SGreg Kroah-Hartman serial_driver->type = TTY_DRIVER_TYPE_SERIAL; 1851a6afd9f3SGreg Kroah-Hartman serial_driver->subtype = SERIAL_TYPE_NORMAL; 1852a6afd9f3SGreg Kroah-Hartman serial_driver->init_termios = tty_std_termios; 1853a6afd9f3SGreg Kroah-Hartman serial_driver->init_termios.c_cflag = 1854a6afd9f3SGreg Kroah-Hartman B9600 | CS8 | CREAD | HUPCL | CLOCAL; 1855a6afd9f3SGreg Kroah-Hartman serial_driver->flags = TTY_DRIVER_REAL_RAW; 1856a6afd9f3SGreg Kroah-Hartman tty_set_operations(serial_driver, &serial_ops); 1857a6afd9f3SGreg Kroah-Hartman 1858a6afd9f3SGreg Kroah-Hartman error = tty_register_driver(serial_driver); 1859a6afd9f3SGreg Kroah-Hartman if (error) 1860a6afd9f3SGreg Kroah-Hartman goto fail_put_tty_driver; 1861a6afd9f3SGreg Kroah-Hartman 1862a6afd9f3SGreg Kroah-Hartman state = rs_table; 1863a6afd9f3SGreg Kroah-Hartman state->port = (int)&custom.serdatr; /* Just to give it a value */ 1864a6afd9f3SGreg Kroah-Hartman state->line = 0; 1865a6afd9f3SGreg Kroah-Hartman state->custom_divisor = 0; 1866a6afd9f3SGreg Kroah-Hartman state->close_delay = 5*HZ/10; 1867a6afd9f3SGreg Kroah-Hartman state->closing_wait = 30*HZ; 1868a6afd9f3SGreg Kroah-Hartman state->icount.cts = state->icount.dsr = 1869a6afd9f3SGreg Kroah-Hartman state->icount.rng = state->icount.dcd = 0; 1870a6afd9f3SGreg Kroah-Hartman state->icount.rx = state->icount.tx = 0; 1871a6afd9f3SGreg Kroah-Hartman state->icount.frame = state->icount.parity = 0; 1872a6afd9f3SGreg Kroah-Hartman state->icount.overrun = state->icount.brk = 0; 1873*87758791SJiri Slaby tty_port_init(&state->tport); 1874a6afd9f3SGreg Kroah-Hartman 1875a6afd9f3SGreg Kroah-Hartman printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", 1876a6afd9f3SGreg Kroah-Hartman state->line); 1877a6afd9f3SGreg Kroah-Hartman 1878a6afd9f3SGreg Kroah-Hartman /* Hardware set up */ 1879a6afd9f3SGreg Kroah-Hartman 1880a6afd9f3SGreg Kroah-Hartman state->baud_base = amiga_colorclock; 1881a6afd9f3SGreg Kroah-Hartman state->xmit_fifo_size = 1; 1882a6afd9f3SGreg Kroah-Hartman 1883a6afd9f3SGreg Kroah-Hartman /* set ISRs, and then disable the rx interrupts */ 1884a6afd9f3SGreg Kroah-Hartman error = request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state); 1885a6afd9f3SGreg Kroah-Hartman if (error) 1886a6afd9f3SGreg Kroah-Hartman goto fail_unregister; 1887a6afd9f3SGreg Kroah-Hartman 18889cfb5c05SYong Zhang error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, 0, 1889a6afd9f3SGreg Kroah-Hartman "serial RX", state); 1890a6afd9f3SGreg Kroah-Hartman if (error) 1891a6afd9f3SGreg Kroah-Hartman goto fail_free_irq; 1892a6afd9f3SGreg Kroah-Hartman 1893a6afd9f3SGreg Kroah-Hartman local_irq_save(flags); 1894a6afd9f3SGreg Kroah-Hartman 1895a6afd9f3SGreg Kroah-Hartman /* turn off Rx and Tx interrupts */ 1896a6afd9f3SGreg Kroah-Hartman custom.intena = IF_RBF | IF_TBE; 1897a6afd9f3SGreg Kroah-Hartman mb(); 1898a6afd9f3SGreg Kroah-Hartman 1899a6afd9f3SGreg Kroah-Hartman /* clear any pending interrupt */ 1900a6afd9f3SGreg Kroah-Hartman custom.intreq = IF_RBF | IF_TBE; 1901a6afd9f3SGreg Kroah-Hartman mb(); 1902a6afd9f3SGreg Kroah-Hartman 1903a6afd9f3SGreg Kroah-Hartman local_irq_restore(flags); 1904a6afd9f3SGreg Kroah-Hartman 1905a6afd9f3SGreg Kroah-Hartman /* 1906a6afd9f3SGreg Kroah-Hartman * set the appropriate directions for the modem control flags, 1907a6afd9f3SGreg Kroah-Hartman * and clear RTS and DTR 1908a6afd9f3SGreg Kroah-Hartman */ 1909a6afd9f3SGreg Kroah-Hartman ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */ 1910a6afd9f3SGreg Kroah-Hartman ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ 1911a6afd9f3SGreg Kroah-Hartman 1912a6afd9f3SGreg Kroah-Hartman platform_set_drvdata(pdev, state); 1913a6afd9f3SGreg Kroah-Hartman 1914a6afd9f3SGreg Kroah-Hartman return 0; 1915a6afd9f3SGreg Kroah-Hartman 1916a6afd9f3SGreg Kroah-Hartman fail_free_irq: 1917a6afd9f3SGreg Kroah-Hartman free_irq(IRQ_AMIGA_TBE, state); 1918a6afd9f3SGreg Kroah-Hartman fail_unregister: 1919a6afd9f3SGreg Kroah-Hartman tty_unregister_driver(serial_driver); 1920a6afd9f3SGreg Kroah-Hartman fail_put_tty_driver: 1921a6afd9f3SGreg Kroah-Hartman put_tty_driver(serial_driver); 1922a6afd9f3SGreg Kroah-Hartman return error; 1923a6afd9f3SGreg Kroah-Hartman } 1924a6afd9f3SGreg Kroah-Hartman 1925a6afd9f3SGreg Kroah-Hartman static int __exit amiga_serial_remove(struct platform_device *pdev) 1926a6afd9f3SGreg Kroah-Hartman { 1927a6afd9f3SGreg Kroah-Hartman int error; 1928a6afd9f3SGreg Kroah-Hartman struct serial_state *state = platform_get_drvdata(pdev); 1929a6afd9f3SGreg Kroah-Hartman 1930a6afd9f3SGreg Kroah-Hartman /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ 1931a6afd9f3SGreg Kroah-Hartman if ((error = tty_unregister_driver(serial_driver))) 1932a6afd9f3SGreg Kroah-Hartman printk("SERIAL: failed to unregister serial driver (%d)\n", 1933a6afd9f3SGreg Kroah-Hartman error); 1934a6afd9f3SGreg Kroah-Hartman put_tty_driver(serial_driver); 1935a6afd9f3SGreg Kroah-Hartman 1936916b7656SJiri Slaby free_irq(IRQ_AMIGA_TBE, state); 1937916b7656SJiri Slaby free_irq(IRQ_AMIGA_RBF, state); 1938a6afd9f3SGreg Kroah-Hartman 1939a6afd9f3SGreg Kroah-Hartman platform_set_drvdata(pdev, NULL); 1940a6afd9f3SGreg Kroah-Hartman 1941a6afd9f3SGreg Kroah-Hartman return error; 1942a6afd9f3SGreg Kroah-Hartman } 1943a6afd9f3SGreg Kroah-Hartman 1944a6afd9f3SGreg Kroah-Hartman static struct platform_driver amiga_serial_driver = { 1945a6afd9f3SGreg Kroah-Hartman .remove = __exit_p(amiga_serial_remove), 1946a6afd9f3SGreg Kroah-Hartman .driver = { 1947a6afd9f3SGreg Kroah-Hartman .name = "amiga-serial", 1948a6afd9f3SGreg Kroah-Hartman .owner = THIS_MODULE, 1949a6afd9f3SGreg Kroah-Hartman }, 1950a6afd9f3SGreg Kroah-Hartman }; 1951a6afd9f3SGreg Kroah-Hartman 1952a6afd9f3SGreg Kroah-Hartman static int __init amiga_serial_init(void) 1953a6afd9f3SGreg Kroah-Hartman { 1954a6afd9f3SGreg Kroah-Hartman return platform_driver_probe(&amiga_serial_driver, amiga_serial_probe); 1955a6afd9f3SGreg Kroah-Hartman } 1956a6afd9f3SGreg Kroah-Hartman 1957a6afd9f3SGreg Kroah-Hartman module_init(amiga_serial_init); 1958a6afd9f3SGreg Kroah-Hartman 1959a6afd9f3SGreg Kroah-Hartman static void __exit amiga_serial_exit(void) 1960a6afd9f3SGreg Kroah-Hartman { 1961a6afd9f3SGreg Kroah-Hartman platform_driver_unregister(&amiga_serial_driver); 1962a6afd9f3SGreg Kroah-Hartman } 1963a6afd9f3SGreg Kroah-Hartman 1964a6afd9f3SGreg Kroah-Hartman module_exit(amiga_serial_exit); 1965a6afd9f3SGreg Kroah-Hartman 1966a6afd9f3SGreg Kroah-Hartman 1967a6afd9f3SGreg Kroah-Hartman #if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE) 1968a6afd9f3SGreg Kroah-Hartman 1969a6afd9f3SGreg Kroah-Hartman /* 1970a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 1971a6afd9f3SGreg Kroah-Hartman * Serial console driver 1972a6afd9f3SGreg Kroah-Hartman * ------------------------------------------------------------ 1973a6afd9f3SGreg Kroah-Hartman */ 1974a6afd9f3SGreg Kroah-Hartman 1975a6afd9f3SGreg Kroah-Hartman static void amiga_serial_putc(char c) 1976a6afd9f3SGreg Kroah-Hartman { 1977a6afd9f3SGreg Kroah-Hartman custom.serdat = (unsigned char)c | 0x100; 1978a6afd9f3SGreg Kroah-Hartman while (!(custom.serdatr & 0x2000)) 1979a6afd9f3SGreg Kroah-Hartman barrier(); 1980a6afd9f3SGreg Kroah-Hartman } 1981a6afd9f3SGreg Kroah-Hartman 1982a6afd9f3SGreg Kroah-Hartman /* 1983a6afd9f3SGreg Kroah-Hartman * Print a string to the serial port trying not to disturb 1984a6afd9f3SGreg Kroah-Hartman * any possible real use of the port... 1985a6afd9f3SGreg Kroah-Hartman * 1986a6afd9f3SGreg Kroah-Hartman * The console must be locked when we get here. 1987a6afd9f3SGreg Kroah-Hartman */ 1988a6afd9f3SGreg Kroah-Hartman static void serial_console_write(struct console *co, const char *s, 1989a6afd9f3SGreg Kroah-Hartman unsigned count) 1990a6afd9f3SGreg Kroah-Hartman { 1991a6afd9f3SGreg Kroah-Hartman unsigned short intena = custom.intenar; 1992a6afd9f3SGreg Kroah-Hartman 1993a6afd9f3SGreg Kroah-Hartman custom.intena = IF_TBE; 1994a6afd9f3SGreg Kroah-Hartman 1995a6afd9f3SGreg Kroah-Hartman while (count--) { 1996a6afd9f3SGreg Kroah-Hartman if (*s == '\n') 1997a6afd9f3SGreg Kroah-Hartman amiga_serial_putc('\r'); 1998a6afd9f3SGreg Kroah-Hartman amiga_serial_putc(*s++); 1999a6afd9f3SGreg Kroah-Hartman } 2000a6afd9f3SGreg Kroah-Hartman 2001a6afd9f3SGreg Kroah-Hartman custom.intena = IF_SETCLR | (intena & IF_TBE); 2002a6afd9f3SGreg Kroah-Hartman } 2003a6afd9f3SGreg Kroah-Hartman 2004a6afd9f3SGreg Kroah-Hartman static struct tty_driver *serial_console_device(struct console *c, int *index) 2005a6afd9f3SGreg Kroah-Hartman { 2006a6afd9f3SGreg Kroah-Hartman *index = 0; 2007a6afd9f3SGreg Kroah-Hartman return serial_driver; 2008a6afd9f3SGreg Kroah-Hartman } 2009a6afd9f3SGreg Kroah-Hartman 2010a6afd9f3SGreg Kroah-Hartman static struct console sercons = { 2011a6afd9f3SGreg Kroah-Hartman .name = "ttyS", 2012a6afd9f3SGreg Kroah-Hartman .write = serial_console_write, 2013a6afd9f3SGreg Kroah-Hartman .device = serial_console_device, 2014a6afd9f3SGreg Kroah-Hartman .flags = CON_PRINTBUFFER, 2015a6afd9f3SGreg Kroah-Hartman .index = -1, 2016a6afd9f3SGreg Kroah-Hartman }; 2017a6afd9f3SGreg Kroah-Hartman 2018a6afd9f3SGreg Kroah-Hartman /* 2019a6afd9f3SGreg Kroah-Hartman * Register console. 2020a6afd9f3SGreg Kroah-Hartman */ 2021a6afd9f3SGreg Kroah-Hartman static int __init amiserial_console_init(void) 2022a6afd9f3SGreg Kroah-Hartman { 2023a6afd9f3SGreg Kroah-Hartman register_console(&sercons); 2024a6afd9f3SGreg Kroah-Hartman return 0; 2025a6afd9f3SGreg Kroah-Hartman } 2026a6afd9f3SGreg Kroah-Hartman console_initcall(amiserial_console_init); 2027a6afd9f3SGreg Kroah-Hartman 2028a6afd9f3SGreg Kroah-Hartman #endif /* CONFIG_SERIAL_CONSOLE && !MODULE */ 2029a6afd9f3SGreg Kroah-Hartman 2030a6afd9f3SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 2031a6afd9f3SGreg Kroah-Hartman MODULE_ALIAS("platform:amiga-serial"); 2032