⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sx.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	int retval, line;	unsigned long flags;	func_enter();	if (!sx_initialized) {		return -EIO;	}	line = tty->index;	sx_dprintk(SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, "			"np=%d)\n", task_pid_nr(current), line, tty,			current->signal->tty, sx_nports);	if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports))		return -ENODEV;	port = &sx_ports[line];	port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a			    1 -> 0 transition. */	sx_dprintk(SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);	spin_lock_irqsave(&port->gs.driver_lock, flags);	tty->driver_data = port;	port->gs.tty = tty;	port->gs.count++;	spin_unlock_irqrestore(&port->gs.driver_lock, flags);	sx_dprintk(SX_DEBUG_OPEN, "starting port\n");	/*	 * Start up serial port	 */	retval = gs_init_port(&port->gs);	sx_dprintk(SX_DEBUG_OPEN, "done gs_init\n");	if (retval) {		port->gs.count--;		return retval;	}	port->gs.flags |= GS_ACTIVE;	if (port->gs.count <= 1)		sx_setsignals(port, 1, 1);#if 0	if (sx_debug & SX_DEBUG_OPEN)		my_hd(port, sizeof(*port));#else	if (sx_debug & SX_DEBUG_OPEN)		my_hd_io(port->board->base + port->ch_base, sizeof(*port));#endif	if (port->gs.count <= 1) {		if (sx_send_command(port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {			printk(KERN_ERR "sx: Card didn't respond to LOPEN "					"command.\n");			spin_lock_irqsave(&port->gs.driver_lock, flags);			port->gs.count--;			spin_unlock_irqrestore(&port->gs.driver_lock, flags);			return -EIO;		}	}	retval = gs_block_til_ready(port, filp);	sx_dprintk(SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",			retval, port->gs.count);	if (retval) {/* * Don't lower gs.count here because sx_close() will be called later */		return retval;	}	/* tty->low_latency = 1; */	port->c_dcd = sx_get_CD(port);	sx_dprintk(SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);	func_exit();	return 0;}static void sx_close(void *ptr){	struct sx_port *port = ptr;	/* Give the port 5 seconds to close down. */	int to = 5 * HZ;	func_enter();	sx_setsignals(port, 0, 0);	sx_reconfigure_port(port);	sx_send_command(port, HS_CLOSE, 0, 0);	while (to-- && (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED))		if (msleep_interruptible(10))			break;	if (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) {		if (sx_send_command(port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED)				!= 1) {			printk(KERN_ERR "sx: sent the force_close command, but "					"card didn't react\n");		} else			sx_dprintk(SX_DEBUG_CLOSE, "sent the force_close "					"command.\n");	}	sx_dprintk(SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n",			5 * HZ - to - 1, port->gs.count);	if (port->gs.count) {		sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n",				port->gs.count);		/*printk("%s SETTING port count to zero: %p count: %d\n",				__FUNCTION__, port, port->gs.count);		port->gs.count = 0;*/	}	func_exit();}/* This is relatively thorough. But then again it is only 20 lines. */#define MARCHUP		for (i = min; i < max; i++)#define MARCHDOWN	for (i = max - 1; i >= min; i--)#define W0		write_sx_byte(board, i, 0x55)#define W1		write_sx_byte(board, i, 0xaa)#define R0		if (read_sx_byte(board, i) != 0x55) return 1#define R1		if (read_sx_byte(board, i) != 0xaa) return 1/* This memtest takes a human-noticable time. You normally only do it   once a boot, so I guess that it is worth it. */static int do_memtest(struct sx_board *board, int min, int max){	int i;	/* This is a marchb. Theoretically, marchb catches much more than	   simpler tests. In practise, the longer test just catches more	   intermittent errors. -- REW	   (For the theory behind memory testing see: 	   Testing Semiconductor Memories by A.J. van de Goor.) */	MARCHUP {		W0;	}	MARCHUP {		R0;		W1;		R1;		W0;		R0;		W1;	}	MARCHUP {		R1;		W0;		W1;	}	MARCHDOWN {		R1;		W0;		W1;		W0;	}	MARCHDOWN {		R0;		W1;		W0;	}	return 0;}#undef MARCHUP#undef MARCHDOWN#undef W0#undef W1#undef R0#undef R1#define MARCHUP		for (i = min; i < max; i += 2)#define MARCHDOWN	for (i = max - 1; i >= min; i -= 2)#define W0		write_sx_word(board, i, 0x55aa)#define W1		write_sx_word(board, i, 0xaa55)#define R0		if (read_sx_word(board, i) != 0x55aa) return 1#define R1		if (read_sx_word(board, i) != 0xaa55) return 1#if 0/* This memtest takes a human-noticable time. You normally only do it   once a boot, so I guess that it is worth it. */static int do_memtest_w(struct sx_board *board, int min, int max){	int i;	MARCHUP {		W0;	}	MARCHUP {		R0;		W1;		R1;		W0;		R0;		W1;	}	MARCHUP {		R1;		W0;		W1;	}	MARCHDOWN {		R1;		W0;		W1;		W0;	}	MARCHDOWN {		R0;		W1;		W0;	}	return 0;}#endifstatic int sx_fw_ioctl(struct inode *inode, struct file *filp,		unsigned int cmd, unsigned long arg){	int rc = 0;	int __user *descr = (int __user *)arg;	int i;	static struct sx_board *board = NULL;	int nbytes, offset;	unsigned long data;	char *tmp;	func_enter();#if 0	/* Removed superuser check: Sysops can use the permissions on the device	   file to restrict access. Recommendation: Root only. (root.root 600) */	if (!capable(CAP_SYS_ADMIN)) {		return -EPERM;	}#endif	sx_dprintk(SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);	if (!board)		board = &boards[0];	if (board->flags & SX_BOARD_PRESENT) {		sx_dprintk(SX_DEBUG_FIRMWARE, "Board present! (%x)\n",				board->flags);	} else {		sx_dprintk(SX_DEBUG_FIRMWARE, "Board not present! (%x) all:",				board->flags);		for (i = 0; i < SX_NBOARDS; i++)			sx_dprintk(SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);		sx_dprintk(SX_DEBUG_FIRMWARE, "\n");		return -EIO;	}	switch (cmd) {	case SXIO_SET_BOARD:		sx_dprintk(SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);		if (arg >= SX_NBOARDS)			return -EIO;		sx_dprintk(SX_DEBUG_FIRMWARE, "not out of range\n");		if (!(boards[arg].flags & SX_BOARD_PRESENT))			return -EIO;		sx_dprintk(SX_DEBUG_FIRMWARE, ".. and present!\n");		board = &boards[arg];		break;	case SXIO_GET_TYPE:		rc = -ENOENT;	/* If we manage to miss one, return error. */		if (IS_SX_BOARD(board))			rc = SX_TYPE_SX;		if (IS_CF_BOARD(board))			rc = SX_TYPE_CF;		if (IS_SI_BOARD(board))			rc = SX_TYPE_SI;		if (IS_SI1_BOARD(board))			rc = SX_TYPE_SI;		if (IS_EISA_BOARD(board))			rc = SX_TYPE_SI;		sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %d\n", rc);		break;	case SXIO_DO_RAMTEST:		if (sx_initialized)	/* Already initialized: better not ramtest the board.  */			return -EPERM;		if (IS_SX_BOARD(board)) {			rc = do_memtest(board, 0, 0x7000);			if (!rc)				rc = do_memtest(board, 0, 0x7000);			/*if (!rc) rc = do_memtest_w (board, 0, 0x7000); */		} else {			rc = do_memtest(board, 0, 0x7ff8);			/* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */		}		sx_dprintk(SX_DEBUG_FIRMWARE, "returning memtest result= %d\n",			   rc);		break;	case SXIO_DOWNLOAD:		if (sx_initialized)	/* Already initialized */			return -EEXIST;		if (!sx_reset(board))			return -EIO;		sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");		tmp = kmalloc(SX_CHUNK_SIZE, GFP_USER);		if (!tmp)			return -ENOMEM;		get_user(nbytes, descr++);		get_user(offset, descr++);		get_user(data, descr++);		while (nbytes && data) {			for (i = 0; i < nbytes; i += SX_CHUNK_SIZE) {				if (copy_from_user(tmp, (char __user *)data + i,						(i + SX_CHUNK_SIZE > nbytes) ?						nbytes - i : SX_CHUNK_SIZE)) {					kfree(tmp);					return -EFAULT;				}				memcpy_toio(board->base2 + offset + i, tmp,						(i + SX_CHUNK_SIZE > nbytes) ?						nbytes - i : SX_CHUNK_SIZE);			}			get_user(nbytes, descr++);			get_user(offset, descr++);			get_user(data, descr++);		}		kfree(tmp);		sx_nports += sx_init_board(board);		rc = sx_nports;		break;	case SXIO_INIT:		if (sx_initialized)	/* Already initialized */			return -EEXIST;		/* This is not allowed until all boards are initialized... */		for (i = 0; i < SX_NBOARDS; i++) {			if ((boards[i].flags & SX_BOARD_PRESENT) &&				!(boards[i].flags & SX_BOARD_INITIALIZED))				return -EIO;		}		for (i = 0; i < SX_NBOARDS; i++)			if (!(boards[i].flags & SX_BOARD_PRESENT))				break;		sx_dprintk(SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, "				"%d channels, first board: %d ports\n",				i, sx_nports, boards[0].nports);		rc = sx_init_portstructs(i, sx_nports);		sx_init_drivers();		if (rc >= 0)			sx_initialized++;		break;	case SXIO_SETDEBUG:		sx_debug = arg;		break;	case SXIO_GETDEBUG:		rc = sx_debug;		break;	case SXIO_GETGSDEBUG:	case SXIO_SETGSDEBUG:		rc = -EINVAL;		break;	case SXIO_GETNPORTS:		rc = sx_nports;		break;	default:		printk(KERN_WARNING "Unknown ioctl on firmware device (%x).\n",				cmd);		break;	}	func_exit();	return rc;}static void sx_break(struct tty_struct *tty, int flag){	struct sx_port *port = tty->driver_data;	int rv;	func_enter();	if (flag)		rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK);	else		rv = sx_send_command(port, HS_STOP, -1, HS_IDLE_OPEN);	if (rv != 1)		printk(KERN_ERR "sx: couldn't send break (%x).\n",			read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));	func_exit();}static int sx_tiocmget(struct tty_struct *tty, struct file *file){	struct sx_port *port = tty->driver_data;	return sx_getsignals(port);}static int sx_tiocmset(struct tty_struct *tty, struct file *file,		unsigned int set, unsigned int clear){	struct sx_port *port = tty->driver_data;	int rts = -1, dtr = -1;	if (set & TIOCM_RTS)		rts = 1;	if (set & TIOCM_DTR)		dtr = 1;	if (clear & TIOCM_RTS)		rts = 0;	if (clear & TIOCM_DTR)		dtr = 0;	sx_setsignals(port, dtr, rts);	sx_reconfigure_port(port);	return 0;}static int sx_ioctl(struct tty_struct *tty, struct file *filp,		unsigned int cmd, unsigned long arg){	int rc;	struct sx_port *port = tty->driver_data;	void __user *argp = (void __user *)arg;	int ival;	/* func_enter2(); */	rc = 0;	switch (cmd) {	case TIOCGSOFTCAR:		rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),				(unsigned __user *)argp);		break;	case TIOCSSOFTCAR:		if ((rc = get_user(ival, (unsigned __user *)argp)) == 0) {			tty->termios->c_cflag =				(tty->termios->c_cflag & ~CLOCAL) |				(ival ? CLOCAL : 0);		}		break;	case TIOCGSERIAL:		rc = gs_getserial(&port->gs, argp);		break;	case TIOCSSERIAL:		rc = gs_setserial(&port->gs, argp);		break;	default:		rc = -ENOIOCTLCMD;		break;	}	/* func_exit(); */	return rc;}/* The throttle/unthrottle scheme for the Specialix card is different * from other drivers and deserves some explanation.  * The Specialix hardware takes care of XON/XOFF * and CTS/RTS flow control itself.  This means that all we have to * do when signalled by the upper tty layer to throttle/unthrottle is * to make a note of it here.  When we come to read characters from the * rx buffers on the card (sx_receive_chars()) we look to see if the * upper layer can accept more (as noted here in sx_rx_throt[]).  * If it can't we simply don't remove chars from the cards buffer.  * When the tty layer can accept chars, we again note that here and when * sx_receive_chars() is called it will remove them from the cards buffer. * The card will notice that a ports buffer has drained below some low * water mark and will unflow control the line itself, using whatever * flow control scheme is in use for that port. -- Simon Allen */static void sx_throttle(struct tty_struct *tty){	struct sx_port *port = (struct sx_port *)tty->driver_data;	func_enter2();	/* If the port is using any type of input flow

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -