synclinkmp.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,458 行 · 第 1/5 页
C
2,458 行
static void synclinkmp_remove_one(struct pci_dev *dev);static struct pci_device_id synclinkmp_pci_tbl[] = { { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, /* terminate list */};MODULE_DEVICE_TABLE(pci, synclinkmp_pci_tbl);MODULE_LICENSE("GPL");static struct pci_driver synclinkmp_pci_driver = { .name = "synclinkmp", .id_table = synclinkmp_pci_tbl, .probe = synclinkmp_init_one, .remove = __devexit_p(synclinkmp_remove_one),};static struct tty_driver *serial_driver;/* number of characters left in xmit buffer before we ask for more */#define WAKEUP_CHARS 256/* tty callbacks */static int open(struct tty_struct *tty, struct file * filp);static void close(struct tty_struct *tty, struct file * filp);static void hangup(struct tty_struct *tty);static void set_termios(struct tty_struct *tty, struct termios *old_termios);static int write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);static void put_char(struct tty_struct *tty, unsigned char ch);static void send_xchar(struct tty_struct *tty, char ch);static void wait_until_sent(struct tty_struct *tty, int timeout);static int write_room(struct tty_struct *tty);static void flush_chars(struct tty_struct *tty);static void flush_buffer(struct tty_struct *tty);static void tx_hold(struct tty_struct *tty);static void tx_release(struct tty_struct *tty);static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);static int read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);static int chars_in_buffer(struct tty_struct *tty);static void throttle(struct tty_struct * tty);static void unthrottle(struct tty_struct * tty);static void set_break(struct tty_struct *tty, int break_state);#ifdef CONFIG_HDLC#define dev_to_port(D) (dev_to_hdlc(D)->priv)static void hdlcdev_tx_done(SLMP_INFO *info);static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size);static int hdlcdev_init(SLMP_INFO *info);static void hdlcdev_exit(SLMP_INFO *info);#endif/* ioctl handlers */static int get_stats(SLMP_INFO *info, struct mgsl_icount __user *user_icount);static int get_params(SLMP_INFO *info, MGSL_PARAMS __user *params);static int set_params(SLMP_INFO *info, MGSL_PARAMS __user *params);static int get_txidle(SLMP_INFO *info, int __user *idle_mode);static int set_txidle(SLMP_INFO *info, int idle_mode);static int tx_enable(SLMP_INFO *info, int enable);static int tx_abort(SLMP_INFO *info);static int rx_enable(SLMP_INFO *info, int enable);static int map_status(int signals);static int modem_input_wait(SLMP_INFO *info,int arg);static int wait_mgsl_event(SLMP_INFO *info, int __user *mask_ptr);static int tiocmget(struct tty_struct *tty, struct file *file);static int tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear);static void set_break(struct tty_struct *tty, int break_state);static void add_device(SLMP_INFO *info);static void device_init(int adapter_num, struct pci_dev *pdev);static int claim_resources(SLMP_INFO *info);static void release_resources(SLMP_INFO *info);static int startup(SLMP_INFO *info);static int block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info);static void shutdown(SLMP_INFO *info);static void program_hw(SLMP_INFO *info);static void change_params(SLMP_INFO *info);static int init_adapter(SLMP_INFO *info);static int register_test(SLMP_INFO *info);static int irq_test(SLMP_INFO *info);static int loopback_test(SLMP_INFO *info);static int adapter_test(SLMP_INFO *info);static int memory_test(SLMP_INFO *info);static void reset_adapter(SLMP_INFO *info);static void reset_port(SLMP_INFO *info);static void async_mode(SLMP_INFO *info);static void hdlc_mode(SLMP_INFO *info);static void rx_stop(SLMP_INFO *info);static void rx_start(SLMP_INFO *info);static void rx_reset_buffers(SLMP_INFO *info);static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last);static int rx_get_frame(SLMP_INFO *info);static void tx_start(SLMP_INFO *info);static void tx_stop(SLMP_INFO *info);static void tx_load_fifo(SLMP_INFO *info);static void tx_set_idle(SLMP_INFO *info);static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count);static void get_signals(SLMP_INFO *info);static void set_signals(SLMP_INFO *info);static void enable_loopback(SLMP_INFO *info, int enable);static void set_rate(SLMP_INFO *info, u32 data_rate);static int bh_action(SLMP_INFO *info);static void bh_handler(void* Context);static void bh_receive(SLMP_INFO *info);static void bh_transmit(SLMP_INFO *info);static void bh_status(SLMP_INFO *info);static void isr_timer(SLMP_INFO *info);static void isr_rxint(SLMP_INFO *info);static void isr_rxrdy(SLMP_INFO *info);static void isr_txint(SLMP_INFO *info);static void isr_txrdy(SLMP_INFO *info);static void isr_rxdmaok(SLMP_INFO *info);static void isr_rxdmaerror(SLMP_INFO *info);static void isr_txdmaok(SLMP_INFO *info);static void isr_txdmaerror(SLMP_INFO *info);static void isr_io_pin(SLMP_INFO *info, u16 status);static int alloc_dma_bufs(SLMP_INFO *info);static void free_dma_bufs(SLMP_INFO *info);static int alloc_buf_list(SLMP_INFO *info);static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *list, SCADESC_EX *list_ex,int count);static int alloc_tmp_rx_buf(SLMP_INFO *info);static void free_tmp_rx_buf(SLMP_INFO *info);static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count);static void trace_block(SLMP_INFO *info, const char* data, int count, int xmit);static void tx_timeout(unsigned long context);static void status_timeout(unsigned long context);static unsigned char read_reg(SLMP_INFO *info, unsigned char addr);static void write_reg(SLMP_INFO *info, unsigned char addr, unsigned char val);static u16 read_reg16(SLMP_INFO *info, unsigned char addr);static void write_reg16(SLMP_INFO *info, unsigned char addr, u16 val);static unsigned char read_status_reg(SLMP_INFO * info);static void write_control_reg(SLMP_INFO * info);static unsigned char rx_active_fifo_level = 16; // rx request FIFO activation level in bytesstatic unsigned char tx_active_fifo_level = 16; // tx request FIFO activation level in bytesstatic unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytesstatic u32 misc_ctrl_value = 0x007e4040;static u32 lcr1_brdr_value = 0x00800029;static u32 read_ahead_count = 8;/* DPCR, DMA Priority Control * * 07..05 Not used, must be 0 * 04 BRC, bus release condition: 0=all transfers complete * 1=release after 1 xfer on all channels * 03 CCC, channel change condition: 0=every cycle * 1=after each channel completes all xfers * 02..00 PR<2..0>, priority 100=round robin * * 00000100 = 0x00 */static unsigned char dma_priority = 0x04;// Number of bytes that can be written to shared RAM// in a single write operationstatic u32 sca_pci_load_interval = 64;/* * 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. */static void* synclinkmp_get_text_ptr(void);static void* synclinkmp_get_text_ptr(void) {return synclinkmp_get_text_ptr;}static inline int sanity_check(SLMP_INFO *info, char *name, const char *routine){#ifdef SANITY_CHECK static const char *badmagic = "Warning: bad magic number for synclinkmp_struct (%s) in %s\n"; static const char *badinfo = "Warning: null synclinkmp_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); }}/* tty callbacks *//* Called when a port is opened. Init and enable port. */static int open(struct tty_struct *tty, struct file *filp){ SLMP_INFO *info; int retval, line; unsigned long flags; line = tty->index; if ((line < 0) || (line >= synclinkmp_device_count)) { printk("%s(%d): open with invalid line #%d.\n", __FILE__,__LINE__,line); return -ENODEV; } info = synclinkmp_device_list; while(info && info->line != line) info = info->next_device; if (sanity_check(info, tty->name, "open")) return -ENODEV; if ( info->init_error ) { printk("%s(%d):%s device is not allocated, init error=%d\n", __FILE__,__LINE__,info->device_name,info->init_error); return -ENODEV; } tty->driver_data = info; info->tty = tty; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s open(), old ref count = %d\n", __FILE__,__LINE__,tty->driver->name, info->count); /* If port is closing, signal caller to try again */ if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){ if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); retval = ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); goto cleanup; } info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); if (info->netcount) { retval = -EBUSY; spin_unlock_irqrestore(&info->netlock, flags); goto cleanup; } info->count++; spin_unlock_irqrestore(&info->netlock, flags); if (info->count == 1) { /* 1st open on this device, init hardware */ retval = startup(info); if (retval < 0) goto cleanup; } retval = block_til_ready(tty, filp, info); if (retval) { if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s block_til_ready() returned %d\n", __FILE__,__LINE__, info->device_name, retval); goto cleanup; } if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s open() success\n", __FILE__,__LINE__, info->device_name); retval = 0;cleanup: if (retval) { if (tty->count == 1) info->tty = NULL; /* tty layer will release tty struct */ if(info->count) info->count--; } return retval;}/* Called when port is closed. Wait for remaining data to be * sent. Disable port and free resources. */static void close(struct tty_struct *tty, struct file *filp){ SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; if (sanity_check(info, tty->name, "close")) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() entry, count=%d\n", __FILE__,__LINE__, info->device_name, info->count); if (!info->count) return; if (tty_hung_up_p(filp)) goto cleanup; if ((tty->count == 1) && (info->count != 1)) { /* * tty->count is 1 and the tty structure will be freed. * info->count should be one in this case. * if it's not, correct it so that the port is shutdown. */ printk("%s(%d):%s close: bad refcount; tty->count is 1, " "info->count is %d\n", __FILE__,__LINE__, info->device_name, info->count); info->count = 1; } info->count--; /* if at least one open remaining, leave hardware active */ if (info->count) goto cleanup; info->flags |= ASYNC_CLOSING; /* set tty->closing to notify line discipline to * only process XON/XOFF characters. Only the N_TTY * discipline appears to use this (ppp does not). */ tty->closing = 1; /* wait for transmit data to clear all layers */ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) { if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() calling tty_wait_until_sent\n", __FILE__,__LINE__, info->device_name ); tty_wait_until_sent(tty, info->closing_wait); } if (info->flags & ASYNC_INITIALIZED) wait_until_sent(tty, info->timeout); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); shutdown(info); tty->closing = 0; info->tty = NULL; if (info->blocked_open) { if (info->close_delay) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait);cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__, tty->driver->name, info->count);}/* Called by tty_hangup() when a hangup is signaled. * This is the same as closing all open descriptors for the port. */static void hangup(struct tty_struct *tty){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s hangup()\n", __FILE__,__LINE__, info->device_name ); if (sanity_check(info, tty->name, "hangup")) return; flush_buffer(tty); shutdown(info); info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; wake_up_interruptible(&info->open_wait);}/* Set new termios settings */static void set_termios(struct tty_struct *tty, struct termios *old_termios){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s set_termios()\n", __FILE__,__LINE__, tty->driver->name ); /* just return if nothing has changed */ if ((tty->termios->c_cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) return; change_params(info); /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && !(tty->termios->c_cflag & CBAUD)) { info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); spin_lock_irqsave(&info->lock,flags); set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && tty->termios->c_cflag & CBAUD) { info->serial_signals |= SerialSignal_DTR; if (!(tty->termios->c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->serial_signals |= SerialSignal_RTS; } spin_lock_irqsave(&info->lock,flags); set_signals(info); spin_unlock_irqrestore(&info->lock,flags); } /* Handle turning off CRTSCTS */ if (old_termios->c_cflag & CRTSCTS && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; tx_release(tty); }}/* Send a block of data * * Arguments: * * tty pointer to tty information structure * from_user flag: 1 = from user process * buf pointer to buffer containing send data * count size of send data in bytes * * Return Value: number of characters written */static int write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ int c, ret = 0, err;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?