📄 synclink_cs.c
字号:
return mgslpc_get_text_ptr;}/** * line discipline callback wrappers * * The wrappers maintain line discipline references * while calling into the line discipline. * * ldisc_flush_buffer - flush line discipline receive buffers * ldisc_receive_buf - pass receive data to line discipline */static void ldisc_flush_buffer(struct tty_struct *tty){ struct tty_ldisc *ld = tty_ldisc_ref(tty); if (ld) { if (ld->flush_buffer) ld->flush_buffer(tty); tty_ldisc_deref(ld); }}static void ldisc_receive_buf(struct tty_struct *tty, const __u8 *data, char *flags, int count){ struct tty_ldisc *ld; if (!tty) return; ld = tty_ldisc_ref(tty); if (ld) { if (ld->receive_buf) ld->receive_buf(tty, data, flags, count); tty_ldisc_deref(ld); }}static int mgslpc_probe(struct pcmcia_device *link){ MGSLPC_INFO *info; int ret; if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_attach\n"); info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); if (!info) { printk("Error can't allocate device instance data\n"); return -ENOMEM; } memset(info, 0, sizeof(MGSLPC_INFO)); info->magic = MGSLPC_MAGIC; INIT_WORK(&info->task, bh_handler, info); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->status_event_wait_q); init_waitqueue_head(&info->event_wait_q); spin_lock_init(&info->lock); spin_lock_init(&info->netlock); memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); info->idle_mode = HDLC_TXIDLE_FLAGS; info->imra_value = 0xffff; info->imrb_value = 0xffff; info->pim_value = 0xff; info->p_dev = link; link->priv = info; /* Initialize the struct pcmcia_device structure */ /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = NULL; link->conf.Attributes = 0; link->conf.IntType = INT_MEMORY_AND_IO; ret = mgslpc_config(link); if (ret) return ret; mgslpc_add_device(info); return 0;}/* Card has been inserted. */#define CS_CHECK(fn, ret) \do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)static int mgslpc_config(struct pcmcia_device *link){ MGSLPC_INFO *info = link->priv; tuple_t tuple; cisparse_t parse; int last_fn, last_ret; u_char buf[64]; cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg; if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_config(0x%p)\n", link); /* read CONFIG tuple to find its configuration registers */ tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* get CIS configuration entry */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); cfg = &(parse.cftable_entry); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) goto cs_failed; link->conf.ConfigIndex = cfg->index; link->conf.Attributes |= CONF_ENABLE_IRQ; /* IO window settings */ link->io.NumPorts1 = 0; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; if (!(io->flags & CISTPL_IO_16BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; link->io.BasePort1 = io->win[0].base; link->io.NumPorts1 = io->win[0].len; CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); } link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 8; link->conf.Present = PRESENT_OPTION; link->irq.Attributes |= IRQ_HANDLE_PRESENT; link->irq.Handler = mgslpc_isr; link->irq.Instance = info; CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); info->io_base = link->io.BasePort1; info->irq_level = link->irq.AssignedIRQ; /* add to linked list of devices */ sprintf(info->node.dev_name, "mgslpc0"); info->node.major = info->node.minor = 0; link->dev_node = &info->node; printk(KERN_INFO "%s: index 0x%02x:", info->node.dev_name, link->conf.ConfigIndex); if (link->conf.Attributes & CONF_ENABLE_IRQ) printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); printk("\n"); return 0;cs_failed: cs_error(link, last_fn, last_ret); mgslpc_release((u_long)link); return -ENODEV;}/* Card has been removed. * Unregister device and release PCMCIA configuration. * If device is open, postpone until it is closed. */static void mgslpc_release(u_long arg){ struct pcmcia_device *link = (struct pcmcia_device *)arg; if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_release(0x%p)\n", link); pcmcia_disable_device(link);}static void mgslpc_detach(struct pcmcia_device *link){ if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_detach(0x%p)\n", link); ((MGSLPC_INFO *)link->priv)->stop = 1; mgslpc_release((u_long)link); mgslpc_remove_device((MGSLPC_INFO *)link->priv);}static int mgslpc_suspend(struct pcmcia_device *link){ MGSLPC_INFO *info = link->priv; info->stop = 1; return 0;}static int mgslpc_resume(struct pcmcia_device *link){ MGSLPC_INFO *info = link->priv; info->stop = 0; return 0;}static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, char *name, const char *routine){#ifdef MGSLPC_PARANOIA_CHECK static const char *badmagic = "Warning: bad magic number for mgsl struct (%s) in %s\n"; static const char *badinfo = "Warning: null mgslpc_info for (%s) in %s\n"; if (!info) { printk(badinfo, name, routine); return 1; } if (info->magic != MGSLPC_MAGIC) { printk(badmagic, name, routine); return 1; }#else if (!info) return 1;#endif return 0;}#define CMD_RXFIFO BIT7 // release current rx FIFO#define CMD_RXRESET BIT6 // receiver reset#define CMD_RXFIFO_READ BIT5#define CMD_START_TIMER BIT4#define CMD_TXFIFO BIT3 // release current tx FIFO#define CMD_TXEOM BIT1 // transmit end message#define CMD_TXRESET BIT0 // transmit resetstatic BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel) { int i = 0; /* wait for command completion */ while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) { udelay(1); if (i++ == 1000) return FALSE; } return TRUE;}static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd) { wait_command_complete(info, channel); write_reg(info, (unsigned char) (channel + CMDR), cmd);}static void tx_pause(struct tty_struct *tty){ MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; unsigned long flags; if (mgslpc_paranoia_check(info, tty->name, "tx_pause")) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("tx_pause(%s)\n",info->device_name); spin_lock_irqsave(&info->lock,flags); if (info->tx_enabled) tx_stop(info); spin_unlock_irqrestore(&info->lock,flags);}static void tx_release(struct tty_struct *tty){ MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; unsigned long flags; if (mgslpc_paranoia_check(info, tty->name, "tx_release")) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("tx_release(%s)\n",info->device_name); spin_lock_irqsave(&info->lock,flags); if (!info->tx_enabled) tx_start(info); spin_unlock_irqrestore(&info->lock,flags);}/* Return next bottom half action to perform. * or 0 if nothing to do. */static int bh_action(MGSLPC_INFO *info){ unsigned long flags; int rc = 0; spin_lock_irqsave(&info->lock,flags); if (info->pending_bh & BH_RECEIVE) { info->pending_bh &= ~BH_RECEIVE; rc = BH_RECEIVE; } else if (info->pending_bh & BH_TRANSMIT) { info->pending_bh &= ~BH_TRANSMIT; rc = BH_TRANSMIT; } else if (info->pending_bh & BH_STATUS) { info->pending_bh &= ~BH_STATUS; rc = BH_STATUS; } if (!rc) { /* Mark BH routine as complete */ info->bh_running = 0; info->bh_requested = 0; } spin_unlock_irqrestore(&info->lock,flags); return rc;}void bh_handler(void* Context){ MGSLPC_INFO *info = (MGSLPC_INFO*)Context; int action; if (!info) return; if (debug_level >= DEBUG_LEVEL_BH) printk( "%s(%d):bh_handler(%s) entry\n", __FILE__,__LINE__,info->device_name); info->bh_running = 1; while((action = bh_action(info)) != 0) { /* Process work item */ if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):bh_handler() work item action=%d\n", __FILE__,__LINE__,action); switch (action) { case BH_RECEIVE: while(rx_get_frame(info)); break; case BH_TRANSMIT: bh_transmit(info); break; case BH_STATUS: bh_status(info); break; default: /* unknown work item ID */ printk("Unknown work item ID=%08X!\n", action); break; } } if (debug_level >= DEBUG_LEVEL_BH) printk( "%s(%d):bh_handler(%s) exit\n", __FILE__,__LINE__,info->device_name);}void bh_transmit(MGSLPC_INFO *info){ struct tty_struct *tty = info->tty; if (debug_level >= DEBUG_LEVEL_BH) printk("bh_transmit() entry on %s\n", info->device_name); if (tty) { tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); }}void bh_status(MGSLPC_INFO *info){ info->ri_chkcount = 0; info->dsr_chkcount = 0; info->dcd_chkcount = 0; info->cts_chkcount = 0;}/* eom: non-zero = end of frame */ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom){ unsigned char data[2]; unsigned char fifo_count, read_count, i; RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size)); if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):rx_ready_hdlc(eom=%d)\n",__FILE__,__LINE__,eom); if (!info->rx_enabled) return; if (info->rx_frame_count >= info->rx_buf_count) { /* no more free buffers */ issue_command(info, CHA, CMD_RXRESET); info->pending_bh |= BH_RECEIVE; info->rx_overflow = 1; info->icount.buf_overrun++; return; } if (eom) { /* end of frame, get FIFO count from RBCL register */ if (!(fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f))) fifo_count = 32; } else fifo_count = 32; do { if (fifo_count == 1) { read_count = 1; data[0] = read_reg(info, CHA + RXFIFO); } else { read_count = 2; *((unsigned short *) data) = read_reg16(info, CHA + RXFIFO); } fifo_count -= read_count; if (!fifo_count && eom) buf->status = data[--read_count]; for (i = 0; i < read_count; i++) { if (buf->count >= info->max_frame_size) { /* frame too large, reset receiver and reset current buffer */ issue_command(info, CHA, CMD_RXRESET); buf->count = 0; return; } *(buf->data + buf->count) = data[i]; buf->count++; } } while (fifo_count); if (eom) { info->pending_bh |= BH_RECEIVE; info->rx_frame_count++; info->rx_put++; if (info->rx_put >= info->rx_buf_count) info->rx_put = 0; } issue_command(info, CHA, CMD_RXFIFO);}static void rx_ready_async(MGSLPC_INFO *info, int tcd){ unsigned char data, status, flag; int fifo_count; int work = 0; struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; if (tcd) { /* early termination, get FIFO count from RBCL register */ fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); /* Zero fifo count could mean 0 or 32 bytes available. * If BIT5 of STAR is set then at least 1 byte is available. */ if (!fifo_count && (read_reg(info,CHA+STAR) & BIT5)) fifo_count = 32; } else fifo_count = 32; tty_buffer_request_room(tty, fifo_count); /* Flush received async data to receive data buffer. */ while (fifo_count) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -