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

📄 serial167.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	tty->ldisc.flush_buffer(tty);    info->event = 0;    info->tty = 0;    if (tty->ldisc.num != ldiscs[N_TTY].num) {	if (tty->ldisc.close)	    (tty->ldisc.close)(tty);	tty->ldisc = ldiscs[N_TTY];	tty->termios->c_line = N_TTY;	if (tty->ldisc.open)	    (tty->ldisc.open)(tty);    }    if (info->blocked_open) {	if (info->close_delay) {	    current->state = TASK_INTERRUPTIBLE;	    schedule_timeout(info->close_delay);	}	wake_up_interruptible(&info->open_wait);    }    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|		     ASYNC_CLOSING);    wake_up_interruptible(&info->close_wait);#ifdef SERIAL_DEBUG_OTHER    printk("cy_close done\n");#endif    return;} /* cy_close *//* * cy_hangup() --- called by tty_hangup() when a hangup is signaled. */voidcy_hangup(struct tty_struct *tty){  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;	#ifdef SERIAL_DEBUG_OTHER    printk("cy_hangup ttyS%d\n", info->line); /* */#endif    if (serial_paranoia_check(info, tty->device, "cy_hangup"))	return;        shutdown(info);#if 0    info->event = 0;    info->count = 0;#ifdef SERIAL_DEBUG_COUNT    printk("cyc: %d: setting count to 0\n", __LINE__);#endif    info->tty = 0;#endif    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);    wake_up_interruptible(&info->open_wait);} /* cy_hangup *//* * ------------------------------------------------------------ * cy_open() and friends * ------------------------------------------------------------ */static intblock_til_ready(struct tty_struct *tty, struct file * filp,                           struct cyclades_port *info){  DECLARE_WAITQUEUE(wait, current);  unsigned long flags;  int channel;  int retval;  volatile u_char *base_addr = (u_char *)BASE_ADDR;    /*     * If the device is in the middle of being closed, then block     * until it's done, and then try again.     */    if (info->flags & ASYNC_CLOSING) {	interruptible_sleep_on(&info->close_wait);	if (info->flags & ASYNC_HUP_NOTIFY){	    return -EAGAIN;	}else{	    return -ERESTARTSYS;	}    }    /*     * If this is a callout device, then just make sure the normal     * device isn't being used.     */    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {	if (info->flags & ASYNC_NORMAL_ACTIVE){	    return -EBUSY;	}	if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&	    (info->flags & ASYNC_SESSION_LOCKOUT) &&	    (info->session != current->session)){	    return -EBUSY;	}	if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&	    (info->flags & ASYNC_PGRP_LOCKOUT) &&	    (info->pgrp != current->pgrp)){	    return -EBUSY;	}	info->flags |= ASYNC_CALLOUT_ACTIVE;	return 0;    }    /*     * If non-blocking mode is set, then make the check up front     * and then exit.     */    if (filp->f_flags & O_NONBLOCK) {	if (info->flags & ASYNC_CALLOUT_ACTIVE){	    return -EBUSY;	}	info->flags |= ASYNC_NORMAL_ACTIVE;	return 0;    }    /*     * Block waiting for the carrier detect and the line to become     * free (i.e., not in use by the callout).  While we are in     * this loop, info->count is dropped by one, so that     * cy_close() knows when to free things.  We restore it upon     * exit, either normal or abnormal.     */    retval = 0;    add_wait_queue(&info->open_wait, &wait);#ifdef SERIAL_DEBUG_OPEN    printk("block_til_ready before block: ttyS%d, count = %d\n",	   info->line, info->count);/**/#endif    info->count--;#ifdef SERIAL_DEBUG_COUNT    printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);#endif    info->blocked_open++;    channel = info->line;    while (1) {	save_flags(flags); cli();	    if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){		base_addr[CyCAR] = (u_char)channel;		base_addr[CyMSVR1] = CyRTS;/* CP('S');CP('4'); */		base_addr[CyMSVR2] = CyDTR;#ifdef SERIAL_DEBUG_DTR                printk("cyc: %d: raising DTR\n", __LINE__);                printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);#endif	    }	restore_flags(flags);	set_current_state(TASK_INTERRUPTIBLE);	if (tty_hung_up_p(filp)	|| !(info->flags & ASYNC_INITIALIZED) ){	    if (info->flags & ASYNC_HUP_NOTIFY) {		retval = -EAGAIN;	    }else{		retval = -ERESTARTSYS;	    }	    break;	}	save_flags(flags); cli();	    base_addr[CyCAR] = (u_char)channel;/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */	    if (!(info->flags & ASYNC_CALLOUT_ACTIVE)	    && !(info->flags & ASYNC_CLOSING)	    && (C_CLOCAL(tty)	        || (base_addr[CyMSVR1] & CyDCD))) {		    restore_flags(flags);		    break;	    }	restore_flags(flags);	if (signal_pending(current)) {	    retval = -ERESTARTSYS;	    break;	}#ifdef SERIAL_DEBUG_OPEN	printk("block_til_ready blocking: ttyS%d, count = %d\n",	       info->line, info->count);/**/#endif	schedule();    }    current->state = TASK_RUNNING;    remove_wait_queue(&info->open_wait, &wait);    if (!tty_hung_up_p(filp)){	info->count++;#ifdef SERIAL_DEBUG_COUNT    printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);#endif    }    info->blocked_open--;#ifdef SERIAL_DEBUG_OPEN    printk("block_til_ready after blocking: ttyS%d, count = %d\n",	   info->line, info->count);/**/#endif    if (retval)	    return retval;    info->flags |= ASYNC_NORMAL_ACTIVE;    return 0;} /* block_til_ready *//* * This routine is called whenever a serial port is opened.  It * performs the serial-specific initialization for the tty structure. */intcy_open(struct tty_struct *tty, struct file * filp){  struct cyclades_port  *info;  int retval, line;/* CP('O'); */    line = MINOR(tty->device) - tty->driver.minor_start;    if ((line < 0) || (NR_PORTS <= line)){        return -ENODEV;    }    info = &cy_port[line];    if (info->line < 0){        return -ENODEV;    }#ifdef SERIAL_DEBUG_OTHER    printk("cy_open ttyS%d\n", info->line); /* */#endif    if (serial_paranoia_check(info, tty->device, "cy_open")){        return -ENODEV;    }#ifdef SERIAL_DEBUG_OPEN    printk("cy_open ttyS%d, count = %d\n", info->line, info->count);/**/#endif    info->count++;#ifdef SERIAL_DEBUG_COUNT    printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);#endif    tty->driver_data = info;    info->tty = tty;    if (!tmp_buf) {	tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);	if (!tmp_buf){	    return -ENOMEM;        }    }    if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {	if (tty->driver.subtype == SERIAL_TYPE_NORMAL)	    *tty->termios = info->normal_termios;	else 	    *tty->termios = info->callout_termios;    }    /*     * Start up serial port     */    retval = startup(info);    if (retval){	return retval;    }    retval = block_til_ready(tty, filp, info);    if (retval) {#ifdef SERIAL_DEBUG_OPEN	printk("cy_open returning after block_til_ready with %d\n",	       retval);#endif	return retval;    }    info->session = current->session;    info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN    printk("cy_open done\n");/**/#endif    return 0;} /* cy_open *//* * --------------------------------------------------------------------- * serial167_init() and friends * * serial167_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- *//* * This routine prints out the appropriate serial driver version * number, and identifies which options were configured into this * driver. */static voidshow_version(void){    printk("MVME166/167 cd2401 driver\n");} /* show_version *//* initialize chips on card -- return number of valid   chips (which is number of ports/4) *//* * This initialises the hardware to a reasonable state.  It should * probe the chip first so as to copy 166-Bug setup as a default for * port 0.  It initialises CMR to CyASYNC; that is never done again, so * as to limit the number of CyINIT_CHAN commands in normal running. * * ... I wonder what I should do if this fails ... */voidmvme167_serial_console_setup(int cflag){	volatile unsigned char* base_addr = (u_char *)BASE_ADDR;	int ch;	u_char spd;	u_char rcor, rbpr, badspeed = 0;	unsigned long flags;	save_flags(flags); cli();	/*	 * First probe channel zero of the chip, to see what speed has	 * been selected.	 */	base_addr[CyCAR] = 0;	rcor = base_addr[CyRCOR] << 5;	rbpr = base_addr[CyRBPR];	for (spd = 0; spd < sizeof(baud_bpr); spd++)		if (rbpr == baud_bpr[spd] && rcor == baud_co[spd])			break;	if (spd >= sizeof(baud_bpr)) {		spd = 14;	/* 19200 */		badspeed = 1;	/* Failed to identify speed */	}	initial_console_speed = spd;	/* OK, we have chosen a speed, now reset and reinitialise */        my_udelay(20000L);	/* Allow time for any active o/p to complete */        if(base_addr[CyCCR] != 0x00){            restore_flags(flags);            /* printk(" chip is never idle (CCR != 0)\n"); */            return;        }        base_addr[CyCCR] = CyCHIP_RESET;	/* Reset the chip */        my_udelay(1000L);        if(base_addr[CyGFRCR] == 0x00){            restore_flags(flags);            /* printk(" chip is not responding (GFRCR stayed 0)\n"); */            return;        }	/*	 * System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms	 * tick	 */	base_addr[CyTPR] = 10;	base_addr[CyPILR1] = 0x01;    /* Interrupt level for modem change */	base_addr[CyPILR2] = 0x02;    /* Interrupt level for tx ints */	base_addr[CyPILR3] = 0x03;    /* Interrupt level for rx ints */	/*	 * Attempt to set up all channels to something reasonable, and	 * bang out a INIT_CHAN command.  We should then be able to limit	 * the ammount of fiddling we have to do in normal running.	 */	for (ch = 3; ch >= 0 ; ch--) {		base_addr[CyCAR] = (u_char)ch;		base_addr[CyIER] = 0;		base_addr[CyCMR] = CyASYNC;		base_addr[CyLICR] = (u_char)ch << 2;		base_addr[CyLIVR] = 0x5c;		base_addr[CyTCOR] = baud_co[spd];		base_addr[CyTBPR] = baud_bpr[spd];		base_addr[CyRCOR] = baud_co[spd] >> 5;		base_addr[CyRBPR] = baud_bpr[spd];		base_addr[CySCHR1] = 'Q' & 0x1f;		base_addr[CySCHR2] = 'X' & 0x1f;		base_addr[CySCRL] = 0;		base_addr[CySCRH] = 0;		base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;		base_addr[CyCOR2] = 0;		base_addr[CyCOR3] = Cy_1_STOP;		base_addr[CyCOR4] = baud_cor4[spd];		base_addr[CyCOR5] = 0;		base_addr[CyCOR6] = 0;		base_addr[CyCOR7] = 0;		base_addr[CyRTPRL] = 2;		base_addr[CyRTPRH] = 0;	        base_addr[CyMSVR1] = 0;	        base_addr[CyMSVR2] = 0;		write_cy_cmd(base_addr,CyINIT_CHAN|CyDIS_RCVR|CyDIS_XMTR);	}	/*	 * Now do specials for channel zero....	 */        base_addr[CyMSVR1] = CyRTS;        base_addr[CyMSVR2] = CyDTR;	base_addr[CyIER] = CyRxData;	write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR);	restore_flags(flags);	my_udelay(20000L);	/* Let it all settle down */        printk("CD2401 initialised,  chip is rev 0x%02x\n", base_addr[CyGFRCR]);	if (badspeed)        	printk("  WARNING:  Failed to identify line speed, rcor=%02x,rbpr=%02x\n",					rcor >> 5, rbpr);} /* serial_console_init *//* The serial driver boot-time initialization code!    Hardware I/O ports are mapped to character special devices on a    first found, first allocated manner.  That is, this code searches    for Cyclom cards in the system.  As each is found, it is probed    to discover how many chips (and thus how many ports) are present.    These ports are mapped to the tty ports 64 and upward in monotonic    fashion.  If an 8-port card is replaced with a 16-port card, the    port mapping on a following card will shift.    This approach is different from what is used in the other serial    device driver because the Cyclom is more properly a multiplexer,    not just an aggregation of serial ports on one card.    If there are more cards with more ports than have been statically    allocated above, a warning is printed and the extra ports are ignored. */intserial167_init(void){  struct cyclades_port *info;  int ret = 0;  int good_ports = 0;  int port_num = 0;  int index;  int DefSpeed;#ifdef notyet  struct sigaction sa;#endif    if (!(mvme16x_config &MVME16x_CONFIG_GOT_CD2401))	return 0;#if 0scrn[1] = '\0';#endif    show_version();    /* Has "console=0,9600n8" been used in bootinfo to change speed? */    if (serial_console_cflag)	DefSpeed = serial_console_cflag & 0017;    else {	DefSpeed = initial_console_speed;	serial_console_info = &cy_port[0];	serial_console_cflag = DefSpeed | CS8;#if 0	ser

⌨️ 快捷键说明

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