📄 istallion.c
字号:
sp = str; if ((*sp == '0') && (*(sp+1) == 'x')) { base = 16; sp += 2; } else if (*sp == '0') { base = 8; sp++; } else { base = 10; } for (; (*sp != 0); sp++) { c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); if ((c < 0) || (c >= base)) { printk("STALLION: invalid argument %s\n", str); val = 0; break; } val = (val * base) + c; } return(val);}/*****************************************************************************//* * Parse the supplied argument string, into the board conf struct. */static int stli_parsebrd(stlconf_t *confp, char **argp){ char *sp; int nrbrdnames, i;#if DEBUG printk("stli_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp);#endif if ((argp[0] == (char *) NULL) || (*argp[0] == 0)) return(0); for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++) *sp = TOLOWER(*sp); nrbrdnames = sizeof(stli_brdstr) / sizeof(stlibrdtype_t); for (i = 0; (i < nrbrdnames); i++) { if (strcmp(stli_brdstr[i].name, argp[0]) == 0) break; } if (i >= nrbrdnames) { printk("STALLION: unknown board name, %s?\n", argp[0]); return(0); } confp->brdtype = stli_brdstr[i].type; if ((argp[1] != (char *) NULL) && (*argp[1] != 0)) confp->ioaddr1 = stli_atol(argp[1]); if ((argp[2] != (char *) NULL) && (*argp[2] != 0)) confp->memaddr = stli_atol(argp[2]); return(1);}#endif/*****************************************************************************//* * Local driver kernel malloc routine. */static void *stli_memalloc(int len){ return((void *) kmalloc(len, GFP_KERNEL));}/*****************************************************************************/static int stli_open(struct tty_struct *tty, struct file *filp){ stlibrd_t *brdp; stliport_t *portp; unsigned int minordev; int brdnr, portnr, rc;#if DEBUG printk("stli_open(tty=%x,filp=%x): device=%x\n", (int) tty, (int) filp, tty->device);#endif minordev = MINOR(tty->device); brdnr = MINOR2BRD(minordev); if (brdnr >= stli_nrbrds) return(-ENODEV); brdp = stli_brds[brdnr]; if (brdp == (stlibrd_t *) NULL) return(-ENODEV); if ((brdp->state & BST_STARTED) == 0) return(-ENODEV); portnr = MINOR2PORT(minordev); if ((portnr < 0) || (portnr > brdp->nrports)) return(-ENODEV); portp = brdp->ports[portnr]; if (portp == (stliport_t *) NULL) return(-ENODEV); if (portp->devnr < 1) return(-ENODEV); MOD_INC_USE_COUNT;/* * Check if this port is in the middle of closing. If so then wait * until it is closed then return error status based on flag settings. * The sleep here does not need interrupt protection since the wakeup * for it is done with the same context. */ if (portp->flags & ASYNC_CLOSING) { interruptible_sleep_on(&portp->close_wait); if (portp->flags & ASYNC_HUP_NOTIFY) return(-EAGAIN); return(-ERESTARTSYS); }/* * On the first open of the device setup the port hardware, and * initialize the per port data structure. Since initializing the port * requires several commands to the board we will need to wait for any * other open that is already initializing the port. */ portp->tty = tty; tty->driver_data = portp; portp->refcount++; while (test_bit(ST_INITIALIZING, &portp->state)) { if (signal_pending(current)) return(-ERESTARTSYS); interruptible_sleep_on(&portp->raw_wait); } if ((portp->flags & ASYNC_INITIALIZED) == 0) { set_bit(ST_INITIALIZING, &portp->state); if ((rc = stli_initopen(brdp, portp)) >= 0) { portp->flags |= ASYNC_INITIALIZED; clear_bit(TTY_IO_ERROR, &tty->flags); } clear_bit(ST_INITIALIZING, &portp->state); wake_up_interruptible(&portp->raw_wait); if (rc < 0) return(rc); }/* * Check if this port is in the middle of closing. If so then wait * until it is closed then return error status, based on flag settings. * The sleep here does not need interrupt protection since the wakeup * for it is done with the same context. */ if (portp->flags & ASYNC_CLOSING) { interruptible_sleep_on(&portp->close_wait); if (portp->flags & ASYNC_HUP_NOTIFY) return(-EAGAIN); return(-ERESTARTSYS); }/* * Based on type of open being done check if it can overlap with any * previous opens still in effect. If we are a normal serial device * then also we might have to wait for carrier. */ if (tty->driver.subtype == STL_DRVTYPCALLOUT) { if (portp->flags & ASYNC_NORMAL_ACTIVE) return(-EBUSY); if (portp->flags & ASYNC_CALLOUT_ACTIVE) { if ((portp->flags & ASYNC_SESSION_LOCKOUT) && (portp->session != current->session)) return(-EBUSY); if ((portp->flags & ASYNC_PGRP_LOCKOUT) && (portp->pgrp != current->pgrp)) return(-EBUSY); } portp->flags |= ASYNC_CALLOUT_ACTIVE; } else { if (filp->f_flags & O_NONBLOCK) { if (portp->flags & ASYNC_CALLOUT_ACTIVE) return(-EBUSY); } else { if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0) return(rc); } portp->flags |= ASYNC_NORMAL_ACTIVE; } if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == STL_DRVTYPSERIAL) *tty->termios = portp->normaltermios; else *tty->termios = portp->callouttermios; stli_setport(portp); } portp->session = current->session; portp->pgrp = current->pgrp; return(0);}/*****************************************************************************/static void stli_close(struct tty_struct *tty, struct file *filp){ stlibrd_t *brdp; stliport_t *portp; unsigned long flags;#if DEBUG printk("stli_close(tty=%x,filp=%x)\n", (int) tty, (int) filp);#endif portp = tty->driver_data; if (portp == (stliport_t *) NULL) return; save_flags(flags); cli(); if (tty_hung_up_p(filp)) { MOD_DEC_USE_COUNT; restore_flags(flags); return; } if ((tty->count == 1) && (portp->refcount != 1)) portp->refcount = 1; if (portp->refcount-- > 1) { MOD_DEC_USE_COUNT; restore_flags(flags); return; } portp->flags |= ASYNC_CLOSING; if (portp->flags & ASYNC_NORMAL_ACTIVE) portp->normaltermios = *tty->termios; if (portp->flags & ASYNC_CALLOUT_ACTIVE) portp->callouttermios = *tty->termios;/* * May want to wait for data to drain before closing. The BUSY flag * keeps track of whether we are still transmitting or not. It is * updated by messages from the slave - indicating when all chars * really have drained. */ if (tty == stli_txcooktty) stli_flushchars(tty); tty->closing = 1; if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, portp->closing_wait); portp->flags &= ~ASYNC_INITIALIZED; brdp = stli_brds[portp->brdnr]; stli_rawclose(brdp, portp, 0, 0); if (tty->termios->c_cflag & HUPCL) { stli_mkasysigs(&portp->asig, 0, 0); if (test_bit(ST_CMDING, &portp->state)) set_bit(ST_DOSIGS, &portp->state); else stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } clear_bit(ST_TXBUSY, &portp->state); clear_bit(ST_RXSTOP, &portp->state); set_bit(TTY_IO_ERROR, &tty->flags); if (tty->ldisc.flush_buffer) (tty->ldisc.flush_buffer)(tty); set_bit(ST_DOFLUSHRX, &portp->state); stli_flushbuffer(tty); tty->closing = 0; portp->tty = (struct tty_struct *) NULL; if (portp->openwaitcnt) { if (portp->close_delay) stli_delay(portp->close_delay); wake_up_interruptible(&portp->open_wait); } portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&portp->close_wait); MOD_DEC_USE_COUNT; restore_flags(flags);}/*****************************************************************************//* * Carry out first open operations on a port. This involves a number of * commands to be sent to the slave. We need to open the port, set the * notification events, set the initial port settings, get and set the * initial signal values. We sleep and wait in between each one. But * this still all happens pretty quickly. */static int stli_initopen(stlibrd_t *brdp, stliport_t *portp){ struct tty_struct *tty; asynotify_t nt; asyport_t aport; int rc;#if DEBUG printk("stli_initopen(brdp=%x,portp=%x)\n", (int) brdp, (int) portp);#endif if ((rc = stli_rawopen(brdp, portp, 0, 1)) < 0) return(rc); memset(&nt, 0, sizeof(asynotify_t)); nt.data = (DT_TXLOW | DT_TXEMPTY | DT_RXBUSY | DT_RXBREAK); nt.signal = SG_DCD; if ((rc = stli_cmdwait(brdp, portp, A_SETNOTIFY, &nt, sizeof(asynotify_t), 0)) < 0) return(rc); tty = portp->tty; if (tty == (struct tty_struct *) NULL) return(-ENODEV); stli_mkasyport(portp, &aport, tty->termios); if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)) < 0) return(rc); set_bit(ST_GETSIGS, &portp->state); if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0) return(rc); if (test_and_clear_bit(ST_GETSIGS, &portp->state)) portp->sigs = stli_mktiocm(portp->asig.sigvalue); stli_mkasysigs(&portp->asig, 1, 1); if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0)) < 0) return(rc); return(0);}/*****************************************************************************//* * Send an open message to the slave. This will sleep waiting for the * acknowledgement, so must have user context. We need to co-ordinate * with close events here, since we don't want open and close events * to overlap. */static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait){ volatile cdkhdr_t *hdrp; volatile cdkctrl_t *cp; volatile unsigned char *bits; unsigned long flags; int rc;#if DEBUG printk("stli_rawopen(brdp=%x,portp=%x,arg=%x,wait=%d)\n", (int) brdp, (int) portp, (int) arg, wait);#endif/* * Send a message to the slave to open this port. */ save_flags(flags); cli();/* * Slave is already closing this port. This can happen if a hangup * occurs on this port. So we must wait until it is complete. The * order of opens and closes may not be preserved across shared * memory, so we must wait until it is complete. */ while (test_bit(ST_CLOSING, &portp->state)) { if (signal_pending(current)) { restore_flags(flags); return(-ERESTARTSYS); } interruptible_sleep_on(&portp->raw_wait); }/* * Everything is ready now, so write the open message into shared * memory. Once the message is in set the service bits to say that * this port wants service. */ EBRDENABLE(brdp); cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl; cp->openarg = arg; cp->open = 1; hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx; *bits |= portp->portbit; EBRDDISABLE(brdp); if (wait == 0) { restore_flags(flags); return(0); }/* * Slave is in action, so now we must wait for the open acknowledgment * to come back. */ rc = 0; set_bit(ST_OPENING, &portp->state); while (test_bit(ST_OPENING, &portp->state)) { if (signal_pending(current)) { rc = -ERESTARTSYS; break; } interruptible_sleep_on(&portp->raw_wait); } restore_flags(flags); if ((rc == 0) && (portp->rc != 0)) rc = -EIO; return(rc);}/*****************************************************************************//* * Send a close message to the slave. Normally this will sleep waiting * for the acknowledgement, but if wait parameter is 0 it will not. If * wait is true then must have user context (to sleep). */static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait){ volatile cdkhdr_t *hdrp; volatile cdkctrl_t *cp; volatile unsigned char *bits; unsigned long flags; int rc;#if DEBUG printk("stli_rawclose(brdp=%x,portp=%x,arg=%x,wait=%d)\n", (int) brdp, (int) portp, (int) arg, wait);#endif save_flags(flags); cli();/* * Slave is already closing this port. This can happen if a hangup * occurs on this port. */ if (wait) { while (test_bit(ST_CLOSING, &portp->state)) { if (signal_pending(current)) { restore_flags(flags); return(-ERESTARTSYS); } interruptible_sleep_on(&portp->raw_wait); } }/* * Write the close command into shared memory. */ EBRDENABLE(brdp); cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl; cp->closearg = arg; cp->close = 1; hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -