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 + -
显示快捷键?