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

📄 serial167.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
#ifdef SERIAL_DEBUG_OPEN    printk("cy_close ttyS%d, count = %d\n", info->line, info->count);#endif    if ((tty->count == 1) && (info->count != 1)) {	/*	 * Uh, oh.  tty->count is 1, which means that the tty	 * structure will be freed.  Info->count should always	 * be one in these conditions.  If it's greater than	 * one, we've got real problems, since it means the	 * serial port won't be shutdown.	 */	printk("cy_close: bad serial port count; tty->count is 1, "	   "info->count is %d\n", info->count);	info->count = 1;    }#ifdef SERIAL_DEBUG_COUNT    printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count - 1);#endif    if (--info->count < 0) {	printk("cy_close: bad serial port count for ttys%d: %d\n",	       info->line, info->count);#ifdef SERIAL_DEBUG_COUNT    printk("cyc: %d: setting count to 0\n", __LINE__);#endif	info->count = 0;    }    if (info->count)	return;    info->flags |= ASYNC_CLOSING;    /*     * Save the termios structure, since this port may have     * separate termios for callout and dialin.     */    if (info->flags & ASYNC_NORMAL_ACTIVE)	info->normal_termios = *tty->termios;    if (info->flags & ASYNC_CALLOUT_ACTIVE)	info->callout_termios = *tty->termios;    if (info->flags & ASYNC_INITIALIZED)	tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */    shutdown(info);    if (tty->driver.flush_buffer)	tty->driver.flush_buffer(tty);    if (tty->ldisc.flush_buffer)	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){  struct wait_queue wait = { current, NULL };  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);	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){            /* 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){            /* 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, f

⌨️ 快捷键说明

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