📄 elsa_ser.c
字号:
/* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $ * * stuff for the serial modem on ELSA cards * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#include <linux/config.h>#include <linux/serial.h>#include <linux/serial_reg.h>#define MAX_MODEM_BUF 256#define WAKEUP_CHARS (MAX_MODEM_BUF/2)#define RS_ISR_PASS_LIMIT 256#define BASE_BAUD ( 1843200 / 16 )//#define SERIAL_DEBUG_OPEN 1//#define SERIAL_DEBUG_INTR 1//#define SERIAL_DEBUG_FLOW 1#undef SERIAL_DEBUG_OPEN#undef SERIAL_DEBUG_INTR#undef SERIAL_DEBUG_FLOW#undef SERIAL_DEBUG_REG//#define SERIAL_DEBUG_REG 1#ifdef SERIAL_DEBUG_REGstatic u_char deb[32];const char *ModemIn[] = {"RBR","IER","IIR","LCR","MCR","LSR","MSR","SCR"};const char *ModemOut[] = {"THR","IER","FCR","LCR","MCR","LSR","MSR","SCR"};#endifstatic char *MInit_1 = "AT&F&C1E0&D2\r\0";static char *MInit_2 = "ATL2M1S64=13\r\0";static char *MInit_3 = "AT+FCLASS=0\r\0";static char *MInit_4 = "ATV1S2=128X1\r\0";static char *MInit_5 = "AT\\V8\\N3\r\0";static char *MInit_6 = "ATL0M0&G0%E1\r\0";static char *MInit_7 = "AT%L1%M0%C3\r\0";static char *MInit_speed28800 = "AT%G0%B28800\r\0";static char *MInit_dialout = "ATs7=60 x1 d\r\0";static char *MInit_dialin = "ATs7=60 x1 a\r\0";static inline unsigned int serial_in(struct IsdnCardState *cs, int offset){#ifdef SERIAL_DEBUG_REG u_int val = inb(cs->hw.elsa.base + 8 + offset); debugl1(cs,"in %s %02x",ModemIn[offset], val); return(val);#else return inb(cs->hw.elsa.base + 8 + offset);#endif}static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset){#ifdef SERIAL_DEBUG_REG#ifdef CONFIG_SERIAL_NOPAUSE_IO u_int val = inb(cs->hw.elsa.base + 8 + offset); debugl1(cs,"inp %s %02x",ModemIn[offset], val);#else u_int val = inb_p(cs->hw.elsa.base + 8 + offset); debugl1(cs,"inP %s %02x",ModemIn[offset], val);#endif return(val);#else#ifdef CONFIG_SERIAL_NOPAUSE_IO return inb(cs->hw.elsa.base + 8 + offset);#else return inb_p(cs->hw.elsa.base + 8 + offset);#endif#endif}static inline void serial_out(struct IsdnCardState *cs, int offset, int value){#ifdef SERIAL_DEBUG_REG debugl1(cs,"out %s %02x",ModemOut[offset], value);#endif outb(value, cs->hw.elsa.base + 8 + offset);}static inline void serial_outp(struct IsdnCardState *cs, int offset, int value){#ifdef SERIAL_DEBUG_REG#ifdef CONFIG_SERIAL_NOPAUSE_IO debugl1(cs,"outp %s %02x",ModemOut[offset], value);#else debugl1(cs,"outP %s %02x",ModemOut[offset], value);#endif#endif#ifdef CONFIG_SERIAL_NOPAUSE_IO outb(value, cs->hw.elsa.base + 8 + offset);#else outb_p(value, cs->hw.elsa.base + 8 + offset);#endif}/* * 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; int bits; /* byte size and parity */ cval = 0x03; bits = 10; /* 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 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;}/* * 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 printk(KERN_DEBUG"Shutting down serial ....");#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 printk(" done\n");#endif}static inline intwrite_modem(struct BCState *bcs) { int ret=0; struct IsdnCardState *cs = bcs->cs; int count, len, fp; if (!bcs->tx_skb) return 0; if (bcs->tx_skb->len <= 0) return 0; len = bcs->tx_skb->len; if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt) len = MAX_MODEM_BUF - cs->hw.elsa.transcnt; fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; fp &= (MAX_MODEM_BUF -1); count = len; if (count > MAX_MODEM_BUF - fp) { count = MAX_MODEM_BUF - fp; memcpy(cs->hw.elsa.transbuf + fp, bcs->tx_skb->data, count); skb_pull(bcs->tx_skb, count); cs->hw.elsa.transcnt += count; ret = count; count = len - count; fp = 0; } memcpy((cs->hw.elsa.transbuf + fp), bcs->tx_skb->data, count); skb_pull(bcs->tx_skb, count); cs->hw.elsa.transcnt += count; ret += count; if (cs->hw.elsa.transcnt && !(cs->hw.elsa.IER & UART_IER_THRI)) { cs->hw.elsa.IER |= UART_IER_THRI; serial_outp(cs, UART_IER, cs->hw.elsa.IER); } return(ret);}static inline voidmodem_fill(struct BCState *bcs) { if (bcs->tx_skb) { if (bcs->tx_skb->len) { write_modem(bcs); return; } else { if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && (PACKET_NOACK != bcs->tx_skb->pkt_type)) { u_long flags; spin_lock_irqsave(&bcs->aclock, flags); bcs->ackcnt += bcs->hw.hscx.count; spin_unlock_irqrestore(&bcs->aclock, flags); schedule_event(bcs, B_ACKPENDING); } dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { bcs->hw.hscx.count = 0; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); write_modem(bcs); } else { test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); schedule_event(bcs, B_XMTBUFREADY); }}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 printk("handling exept....");#endif } *status = serial_inp(cs, UART_LSR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -