📄 serial167.c
字号:
#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 + -