AROS_UFH3(void, serialunit_receive_data, AROS_UFHA(APTR, iD, A1), AROS_UFHA(APTR, iC, A5), AROS_UFHA(struct ExecBase *, SysBase, A6)) { AROS_USERFUNC_INIT struct HIDDSerialUnitData * data = iD; int len = 0; UBYTE buffer[READBUFFER_SIZE]; /* ** Read the data from the port ... */ do { buffer[len++] = serial_inp(data, UART_RX); } while (serial_inp(data, UART_LSR) & UART_LSR_DR); /* ** ... and deliver them to whoever is interested. */ if (NULL != data->DataReceivedCallBack) data->DataReceivedCallBack(buffer, len, data->unitnum, data->DataReceivedUserData); return; AROS_USERFUNC_EXIT }
static void common_serial_int_handler(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw, ULONG unitnum) { UBYTE code = UART_IIR_NO_INT; if (csd->units[unitnum]) code = serial_inp(csd->units[unitnum], UART_IIR) & 0x07; switch (code) { case UART_IIR_RLSI: (void)serial_inp(csd->units[unitnum], UART_LSR); break; case UART_IIR_RDI: if (csd->units[unitnum]) { AROS_UFC3(void, serialunit_receive_data, AROS_UFCA(APTR , csd->units[unitnum], A1), AROS_UFCA(APTR , NULL , A5), AROS_UFCA(struct ExecBase * , SysBase, A6)); } break; case UART_IIR_MSI: (void)serial_inp(csd->units[unitnum], UART_MSR); break; case UART_IIR_THRI: if (csd->units[unitnum]) if (0 == serialunit_write_more_data(csd->units[unitnum], NULL, SysBase)) (void)serial_inp(csd->units[unitnum], UART_IIR); break; }
/******* SerialUnit::Write() **********************************/ ULONG PCSerUnit__Hidd_SerialUnit__Write(OOP_Class *cl, OOP_Object *o, struct pHidd_SerialUnit_Write *msg) { struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o); unsigned char status; ULONG len = msg->Length; ULONG count = 0; EnterFunc(bug("SerialUnit::Write()\n")); /* * If the output is currently stopped just don't do anything here. */ if (TRUE == data->stopped) return 0; status = serial_inp(data, UART_LSR); if (status & UART_LSR_THRE) { /* write data into FIFO */ do { serial_outp(data, UART_TX, msg->Outbuffer[count++]); len--; } while (len > 0 && serial_inp(data, UART_LSR & UART_LSR_TEMT)); } ReturnInt("SerialUnit::Write()",ULONG, count); }
/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ static void mshutdown(struct IsdnCardState *cs) { #ifdef SERIAL_DEBUG_OPEN ; #endif /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up */ cs->hw.elsa.IER = 0; serial_outp(cs, UART_IER, 0x00); /* disable all intrs */ cs->hw.elsa.MCR &= ~UART_MCR_OUT2; /* disable break condition */ serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC); cs->hw.elsa.MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); /* disable FIFO's */ serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); serial_inp(cs, UART_RX); /* read data port to reset things */ #ifdef SERIAL_DEBUG_OPEN ; #endif }
static void rs_interrupt_elsa(struct IsdnCardState *cs) { int status, iir, msr; int pass_counter = 0; #ifdef SERIAL_DEBUG_INTR ; #endif do { status = serial_inp(cs, UART_LSR); debugl1(cs,"rs LSR %02x", status); #ifdef SERIAL_DEBUG_INTR ; #endif if (status & UART_LSR_DR) receive_chars(cs, &status); if (status & UART_LSR_THRE) transmit_chars(cs, NULL); if (pass_counter++ > RS_ISR_PASS_LIMIT) { ; break; } iir = serial_inp(cs, UART_IIR); debugl1(cs,"rs IIR %02x", iir); if ((iir & 0xf) == 0) { msr = serial_inp(cs, UART_MSR); debugl1(cs,"rs MSR %02x", msr); } } while (!(iir & UART_IIR_NO_INT)); #ifdef SERIAL_DEBUG_INTR ; #endif }
/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ static void mshutdown(struct IsdnCardState *cs) { unsigned long flags; #ifdef SERIAL_DEBUG_OPEN printk(KERN_DEBUG"Shutting down serial ...."); #endif save_flags(flags); cli(); /* Disable interrupts */ /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up */ cs->hw.elsa.IER = 0; serial_outp(cs, UART_IER, 0x00); /* disable all intrs */ cs->hw.elsa.MCR &= ~UART_MCR_OUT2; /* disable break condition */ serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC); cs->hw.elsa.MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); /* disable FIFO's */ serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); serial_inp(cs, UART_RX); /* read data port to reset things */ restore_flags(flags); #ifdef SERIAL_DEBUG_OPEN printk(" done\n"); #endif }
/* Check if there is a byte ready at the serial port */ static int get_serial_char(void) { unsigned char ch; if (kdb_serial.iobase == 0) return -1; if (serial_inp(&kdb_serial, UART_LSR) & UART_LSR_DR) { ch = serial_inp(&kdb_serial, UART_RX); if (ch == 0x7f) ch = 8; return ch; } return -1; }
static irqreturn_t elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u8 val; if (!cs) { printk(KERN_WARNING "Elsa: Spurious interrupt!\n"); return IRQ_NONE; } if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) { val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */ if (!test_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags) && !(val & ELSA_PCI_IRQ_MASK)) return IRQ_NONE; } #if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_IIR); if (!(val & UART_IIR_NO_INT)) { debugl1(cs,"IIR %02x", val); spin_lock(&cs->lock); rs_interrupt_elsa(intno, cs); spin_unlock(&cs->lock); } } #endif return ipac_irq(intno, dev_id, regs); }
/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ static void change_speed(struct IsdnCardState *cs, int baud) { int quot = 0, baud_base; unsigned cval, fcr = 0; /* byte size and parity */ cval = 0x03; /* Determine divisor based on baud rate */ baud_base = BASE_BAUD; quot = baud_base / baud; /* If the quotient is ever zero, default to 9600 bps */ if (!quot) quot = baud_base / 9600; /* Set up FIFO's */ if ((baud_base / quot) < 2400) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; else fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; serial_outp(cs, UART_FCR, fcr); /* CTS flow control flag and modem status interrupts */ cs->hw.elsa.IER &= ~UART_IER_MSI; cs->hw.elsa.IER |= UART_IER_MSI; serial_outp(cs, UART_IER, cs->hw.elsa.IER); debugl1(cs,"modem quot=0x%x", quot); serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */ serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */ serial_outp(cs, UART_LCR, cval); /* reset DLAB */ serial_inp(cs, UART_RX); }
static void elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u_char ista,val; int icnt=5; if (!cs) { printk(KERN_WARNING "Elsa: Spurious interrupt!\n"); return; } if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) { val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */ if (!(val & ELSA_PCI_IRQ_MASK)) return; } #if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_IIR); if (!(val & UART_IIR_NO_INT)) { debugl1(cs,"IIR %02x", val); rs_interrupt_elsa(intno, cs); } } #endif ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); Start_IPAC: if (cs->debug & L1_DEB_IPAC) debugl1(cs, "IPAC ISTA %02X", ista); if (ista & 0x0f) { val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); if (ista & 0x01) val |= 0x01; if (ista & 0x04) val |= 0x02; if (ista & 0x08) val |= 0x04; if (val) hscx_int_main(cs, val); } if (ista & 0x20) { val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80); if (val) { isac_interrupt(cs, val); } } if (ista & 0x10) { val = 0x01; isac_interrupt(cs, val); } ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); if ((ista & 0x3f) && icnt) { icnt--; goto Start_IPAC; } if (!icnt) printk(KERN_WARNING "ELSA IRQ LOOP\n"); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0); }
static irqreturn_t elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u8 val; if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) { /* The card tends to generate interrupts while being removed causing us to just crash the kernel. bad. */ printk(KERN_WARNING "Elsa: card not available!\n"); return IRQ_NONE; } #if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_IIR); if (!(val & UART_IIR_NO_INT)) { debugl1(cs,"IIR %02x", val); spin_lock(&cs->lock); rs_interrupt_elsa(intno, cs); spin_unlock(&cs->lock); } } #endif hscxisac_irq(intno, dev_id, regs); if (cs->hw.elsa.status & ELSA_TIMER_AKTIV) { if (!TimerRun(cs)) { /* Timer Restart */ byteout(cs->hw.elsa.timer, 0); cs->hw.elsa.counter++; } } #if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_MCR); val ^= 0x8; serial_outp(cs, UART_MCR, val); val = serial_inp(cs, UART_MCR); val ^= 0x8; serial_outp(cs, UART_MCR, val); } #endif if (cs->hw.elsa.trig) byteout(cs->hw.elsa.trig, 0x00); return IRQ_HANDLED; }
/****** SerialUnit::GetStatus ********************************/ UWORD PCSerUnit__Hidd_SerialUnit__GetStatus(OOP_Class * cl, OOP_Object *o, struct pHidd_SerialUnit_GetStatus *msg) { struct HIDDSerialUnitData * data = OOP_INST_DATA(cl, o); UWORD status = 0; UBYTE msr = serial_inp(data, UART_MSR); UBYTE mcr = serial_inp(data, UART_MCR); if (msr & UART_MSR_DCD) status |= (1<<5); if (msr & UART_MSR_DSR) status |= (1<<3); if (msr & UART_MSR_CTS) status |= (1<<4); if (mcr & UART_MCR_DTR) status |= (1<<7); if (mcr & UART_MCR_RTS) status |= (1<<6); /* old RKMs say 'ready to send' */ return status; }
/* * This handles the interrupt from one port. */ static inline void serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) { unsigned int status = serial_inp(up, UART_LSR); DEBUG_INTR("status = %x...", status); if (status & UART_LSR_DR) receive_chars(up, &status, regs); check_modem_status(up); if (status & UART_LSR_THRE) transmit_chars(up); }
/* Check if there is a byte ready at the serial port */ static int get_serial_char(void) { if (!kdb_tty_driver) { kdb_tty_driver = tty_find_polling_driver("ttyS0", &kdb_tty_line); if (!kdb_tty_driver) return -1; } return kdb_tty_driver->ops->poll_get_char(kdb_tty_driver, kdb_tty_line); #if 0 if (kdb_serial.iobase == 0) return -1; if (serial_inp(&kdb_serial, UART_LSR) & UART_LSR_DR) { ch = serial_inp(&kdb_serial, UART_RX); if (ch == 0x7f) ch = 8; return ch; } return -1; #endif }
static void serial8250_shutdown(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned long flags; /* * Disable interrupts from this port */ up->ier = 0; serial_outp(up, UART_IER, 0); spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_FOURPORT) { /* reset interrupts on the AST Fourport board */ inb((up->port.iobase & 0xfe0) | 0x1f); up->port.mctrl |= TIOCM_OUT1; } else up->port.mctrl &= ~TIOCM_OUT2; serial8250_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); /* * Disable break condition and FIFOs */ serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); serial_outp(up, UART_FCR, 0); /* * Read data port to reset things, and then unlink from * the IRQ chain. */ (void) serial_in(up, UART_RX); if (!is_real_interrupt(up->port.irq)) del_timer_sync(&up->timer); else serial_unlink_irq_chain(up); }
static inline void receive_chars(struct IsdnCardState *cs, int *status) { unsigned char ch; struct sk_buff *skb; do { ch = serial_in(cs, UART_RX); if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF) break; cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch; #ifdef SERIAL_DEBUG_INTR printk("DR%02x:%02x...", ch, *status); #endif if (*status & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE)) { #ifdef SERIAL_DEBUG_INTR ; #endif } *status = serial_inp(cs, UART_LSR); } while (*status & UART_LSR_DR); if (cs->hw.elsa.MFlag == 2) { if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt))) ; else { memcpy(skb_put(skb, cs->hw.elsa.rcvcnt), cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt); skb_queue_tail(& cs->hw.elsa.bcs->rqueue, skb); } schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY); } else { char tmp[128]; char *t = tmp; t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt); QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt); debugl1(cs, tmp); } cs->hw.elsa.rcvcnt = 0; }
static int serial8250_startup(struct uart_port *port) { struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned long flags; int retval; /* * Clear the FIFO buffers and disable them. * (they will be reeanbled in set_termios()) */ if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) { serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); serial_outp(up, UART_FCR, 0); } /* * Clear the interrupt registers. */ (void) serial_inp(up, UART_LSR); (void) serial_inp(up, UART_RX); (void) serial_inp(up, UART_IIR); (void) serial_inp(up, UART_MSR); /* * At this point, there's no way the LSR could still be 0xff; * if it is, then bail out, because there's likely no UART * here. */ if (!(up->port.flags & UPF_BUGGY_UART) && (serial_inp(up, UART_LSR) == 0xff)) { printk("ttyS%d: LSR safety check engaged!\n", up->port.line); return -ENODEV; } retval = serial_link_irq_chain(up); if (retval) return retval; /* * Now, initialize the UART */ serial_outp(up, UART_LCR, UART_LCR_WLEN8); spin_lock_irqsave(&up->port.lock, flags); if (up->port.flags & UPF_FOURPORT) { if (!is_real_interrupt(up->port.irq)) up->port.mctrl |= TIOCM_OUT1; } else /* * Most PC uarts need OUT2 raised to enable interrupts. */ if (is_real_interrupt(up->port.irq)) up->port.mctrl |= TIOCM_OUT2; serial8250_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); /* * Finally, enable interrupts. Note: Modem status interrupts * are set via set_termios(), which will be occurring imminently * anyway, so we don't enable them here. */ up->ier = UART_IER_RLSI | UART_IER_RDI; serial_outp(up, UART_IER, up->ier); if (up->port.flags & UPF_FOURPORT) { unsigned int icp; /* * Enable interrupts on the AST Fourport board */ icp = (up->port.iobase & 0xfe0) | 0x01f; outb_p(0x80, icp); (void) inb_p(icp); } /* * And clear the interrupt registers again for luck. */ (void) serial_inp(up, UART_LSR); (void) serial_inp(up, UART_RX); (void) serial_inp(up, UART_IIR); (void) serial_inp(up, UART_MSR); return 0; }
static _INLINE_ void receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) { struct tty_struct *tty = up->port.info->tty; unsigned char ch; int max_count = 256; do { if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { tty->flip.work.func((void *)tty); if (tty->flip.count >= TTY_FLIPBUF_SIZE) return; // if TTY_DONT_FLIP is set } ch = serial_inp(up, UART_RX); *tty->flip.char_buf_ptr = ch; *tty->flip.flag_buf_ptr = TTY_NORMAL; up->port.icount.rx++; if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE))) { /* * For statistics only */ if (*status & UART_LSR_BI) { *status &= ~(UART_LSR_FE | UART_LSR_PE); up->port.icount.brk++; /* * We do the SysRQ and SAK checking * here because otherwise the break * may get masked by ignore_status_mask * or read_status_mask. */ if (uart_handle_break(&up->port)) goto ignore_char; } else if (*status & UART_LSR_PE) up->port.icount.parity++; else if (*status & UART_LSR_FE) up->port.icount.frame++; if (*status & UART_LSR_OE) up->port.icount.overrun++; /* * Mask off conditions which should be ingored. */ *status &= up->port.read_status_mask; #ifdef CONFIG_SERIAL_AU1X00_CONSOLE if (up->port.line == up->port.cons->index) { /* Recover the break flag from console xmit */ *status |= up->lsr_break_flag; up->lsr_break_flag = 0; } #endif if (*status & UART_LSR_BI) { DEBUG_INTR("handling break...."); *tty->flip.flag_buf_ptr = TTY_BREAK; } else if (*status & UART_LSR_PE) *tty->flip.flag_buf_ptr = TTY_PARITY; else if (*status & UART_LSR_FE) *tty->flip.flag_buf_ptr = TTY_FRAME; } if (uart_handle_sysrq_char(&up->port, ch, regs)) goto ignore_char; if ((*status & up->port.ignore_status_mask) == 0) { tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; } if ((*status & UART_LSR_OE) && tty->flip.count < TTY_FLIPBUF_SIZE) { /* * Overrun is special, since it's reported * immediately, and doesn't affect the current * character. */ *tty->flip.flag_buf_ptr = TTY_OVERRUN; tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; } ignore_char: *status = serial_inp(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); spin_unlock(&up->port.lock); tty_flip_buffer_push(tty); spin_lock(&up->port.lock); }
static irqreturn_t elsa_interrupt_ipac(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_long flags; u_char ista,val; int icnt=5; spin_lock_irqsave(&cs->lock, flags); if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) { val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */ if (!(val & ELSA_PCI_IRQ_MASK)) { spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; } } #if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_IIR); if (!(val & UART_IIR_NO_INT)) { debugl1(cs,"IIR %02x", val); rs_interrupt_elsa(cs); } } #endif ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); Start_IPAC: if (cs->debug & L1_DEB_IPAC) debugl1(cs, "IPAC ISTA %02X", ista); if (ista & 0x0f) { val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); if (ista & 0x01) val |= 0x01; if (ista & 0x04) val |= 0x02; if (ista & 0x08) val |= 0x04; if (val) hscx_int_main(cs, val); } if (ista & 0x20) { val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80); if (val) { isac_interrupt(cs, val); } } if (ista & 0x10) { val = 0x01; isac_interrupt(cs, val); } ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); if ((ista & 0x3f) && icnt) { icnt--; goto Start_IPAC; } if (!icnt) #ifdef CONFIG_DEBUG_PRINTK printk(KERN_WARNING "ELSA IRQ LOOP\n"); #else ; #endif writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0); spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; }
static int mstartup(struct IsdnCardState *cs) { int retval=0; /* * Clear the FIFO buffers and disable them * (they will be reenabled in change_speed()) */ serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); /* * At this point there's no way the LSR could still be 0xFF; * if it is, then bail out, because there's likely no UART * here. */ if (serial_inp(cs, UART_LSR) == 0xff) { retval = -ENODEV; goto errout; } /* * Clear the interrupt registers. */ (void) serial_inp(cs, UART_RX); (void) serial_inp(cs, UART_IIR); (void) serial_inp(cs, UART_MSR); /* * Now, initialize the UART */ serial_outp(cs, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ cs->hw.elsa.MCR = 0; cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); /* * Finally, enable interrupts */ cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; serial_outp(cs, UART_IER, cs->hw.elsa.IER); /* enable interrupts */ /* * And clear the interrupt registers again for luck. */ (void)serial_inp(cs, UART_LSR); (void)serial_inp(cs, UART_RX); (void)serial_inp(cs, UART_IIR); (void)serial_inp(cs, UART_MSR); cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0; cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp =0; /* * and set the speed of the serial port */ change_speed(cs, BASE_BAUD); cs->hw.elsa.MFlag = 1; errout: return retval; }
static irqreturn_t elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u_long flags; u_char val; int icnt=5; if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) { /* The card tends to generate interrupts while being removed causing us to just crash the kernel. bad. */ printk(KERN_WARNING "Elsa: card not available!\n"); return IRQ_NONE; } spin_lock_irqsave(&cs->lock, flags); #if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_IIR); if (!(val & UART_IIR_NO_INT)) { debugl1(cs,"IIR %02x", val); rs_interrupt_elsa(intno, cs); } } #endif val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); Start_HSCX: if (val) { hscx_int_main(cs, val); } val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); Start_ISAC: if (val) { isac_interrupt(cs, val); } val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); if (val && icnt) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "HSCX IntStat after IntRoutine"); icnt--; goto Start_HSCX; } val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); if (val && icnt) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ISAC IntStat after IntRoutine"); icnt--; goto Start_ISAC; } if (!icnt) printk(KERN_WARNING"ELSA IRQ LOOP\n"); writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF); writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF); if (cs->hw.elsa.status & ELSA_TIMER_AKTIV) { if (!TimerRun(cs)) { /* Timer Restart */ byteout(cs->hw.elsa.timer, 0); cs->hw.elsa.counter++; } } #if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_MCR); val ^= 0x8; serial_outp(cs, UART_MCR, val); val = serial_inp(cs, UART_MCR); val ^= 0x8; serial_outp(cs, UART_MCR, val); } #endif if (cs->hw.elsa.trig) byteout(cs->hw.elsa.trig, 0x00); writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0); writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0); spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; }
/******* SerialUnit::New() ***********************************/ OOP_Object *PCSerUnit__Root__New(OOP_Class *cl, OOP_Object *obj, struct pRoot_New *msg) { struct HIDDSerialUnitData * data; struct TagItem *tag, *tstate; ULONG unitnum = 0; EnterFunc(bug("SerialUnit::New()\n")); tstate = msg->attrList; while ((tag = NextTagItem((const struct TagItem **)&tstate))) { ULONG idx; #define csd CSD(cl->UserData) if (IS_HIDDSERIALUNIT_ATTR(tag->ti_Tag, idx)) #undef csd { switch (idx) { case aoHidd_SerialUnit_Unit: unitnum = (ULONG)tag->ti_Data; break; } } } /* while (tags to process) */ obj = (OOP_Object *)OOP_DoSuperMethod(cl, obj, (OOP_Msg)msg); if (obj) { struct IntuitionBase * IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0); data = OOP_INST_DATA(cl, obj); data->baseaddr = bases[unitnum]; if (NULL != IntuitionBase) { struct Preferences prefs; GetPrefs(&prefs,sizeof(prefs)); data->baudrate = prefs.BaudRate; adapt_data(data, &prefs); CloseLibrary((struct Library *)IntuitionBase); } else { data->datalength = 8; data->parity = FALSE; data->baudrate = 9600; /* will be initialize in set_baudrate() */ } data->unitnum = unitnum; Disable(); CSD(cl->UserData)->units[data->unitnum] = data; Enable(); D(bug("Unit %d at 0x0%x\n", data->unitnum, data->baseaddr)); /* Wake up UART */ serial_outp(data, UART_LCR, 0xBF); serial_outp(data, UART_EFR, UART_EFR_ECB); serial_outp(data, UART_IER, 0); serial_outp(data, UART_EFR, 0); serial_outp(data, UART_LCR, 0); /* clear the FIFOs */ serial_outp(data, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); /* clear the interrupt registers */ (void)serial_inp(data, UART_RX); (void)serial_inp(data, UART_IIR); (void)serial_inp(data, UART_MSR); /* initilize the UART */ serial_outp(data, UART_LCR, get_lcr(data)); serial_outp(data, UART_MCR, UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS); serial_outp(data, UART_IER, UART_IER_RDI | UART_IER_THRI | UART_IER_RLSI | UART_IER_MSI); /* clear the interrupt registers again ... */ (void)serial_inp(data, UART_LSR); (void)serial_inp(data, UART_RX); (void)serial_inp(data, UART_IIR); (void)serial_inp(data, UART_MSR); set_baudrate(data, data->baudrate); } /* if (obj) */ ReturnPtr("SerialUnit::New()", OOP_Object *, obj); }