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

📄 specialix.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	tmp.xmit_fifo_size = CD186x_NFIFO;	copy_to_user(retinfo, &tmp, sizeof(tmp));	return 0;}static int sx_ioctl(struct tty_struct * tty, struct file * filp,                     unsigned int cmd, unsigned long arg){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	int error;	int retval;					if (sx_paranoia_check(port, tty->device, "sx_ioctl"))		return -ENODEV;		switch (cmd) {	 case TCSBRK:	/* SVID version: non-zero arg --> no break */		retval = tty_check_change(tty);		if (retval)			return retval;		tty_wait_until_sent(tty, 0);		if (!arg)			sx_send_break(port, HZ/4);	/* 1/4 second */		return 0;	 case TCSBRKP:	/* support for POSIX tcsendbreak() */		retval = tty_check_change(tty);		if (retval)			return retval;		tty_wait_until_sent(tty, 0);		sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);		return 0;	 case TIOCGSOFTCAR:		error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));		if (error)			return error;		put_user(C_CLOCAL(tty) ? 1 : 0,		         (unsigned long *) arg);		return 0;	 case TIOCSSOFTCAR:		Get_user(arg, (unsigned long *) arg);		tty->termios->c_cflag =			((tty->termios->c_cflag & ~CLOCAL) |			(arg ? CLOCAL : 0));		return 0;	 case TIOCMGET:		error = verify_area(VERIFY_WRITE, (void *) arg,		                    sizeof(unsigned int));		if (error)			return error;		return sx_get_modem_info(port, (unsigned int *) arg);	 case TIOCMBIS:	 case TIOCMBIC:	 case TIOCMSET:		return sx_set_modem_info(port, cmd, (unsigned int *) arg);	 case TIOCGSERIAL:			return sx_get_serial_info(port, (struct serial_struct *) arg);	 case TIOCSSERIAL:			return sx_set_serial_info(port, (struct serial_struct *) arg);	 default:		return -ENOIOCTLCMD;	}	return 0;}static void sx_throttle(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	unsigned long flags;					if (sx_paranoia_check(port, tty->device, "sx_throttle"))		return;		bp = port_Board(port);		save_flags(flags); cli();	/* Use DTR instead of RTS ! */	if (SX_CRTSCTS (tty)) 		port->MSVR &= ~MSVR_DTR;	else {		/* Auch!!! I think the system shouldn't call this then. */		/* Or maybe we're supposed (allowed?) to do our side of hw		   handshake anyway, even when hardware handshake is off. 		   When you see this in your logs, please report.... */		printk (KERN_ERR "sx%d: Need to throttle, but can't (hardware hs is off)\n",	                 port_No (port));	}	sx_out(bp, CD186x_CAR, port_No(port));	if (I_IXOFF(tty)) {		sx_wait_CCR(bp);		sx_out(bp, CD186x_CCR, CCR_SSCH2);		sx_wait_CCR(bp);	}	sx_out(bp, CD186x_MSVR, port->MSVR);	restore_flags(flags);}static void sx_unthrottle(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	unsigned long flags;					if (sx_paranoia_check(port, tty->device, "sx_unthrottle"))		return;		bp = port_Board(port);		save_flags(flags); cli();	/* XXXX Use DTR INSTEAD???? */	if (SX_CRTSCTS(tty)) {		port->MSVR |= MSVR_DTR;	} /* Else clause: see remark in "sx_throttle"... */	sx_out(bp, CD186x_CAR, port_No(port));	if (I_IXOFF(tty)) {		sx_wait_CCR(bp);		sx_out(bp, CD186x_CCR, CCR_SSCH1);		sx_wait_CCR(bp);	}	sx_out(bp, CD186x_MSVR, port->MSVR);	restore_flags(flags);}static void sx_stop(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	unsigned long flags;					if (sx_paranoia_check(port, tty->device, "sx_stop"))		return;		bp = port_Board(port);		save_flags(flags); cli();	port->IER &= ~IER_TXRDY;	sx_out(bp, CD186x_CAR, port_No(port));	sx_out(bp, CD186x_IER, port->IER);	restore_flags(flags);}static void sx_start(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	unsigned long flags;					if (sx_paranoia_check(port, tty->device, "sx_start"))		return;		bp = port_Board(port);		save_flags(flags); cli();	if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {		port->IER |= IER_TXRDY;		sx_out(bp, CD186x_CAR, port_No(port));		sx_out(bp, CD186x_IER, port->IER);	}	restore_flags(flags);}/* * This routine is called from the scheduler tqueue when the interrupt * routine has signalled that a hangup has occurred.  The path of * hangup processing is: * * 	serial interrupt routine -> (scheduler tqueue) -> * 	do_sx_hangup() -> tty->hangup() -> sx_hangup() *  */static void do_sx_hangup(void *private_){	struct specialix_port	*port = (struct specialix_port *) private_;	struct tty_struct	*tty;		tty = port->tty;	if (!tty)		return;	tty_hangup(tty);}static void sx_hangup(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;					if (sx_paranoia_check(port, tty->device, "sx_hangup"))		return;		bp = port_Board(port);		sx_shutdown_port(bp, port);	port->event = 0;	port->count = 0;	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);	port->tty = 0;	wake_up_interruptible(&port->open_wait);}static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	unsigned long flags;					if (sx_paranoia_check(port, tty->device, "sx_set_termios"))		return;		if (tty->termios->c_cflag == old_termios->c_cflag &&	    tty->termios->c_iflag == old_termios->c_iflag)		return;	save_flags(flags); cli();	sx_change_speed(port_Board(port), port);	restore_flags(flags);	if ((old_termios->c_cflag & CRTSCTS) &&	    !(tty->termios->c_cflag & CRTSCTS)) {		tty->hw_stopped = 0;		sx_start(tty);	}}static void do_specialix_bh(void){	 run_task_queue(&tq_specialix);}static void do_softint(void *private_){	struct specialix_port	*port = (struct specialix_port *) private_;	struct tty_struct	*tty;		if(!(tty = port->tty)) 		return;	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&		    tty->ldisc.write_wakeup)			(tty->ldisc.write_wakeup)(tty);		wake_up_interruptible(&tty->write_wait);	}}static int sx_init_drivers(void){	int error;	int i;		if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) {		printk(KERN_ERR "sx: Couldn't get free page.\n");		return 1;	}	init_bh(SPECIALIX_BH, do_specialix_bh);	memset(&specialix_driver, 0, sizeof(specialix_driver));	specialix_driver.magic = TTY_DRIVER_MAGIC;	specialix_driver.name = "ttyW";	specialix_driver.major = SPECIALIX_NORMAL_MAJOR;	specialix_driver.num = SX_NBOARD * SX_NPORT;	specialix_driver.type = TTY_DRIVER_TYPE_SERIAL;	specialix_driver.subtype = SPECIALIX_TYPE_NORMAL;	specialix_driver.init_termios = tty_std_termios;	specialix_driver.init_termios.c_cflag =		B9600 | CS8 | CREAD | HUPCL | CLOCAL;	specialix_driver.flags = TTY_DRIVER_REAL_RAW;	specialix_driver.refcount = &specialix_refcount;	specialix_driver.table = specialix_table;	specialix_driver.termios = specialix_termios;	specialix_driver.termios_locked = specialix_termios_locked;	specialix_driver.open  = sx_open;	specialix_driver.close = sx_close;	specialix_driver.write = sx_write;	specialix_driver.put_char = sx_put_char;	specialix_driver.flush_chars = sx_flush_chars;	specialix_driver.write_room = sx_write_room;	specialix_driver.chars_in_buffer = sx_chars_in_buffer;	specialix_driver.flush_buffer = sx_flush_buffer;	specialix_driver.ioctl = sx_ioctl;	specialix_driver.throttle = sx_throttle;	specialix_driver.unthrottle = sx_unthrottle;	specialix_driver.set_termios = sx_set_termios;	specialix_driver.stop = sx_stop;	specialix_driver.start = sx_start;	specialix_driver.hangup = sx_hangup;	specialix_callout_driver = specialix_driver;	specialix_callout_driver.name = "cuw";	specialix_callout_driver.major = SPECIALIX_CALLOUT_MAJOR;	specialix_callout_driver.subtype = SPECIALIX_TYPE_CALLOUT;		if ((error = tty_register_driver(&specialix_driver))) {		free_page((unsigned long)tmp_buf);		printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",		       error);		return 1;	}	if ((error = tty_register_driver(&specialix_callout_driver))) {		free_page((unsigned long)tmp_buf);		tty_unregister_driver(&specialix_driver);		printk(KERN_ERR "sx: Couldn't register specialix IO8+ callout driver, error = %d\n",		       error);		return 1;	}		memset(sx_port, 0, sizeof(sx_port));	for (i = 0; i < SX_NPORT * SX_NBOARD; i++) {		sx_port[i].callout_termios = specialix_callout_driver.init_termios;		sx_port[i].normal_termios  = specialix_driver.init_termios;		sx_port[i].magic = SPECIALIX_MAGIC;		sx_port[i].tqueue.routine = do_softint;		sx_port[i].tqueue.data = &sx_port[i];		sx_port[i].tqueue_hangup.routine = do_sx_hangup;		sx_port[i].tqueue_hangup.data = &sx_port[i];		sx_port[i].close_delay = 50 * HZ/100;		sx_port[i].closing_wait = 3000 * HZ/100;	}		return 0;}static void sx_release_drivers(void){	free_page((unsigned long)tmp_buf);	tty_unregister_driver(&specialix_driver);	tty_unregister_driver(&specialix_callout_driver);}#ifndef MODULE/* * Called at boot time. *  * You can specify IO base for up to SX_NBOARD cards, * using line "specialix=0xiobase1,0xiobase2,.." at LILO prompt. * Note that there will be no probing at default * addresses in this case. * */ void specialix_setup(char *str, int * ints){	int i;        	for (i=0;i<SX_NBOARD;i++) {		sx_board[i].base = 0;	}	for (i = 1; i <= ints[0]; i++) {		if (i&1)			sx_board[i/2].base = ints[i];		else			sx_board[i/2 -1].irq = ints[i];	}}#endif/*  * This routine must be called by kernel at boot time  */int specialix_init(void) {	int i;	int found = 0;	printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");	printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");#ifdef CONFIG_SPECIALIX_RTSCTS	printk (KERN_INFO "sx: DTR/RTS pin is always RTS.\n");#else	printk (KERN_INFO "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n");#endif		if (sx_init_drivers()) 		return -EIO;	for (i = 0; i < SX_NBOARD; i++) 		if (sx_board[i].base && !sx_probe(&sx_board[i]))			found++;#ifdef CONFIG_PCI	if (pci_present()) {		struct pci_dev *pdev = NULL;		unsigned int tint;		i=0;		while (i <= SX_NBOARD) {			if (sx_board[i].flags & SX_BOARD_PRESENT) {				i++;				continue;			}			pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, 			                        PCI_DEVICE_ID_SPECIALIX_IO8, 			                        pdev);			if (!pdev) break;			sx_board[i].irq = pdev->irq;			pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint);			/* Mask out the fact that it's IO-space */			sx_board[i].base = tint & PCI_BASE_ADDRESS_IO_MASK; 			sx_board[i].flags |= SX_BOARD_IS_PCI;			if (!sx_probe(&sx_board[i]))				found ++;		}	}#endif	if (!found) {		sx_release_drivers();		printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");		return -EIO;	}	return 0;}#ifdef MODULEint iobase[SX_NBOARD]  = {0,};int irq [SX_NBOARD] = {0,};/* * You can setup up to 4 boards. * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter. * You should specify the IRQs too in that case "irq=....,...".  *  * More than 4 boards in one computer is not possible, as the card can * only use 4 different interrupts.  * */int init_module(void) {	int i;	if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {		for(i = 0; i < SX_NBOARD; i++) {			sx_board[i].base = iobase[i];			sx_board[i].irq = irq[i];		}	}	return specialix_init();}	void cleanup_module(void){	int i;		sx_release_drivers();	for (i = 0; i < SX_NBOARD; i++)		if (sx_board[i].flags & SX_BOARD_PRESENT) 			sx_release_io_range(&sx_board[i]);#ifdef SPECIALIX_TIMER	del_timer (&missed_irq_timer);#endif	}#endif /* MODULE */

⌨️ 快捷键说明

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