📄 istallion.c
字号:
*/#define ECP_PCIIREG 0#define ECP_PCICONFR 1#define ECP_PCISTOP 0x01/* * Hardware configuration info for ONboard and Brumby boards. These * defines apply to the directly accessible io ports of these boards. */#define ONB_IOSIZE 16#define ONB_MEMSIZE (64 * 1024)#define ONB_ATPAGESIZE (64 * 1024)#define ONB_MCPAGESIZE (64 * 1024)#define ONB_EIMEMSIZE (128 * 1024)#define ONB_EIPAGESIZE (64 * 1024)/* * Important defines for the ISA class of ONboard board. */#define ONB_ATIREG 0#define ONB_ATMEMAR 1#define ONB_ATCONFR 2#define ONB_ATSTOP 0x4#define ONB_ATENABLE 0x01#define ONB_ATDISABLE 0x00#define ONB_ATADDRMASK 0xff0000#define ONB_ATADDRSHFT 16#define ONB_MEMENABLO 0#define ONB_MEMENABHI 0x02/* * Important defines for the EISA class of ONboard board. */#define ONB_EIIREG 0#define ONB_EIMEMARL 1#define ONB_EICONFR 2#define ONB_EIMEMARH 3#define ONB_EIENABLE 0x1#define ONB_EIDISABLE 0x0#define ONB_EISTOP 0x4#define ONB_EIEDGE 0x00#define ONB_EILEVEL 0x80#define ONB_EIADDRMASKL 0x00ff0000#define ONB_EIADDRSHFTL 16#define ONB_EIADDRMASKH 0xff000000#define ONB_EIADDRSHFTH 24#define ONB_EIBRDENAB 0xc84#define ONB_EISAID 0x1/* * Important defines for the Brumby boards. They are pretty simple, * there is not much that is programmably configurable. */#define BBY_IOSIZE 16#define BBY_MEMSIZE (64 * 1024)#define BBY_PAGESIZE (16 * 1024)#define BBY_ATIREG 0#define BBY_ATCONFR 1#define BBY_ATSTOP 0x4/* * Important defines for the Stallion boards. They are pretty simple, * there is not much that is programmably configurable. */#define STAL_IOSIZE 16#define STAL_MEMSIZE (64 * 1024)#define STAL_PAGESIZE (64 * 1024)/* * Define the set of status register values for EasyConnection panels. * The signature will return with the status value for each panel. From * this we can determine what is attached to the board - before we have * actually down loaded any code to it. */#define ECH_PNLSTATUS 2#define ECH_PNL16PORT 0x20#define ECH_PNLIDMASK 0x07#define ECH_PNLXPID 0x40#define ECH_PNLINTRPEND 0x80/* * Define some macros to do things to the board. Even those these boards * are somewhat related there is often significantly different ways of * doing some operation on it (like enable, paging, reset, etc). So each * board class has a set of functions which do the commonly required * operations. The macros below basically just call these functions, * generally checking for a NULL function - which means that the board * needs nothing done to it to achieve this operation! */#define EBRDINIT(brdp) \ if (brdp->init != NULL) \ (* brdp->init)(brdp)#define EBRDENABLE(brdp) \ if (brdp->enable != NULL) \ (* brdp->enable)(brdp);#define EBRDDISABLE(brdp) \ if (brdp->disable != NULL) \ (* brdp->disable)(brdp);#define EBRDINTR(brdp) \ if (brdp->intr != NULL) \ (* brdp->intr)(brdp);#define EBRDRESET(brdp) \ if (brdp->reset != NULL) \ (* brdp->reset)(brdp);#define EBRDGETMEMPTR(brdp,offset) \ (* brdp->getmemptr)(brdp, offset, __LINE__)/* * Define the maximal baud rate, and the default baud base for ports. */#define STL_MAXBAUD 460800#define STL_BAUDBASE 115200#define STL_CLOSEDELAY (5 * HZ / 10)/*****************************************************************************//* * Define macros to extract a brd or port number from a minor number. */#define MINOR2BRD(min) (((min) & 0xc0) >> 6)#define MINOR2PORT(min) ((min) & 0x3f)/*****************************************************************************//* * Prototype all functions in this driver! */static int stli_parsebrd(struct stlconf *confp, char **argp);static int stli_open(struct tty_struct *tty, struct file *filp);static void stli_close(struct tty_struct *tty, struct file *filp);static int stli_write(struct tty_struct *tty, const unsigned char *buf, int count);static void stli_putchar(struct tty_struct *tty, unsigned char ch);static void stli_flushchars(struct tty_struct *tty);static int stli_writeroom(struct tty_struct *tty);static int stli_charsinbuffer(struct tty_struct *tty);static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);static void stli_settermios(struct tty_struct *tty, struct ktermios *old);static void stli_throttle(struct tty_struct *tty);static void stli_unthrottle(struct tty_struct *tty);static void stli_stop(struct tty_struct *tty);static void stli_start(struct tty_struct *tty);static void stli_flushbuffer(struct tty_struct *tty);static void stli_breakctl(struct tty_struct *tty, int state);static void stli_waituntilsent(struct tty_struct *tty, int timeout);static void stli_sendxchar(struct tty_struct *tty, char ch);static void stli_hangup(struct tty_struct *tty);static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos);static int stli_brdinit(struct stlibrd *brdp);static int stli_startbrd(struct stlibrd *brdp);static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp);static void stli_poll(unsigned long arg);static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp);static int stli_initopen(struct stlibrd *brdp, struct stliport *portp);static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);static void stli_dohangup(struct work_struct *);static int stli_setport(struct stliport *portp);static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp);static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp);static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts);static long stli_mktiocm(unsigned long sigvalue);static void stli_read(struct stlibrd *brdp, struct stliport *portp);static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp);static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp);static int stli_getbrdstats(combrd_t __user *bp);static int stli_getportstats(struct stliport *portp, comstats_t __user *cp);static int stli_portcmdstats(struct stliport *portp);static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp);static int stli_getportstruct(struct stliport __user *arg);static int stli_getbrdstruct(struct stlibrd __user *arg);static struct stlibrd *stli_allocbrd(void);static void stli_ecpinit(struct stlibrd *brdp);static void stli_ecpenable(struct stlibrd *brdp);static void stli_ecpdisable(struct stlibrd *brdp);static void __iomem *stli_ecpgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);static void stli_ecpreset(struct stlibrd *brdp);static void stli_ecpintr(struct stlibrd *brdp);static void stli_ecpeiinit(struct stlibrd *brdp);static void stli_ecpeienable(struct stlibrd *brdp);static void stli_ecpeidisable(struct stlibrd *brdp);static void __iomem *stli_ecpeigetmemptr(struct stlibrd *brdp, unsigned long offset, int line);static void stli_ecpeireset(struct stlibrd *brdp);static void stli_ecpmcenable(struct stlibrd *brdp);static void stli_ecpmcdisable(struct stlibrd *brdp);static void __iomem *stli_ecpmcgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);static void stli_ecpmcreset(struct stlibrd *brdp);static void stli_ecppciinit(struct stlibrd *brdp);static void __iomem *stli_ecppcigetmemptr(struct stlibrd *brdp, unsigned long offset, int line);static void stli_ecppcireset(struct stlibrd *brdp);static void stli_onbinit(struct stlibrd *brdp);static void stli_onbenable(struct stlibrd *brdp);static void stli_onbdisable(struct stlibrd *brdp);static void __iomem *stli_onbgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);static void stli_onbreset(struct stlibrd *brdp);static void stli_onbeinit(struct stlibrd *brdp);static void stli_onbeenable(struct stlibrd *brdp);static void stli_onbedisable(struct stlibrd *brdp);static void __iomem *stli_onbegetmemptr(struct stlibrd *brdp, unsigned long offset, int line);static void stli_onbereset(struct stlibrd *brdp);static void stli_bbyinit(struct stlibrd *brdp);static void __iomem *stli_bbygetmemptr(struct stlibrd *brdp, unsigned long offset, int line);static void stli_bbyreset(struct stlibrd *brdp);static void stli_stalinit(struct stlibrd *brdp);static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);static void stli_stalreset(struct stlibrd *brdp);static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, unsigned int portnr);static int stli_initecp(struct stlibrd *brdp);static int stli_initonb(struct stlibrd *brdp);#if STLI_EISAPROBE != 0static int stli_eisamemprobe(struct stlibrd *brdp);#endifstatic int stli_initports(struct stlibrd *brdp);/*****************************************************************************//* * Define the driver info for a user level shared memory device. This * device will work sort of like the /dev/kmem device - except that it * will give access to the shared memory on the Stallion intelligent * board. This is also a very useful debugging tool. */static const struct file_operations stli_fsiomem = { .owner = THIS_MODULE, .read = stli_memread, .write = stli_memwrite, .ioctl = stli_memioctl,};/*****************************************************************************//* * Define a timer_list entry for our poll routine. The slave board * is polled every so often to see if anything needs doing. This is * much cheaper on host cpu than using interrupts. It turns out to * not increase character latency by much either... */static DEFINE_TIMER(stli_timerlist, stli_poll, 0, 0);static int stli_timeron;/* * Define the calculation for the timeout routine. */#define STLI_TIMEOUT (jiffies + 1)/*****************************************************************************/static struct class *istallion_class;static void stli_cleanup_ports(struct stlibrd *brdp){ struct stliport *portp; unsigned int j; for (j = 0; j < STL_MAXPORTS; j++) { portp = brdp->ports[j]; if (portp != NULL) { if (portp->tty != NULL) tty_hangup(portp->tty); kfree(portp); } }}/*****************************************************************************//* * Parse the supplied argument string, into the board conf struct. */static int stli_parsebrd(struct stlconf *confp, char **argp){ unsigned int i; char *sp; if (argp[0] == NULL || *argp[0] == 0) return 0; for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++) *sp = tolower(*sp); for (i = 0; i < ARRAY_SIZE(stli_brdstr); i++) { if (strcmp(stli_brdstr[i].name, argp[0]) == 0) break; } if (i == ARRAY_SIZE(stli_brdstr)) { printk("STALLION: unknown board name, %s?\n", argp[0]); return 0; } confp->brdtype = stli_brdstr[i].type; if (argp[1] != NULL && *argp[1] != 0) confp->ioaddr1 = simple_strtoul(argp[1], NULL, 0); if (argp[2] != NULL && *argp[2] != 0) confp->memaddr = simple_strtoul(argp[2], NULL, 0); return(1);}/*****************************************************************************/static int stli_open(struct tty_struct *tty, struct file *filp){ struct stlibrd *brdp; struct stliport *portp; unsigned int minordev, brdnr, portnr; int rc; minordev = tty->index; brdnr = MINOR2BRD(minordev); if (brdnr >= stli_nrbrds) return -ENODEV; brdp = stli_brds[brdnr]; if (brdp == NULL) return -ENODEV; if ((brdp->state & BST_STARTED) == 0) return -ENODEV; portnr = MINOR2PORT(minordev); if (portnr > brdp->nrports) return -ENODEV; portp = brdp->ports[portnr]; if (portp == NULL) return -ENODEV; if (portp->devnr < 1) return -ENODEV;/* * 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++; wait_event_interruptible(portp->raw_wait, !test_bit(ST_INITIALIZING, &portp->state)); if (signal_pending(current)) return -ERESTARTSYS; 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 (!(filp->f_flags & O_NONBLOCK)) { if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0) return rc; } portp->flags |= ASYNC_NORMAL_ACTIVE; return 0;}/*****************************************************************************/static void stli_close(struct tty_struct *tty, struct file *filp){ struct stlibrd *brdp; struct stliport *portp; unsigned long flags; portp = tty->driver_data; if (portp == NULL) return; spin_lock_irqsave(&stli_lock, flags); if (tty_hung_up_p(filp)) { spin_unlock_irqrestore(&stli_lock, flags); return; } if ((tty->count == 1) && (portp->refcount != 1)) portp->refcount = 1; if (portp->refcount-- > 1) { spin_unlock_irqrestore(&stli_lock, flags); return; } portp->flags |= ASYNC_CLOSING;/* * 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; spin_unlock_irqrestore(&stli_lock, flags); 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))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -