synclink.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,191 行 · 第 1/5 页
C
2,191 行
static int io[MAX_ISA_DEVICES];static int irq[MAX_ISA_DEVICES];static int dma[MAX_ISA_DEVICES];static int debug_level;static int maxframe[MAX_TOTAL_DEVICES];static int dosyncppp[MAX_TOTAL_DEVICES];static int txdmabufs[MAX_TOTAL_DEVICES];static int txholdbufs[MAX_TOTAL_DEVICES]; MODULE_PARM(break_on_load,"i");MODULE_PARM(ttymajor,"i");MODULE_PARM(io,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");MODULE_PARM(irq,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");MODULE_PARM(dma,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");MODULE_PARM(debug_level,"i");MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");static char *driver_name = "SyncLink serial driver";static char *driver_version = "$Revision: 4.28 $";static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent);static void synclink_remove_one (struct pci_dev *dev);static struct pci_device_id synclink_pci_tbl[] = { { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, /* terminate list */};MODULE_DEVICE_TABLE(pci, synclink_pci_tbl);MODULE_LICENSE("GPL");static struct pci_driver synclink_pci_driver = { .name = "synclink", .id_table = synclink_pci_tbl, .probe = synclink_init_one, .remove = __devexit_p(synclink_remove_one),};static struct tty_driver *serial_driver;/* number of characters left in xmit buffer before we ask for more */#define WAKEUP_CHARS 256static void mgsl_change_params(struct mgsl_struct *info);static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout);/* * 1st function defined in .text section. Calling this function in * init_module() followed by a breakpoint allows a remote debugger * (gdb) to get the .text address for the add-symbol-file command. * This allows remote debugging of dynamically loadable modules. */void* mgsl_get_text_ptr(void){ return mgsl_get_text_ptr;}/* * tmp_buf is used as a temporary buffer by mgsl_write. We need to * lock it in case the COPY_FROM_USER blocks while swapping in a page, * and some other program tries to do a serial write at the same time. * Since the lock will only come under contention when the system is * swapping and available memory is low, it makes sense to share one * buffer across all the serial ioports, since it significantly saves * memory if large numbers of serial ports are open. */static unsigned char *tmp_buf;static DECLARE_MUTEX(tmp_buf_sem);static inline int mgsl_paranoia_check(struct mgsl_struct *info, char *name, const char *routine){#ifdef MGSL_PARANOIA_CHECK static const char *badmagic = "Warning: bad magic number for mgsl struct (%s) in %s\n"; static const char *badinfo = "Warning: null mgsl_struct for (%s) in %s\n"; if (!info) { printk(badinfo, name, routine); return 1; } if (info->magic != MGSL_MAGIC) { printk(badmagic, name, routine); return 1; }#else if (!info) return 1;#endif return 0;}/** * line discipline callback wrappers * * The wrappers maintain line discipline references * while calling into the line discipline. * * ldisc_receive_buf - pass receive data to line discipline */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); }}/* mgsl_stop() throttle (stop) transmitter * * Arguments: tty pointer to tty info structure * Return Value: None */static void mgsl_stop(struct tty_struct *tty){ struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (mgsl_paranoia_check(info, tty->name, "mgsl_stop")) return; if ( debug_level >= DEBUG_LEVEL_INFO ) printk("mgsl_stop(%s)\n",info->device_name); spin_lock_irqsave(&info->irq_spinlock,flags); if (info->tx_enabled) usc_stop_transmitter(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); } /* end of mgsl_stop() *//* mgsl_start() release (start) transmitter * * Arguments: tty pointer to tty info structure * Return Value: None */static void mgsl_start(struct tty_struct *tty){ struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if (mgsl_paranoia_check(info, tty->name, "mgsl_start")) return; if ( debug_level >= DEBUG_LEVEL_INFO ) printk("mgsl_start(%s)\n",info->device_name); spin_lock_irqsave(&info->irq_spinlock,flags); if (!info->tx_enabled) usc_start_transmitter(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); } /* end of mgsl_start() *//* * Bottom half work queue access functions *//* mgsl_bh_action() Return next bottom half action to perform. * Return Value: BH action code or 0 if nothing to do. */int mgsl_bh_action(struct mgsl_struct *info){ unsigned long flags; int rc = 0; spin_lock_irqsave(&info->irq_spinlock,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->irq_spinlock,flags); return rc;}/* * Perform bottom half processing of work items queued by ISR. */void mgsl_bh_handler(void* Context){ struct mgsl_struct *info = (struct mgsl_struct*)Context; int action; if (!info) return; if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):mgsl_bh_handler(%s) entry\n", __FILE__,__LINE__,info->device_name); info->bh_running = 1; while((action = mgsl_bh_action(info)) != 0) { /* Process work item */ if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):mgsl_bh_handler() work item action=%d\n", __FILE__,__LINE__,action); switch (action) { case BH_RECEIVE: mgsl_bh_receive(info); break; case BH_TRANSMIT: mgsl_bh_transmit(info); break; case BH_STATUS: mgsl_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):mgsl_bh_handler(%s) exit\n", __FILE__,__LINE__,info->device_name);}void mgsl_bh_receive(struct mgsl_struct *info){ int (*get_rx_frame)(struct mgsl_struct *info) = (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame); if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):mgsl_bh_receive(%s)\n", __FILE__,__LINE__,info->device_name); do { if (info->rx_rcc_underrun) { unsigned long flags; spin_lock_irqsave(&info->irq_spinlock,flags); usc_start_receiver(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); return; } } while(get_rx_frame(info));}void mgsl_bh_transmit(struct mgsl_struct *info){ struct tty_struct *tty = info->tty; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):mgsl_bh_transmit() entry on %s\n", __FILE__,__LINE__,info->device_name); if (tty) { tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } /* if transmitter idle and loopmode_send_done_requested * then start echoing RxD to TxD */ spin_lock_irqsave(&info->irq_spinlock,flags); if ( !info->tx_active && info->loopmode_send_done_requested ) usc_loopmode_send_done( info ); spin_unlock_irqrestore(&info->irq_spinlock,flags);}void mgsl_bh_status(struct mgsl_struct *info){ if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):mgsl_bh_status() entry on %s\n", __FILE__,__LINE__,info->device_name); info->ri_chkcount = 0; info->dsr_chkcount = 0; info->dcd_chkcount = 0; info->cts_chkcount = 0;}/* mgsl_isr_receive_status() * * Service a receive status interrupt. The type of status * interrupt is indicated by the state of the RCSR. * This is only used for HDLC mode. * * Arguments: info pointer to device instance data * Return Value: None */void mgsl_isr_receive_status( struct mgsl_struct *info ){ u16 status = usc_InReg( info, RCSR ); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_isr_receive_status status=%04X\n", __FILE__,__LINE__,status); if ( (status & RXSTATUS_ABORT_RECEIVED) && info->loopmode_insert_requested && usc_loopmode_active(info) ) { ++info->icount.rxabort; info->loopmode_insert_requested = FALSE; /* clear CMR:13 to start echoing RxD to TxD */ info->cmr_value &= ~BIT13; usc_OutReg(info, CMR, info->cmr_value); /* disable received abort irq (no longer required) */ usc_OutReg(info, RICR, (usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED)); } if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) { if (status & RXSTATUS_EXITED_HUNT) info->icount.exithunt++; if (status & RXSTATUS_IDLE_RECEIVED) info->icount.rxidle++; wake_up_interruptible(&info->event_wait_q); } if (status & RXSTATUS_OVERRUN){ info->icount.rxover++; usc_process_rxoverrun_sync( info ); } usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); usc_UnlatchRxstatusBits( info, status );} /* end of mgsl_isr_receive_status() *//* mgsl_isr_transmit_status() * * Service a transmit status interrupt * HDLC mode :end of transmit frame * Async mode:all data is sent * transmit status is indicated by bits in the TCSR. * * Arguments: info pointer to device instance data * Return Value: None */void mgsl_isr_transmit_status( struct mgsl_struct *info ){ u16 status = usc_InReg( info, TCSR ); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_isr_transmit_status status=%04X\n", __FILE__,__LINE__,status); usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); usc_UnlatchTxstatusBits( info, status ); if ( status & (TXSTATUS_UNDERRUN | TXSTATUS_ABORT_SENT) ) { /* finished sending HDLC abort. This may leave */ /* the TxFifo with data from the aborted frame */ /* so purge the TxFifo. Also shutdown the DMA */ /* channel in case there is data remaining in */ /* the DMA buffer */ usc_DmaCmd( info, DmaCmd_ResetTxChannel ); usc_RTCmd( info, RTCmd_PurgeTxFifo ); } if ( status & TXSTATUS_EOF_SENT ) info->icount.txok++; else if ( status & TXSTATUS_UNDERRUN ) info->icount.txunder++; else if ( status & TXSTATUS_ABORT_SENT ) info->icount.txabort++; else info->icount.txunder++; info->tx_active = 0; info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; del_timer(&info->tx_timer); if ( info->drop_rts_on_tx_done ) { usc_get_serial_signals( info ); if ( info->serial_signals & SerialSignal_RTS ) { info->serial_signals &= ~SerialSignal_RTS; usc_set_serial_signals( info ); } info->drop_rts_on_tx_done = 0; }#ifdef CONFIG_HDLC if (info->netcount) hdlcdev_tx_done(info); else #endif { if (info->tty->stopped || info->tty->hw_stopped) { usc_stop_transmitter(info); return; } info->pending_bh |= BH_TRANSMIT; }} /* end of mgsl_isr_transmit_status() *//* mgsl_isr_io_pin() * * Service an Input/Output pin interrupt. The type of * interrupt is indicated by bits in the MISR * * Arguments: info pointer to device instance data * Return Value: None */void mgsl_isr_io_pin( struct mgsl_struct *info ){ struct mgsl_icount *icount; u16 status = usc_InReg( info, MISR );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?