📄 pcxx.c
字号:
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); }#endif if(info->blocked_open) { if(info->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE| ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; restore_flags(flags); }}void pcxe_hangup(struct tty_struct *tty){ struct channel *ch; if ((ch=chan(tty))!=NULL) { unsigned long flags; save_flags(flags); cli(); shutdown(ch); ch->event = 0; ch->count = 0; ch->tty = NULL; ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); wake_up_interruptible(&ch->open_wait); restore_flags(flags); }}static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count){ struct channel *ch; volatile struct board_chan *bc; int total, remain, size, stlen; unsigned int head, tail; unsigned long flags; /* printk("Entering pcxe_write()\n"); */ if ((ch=chan(tty))==NULL) return 0; bc = ch->brdchan; size = ch->txbufsize; if (from_user) { save_flags(flags); cli(); globalwinon(ch); head = bc->tin & (size - 1); /* It seems to be necessary to make sure that the value is stable here somehow This is a rather odd pice of code here. */ do { tail = bc->tout; } while (tail != bc->tout); tail &= (size - 1); stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1); count = MIN(stlen, count); if (count) { if (verify_area(VERIFY_READ, (char*)buf, count)) count=0; else copy_from_user(ch->tmp_buf, buf, count); } buf = ch->tmp_buf; memoff(ch); restore_flags(flags); } /* * All data is now local */ total = 0; save_flags(flags); cli(); globalwinon(ch); head = bc->tin & (size - 1); tail = bc->tout; if (tail != bc->tout) tail = bc->tout; tail &= (size - 1); if (head >= tail) { remain = size - (head - tail) - 1; stlen = size - head; } else { remain = tail - head - 1; stlen = remain; } count = MIN(remain, count); txwinon(ch); while (count > 0) { stlen = MIN(count, stlen); memcpy(ch->txptr + head, buf, stlen); buf += stlen; count -= stlen; total += stlen; head += stlen; if (head >= size) { head = 0; stlen = tail; } } ch->statusflags |= TXBUSY; globalwinon(ch); bc->tin = head; if ((ch->statusflags & LOWWAIT) == 0) { ch->statusflags |= LOWWAIT; bc->ilow = 1; } memoff(ch); restore_flags(flags); return(total);}static void pcxe_put_char(struct tty_struct *tty, unsigned char c){ pcxe_write(tty, 0, &c, 1); return;}static int pcxe_write_room(struct tty_struct *tty){ struct channel *ch; int remain; remain = 0; if ((ch=chan(tty))!=NULL) { volatile struct board_chan *bc; unsigned int head, tail; unsigned long flags; save_flags(flags); cli(); globalwinon(ch); bc = ch->brdchan; head = bc->tin & (ch->txbufsize - 1); tail = bc->tout; if (tail != bc->tout) tail = bc->tout; tail &= (ch->txbufsize - 1); if((remain = tail - head - 1) < 0 ) remain += ch->txbufsize; if (remain && (ch->statusflags & LOWWAIT) == 0) { ch->statusflags |= LOWWAIT; bc->ilow = 1; } memoff(ch); restore_flags(flags); } return remain;}static int pcxe_chars_in_buffer(struct tty_struct *tty){ int chars; unsigned int ctail, head, tail; int remain; unsigned long flags; struct channel *ch; volatile struct board_chan *bc; if ((ch=chan(tty))==NULL) return(0); save_flags(flags); cli(); globalwinon(ch); bc = ch->brdchan; tail = bc->tout; head = bc->tin; ctail = ch->mailbox->cout; if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0) chars = 0; else { head = bc->tin & (ch->txbufsize - 1); tail &= (ch->txbufsize - 1); if((remain = tail - head - 1) < 0 ) remain += ch->txbufsize; chars = (int)(ch->txbufsize - remain); /* * Make it possible to wakeup anything waiting for output * in tty_ioctl.c, etc. */ if(!(ch->statusflags & EMPTYWAIT)) setup_empty_event(tty,ch); } memoff(ch); restore_flags(flags); return(chars);}static void pcxe_flush_buffer(struct tty_struct *tty){ unsigned int tail; volatile struct board_chan *bc; struct channel *ch; unsigned long flags; if ((ch=chan(tty))==NULL) return; save_flags(flags); cli(); globalwinon(ch); bc = ch->brdchan; tail = bc->tout; fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0); memoff(ch); restore_flags(flags); wake_up_interruptible(&tty->write_wait); if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty);}static void pcxe_flush_chars(struct tty_struct *tty){ struct channel * ch; if ((ch=chan(tty))!=NULL) { unsigned long flags; save_flags(flags); cli(); if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT)) setup_empty_event(tty,ch); restore_flags(flags); }}#ifndef MODULE/* * Driver setup function when linked into the kernel to optionally parse multible * "digi="-lines and initialize the driver at boot time. No probing. */__initfunc(void pcxx_setup(char *str, int *ints)){ struct board_info board; int i, j, last; char *temp, *t2; unsigned len; numcards=0; memset(&board, 0, sizeof(board)); for(last=0,i=1;i<=ints[0];i++) switch(i) { case 1: board.status = ints[i]; last = i; break; case 2: board.type = ints[i]; last = i; break; case 3: board.altpin = ints[i]; last = i; break; case 4: board.numports = ints[i]; last = i; break; case 5: board.port = ints[i]; last = i; break; case 6: board.membase = ints[i]; last = i; break; default: printk("PC/Xx: Too many integer parms\n"); return; } while (str && *str) { /* find the next comma or terminator */ temp = str; while (*temp && (*temp != ',')) temp++; if (!*temp) temp = NULL; else *temp++ = 0; i = last + 1; switch(i) { case 1: len = strlen(str); if (strncmp("Disable", str, len) == 0) board.status = 0; else if (strncmp("Enable", str, len) == 0) board.status = 1; else { printk("PC/Xx: Invalid status %s\n", str); return; } last = i; break; case 2: for(j=0;j<PCXX_NUM_TYPES;j++) if (strcmp(board_desc[j], str) == 0) break; if (i<PCXX_NUM_TYPES) board.type = j; else { printk("PC/Xx: Invalid board name: %s\n", str); return; } last = i; break; case 3: len = strlen(str); if (strncmp("Disable", str, len) == 0) board.altpin = 0; else if (strncmp("Enable", str, len) == 0) board.altpin = 1; else { printk("PC/Xx: Invalid altpin %s\n", str); return; } last = i; break; case 4: t2 = str; while (isdigit(*t2)) t2++; if (*t2) { printk("PC/Xx: Invalid port count %s\n", str); return; } board.numports = simple_strtoul(str, NULL, 0); last = i; break; case 5: t2 = str; while (isxdigit(*t2)) t2++; if (*t2) { printk("PC/Xx: Invalid io port address %s\n", str); return; } board.port = simple_strtoul(str, NULL, 16); last = i; break; case 6: t2 = str; while (isxdigit(*t2)) t2++; if (*t2) { printk("PC/Xx: Invalid memory base %s\n", str); return; } board.membase = simple_strtoul(str, NULL, 16); last = i; break; default: printk("PC/Xx: Too many string parms\n"); return; } str = temp; } if (last < 6) { printk("PC/Xx: Insufficient parms specified\n"); return; } /* I should REALLY validate the stuff here */ memcpy(&boards[numcards],&board, sizeof(board)); printk("PC/Xx: Added board %i, %s %s %i ports at 0x%4.4X base 0x%6.6X\n", numcards, board_desc[board.type], board_mem[board.type], board.numports, board.port, (unsigned int) board.membase); /* keep track of my initial minor number */ if (numcards) boards[numcards].first_minor = boards[numcards-1].first_minor + boards[numcards-1].numports; else boards[numcards].first_minor = 0; /* yeha! string parameter was successful! */ numcards++;}#endif/* * function to initialize the driver with the given parameters, which are either * the default values from this file or the parameters given at boot. */__initfunc(int pcxe_init(void)){ ulong memory_seg=0, memory_size=0; int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L; unchar *fepos, *memaddr, *bios, v; volatile struct global_data *gd; volatile struct board_chan *bc; struct board_info *bd; struct channel *ch; printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION);#ifdef MODULE for (i = 0; i < 4; i++) { if (io[i]) { numcards = 0; break; } } if (numcards == 0) { int first_minor = 0; for (i = 0; i < 4; i++) { if (io[i] == 0) { boards[i].port = 0; boards[i].status = DISABLED; } else { boards[i].port = (ushort)io[i]; boards[i].status = ENABLED; boards[i].first_minor = first_minor; numcards=i+1; } if (membase[i]) boards[i].membase = (ulong)membase[i]; else boards[i].membase = 0xD0000; if (memsize[i]) boards[i].memsize = (ulong)(memsize[i] * 1024); else boards[i].memsize = 0; if (altpin[i]) boards[i].altpin = ON; else boards[i].altpin = OFF; if (numports[i]) boards[i].numports = (ushort)numports[i]; else boards[i].numports = 16; first_minor += boards[i].numports; } }#endif if (numcards <= 0) { printk("PC/Xx: No cards configured, driver not active.\n"); return -EIO; }#if 1 if (debug) for (i = 0; i < numcards; i++) { printk("Card %d:status=%d, port=0x%x, membase=0x%lx, memsize=0x%lx, altpin=%d, numports=%d, first_minor=%d\n", i+1, boards[i].status, boards[i].port, boards[i].membase, boards[i].memsize, boards[i].altpin, boards[i].numports, boards[i].first_minor); }#endif for (i=0;i<numcards;i++) nbdevs += boards[i].numports; if (nbdevs <= 0) { printk("PC/Xx: No devices activated, driver not active.\n"); return -EIO; } /* * this turns out to be more memory efficient, as there are no * unused spaces. */ digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL); if (!digi_channels) panic("Unable to allocate digi_channel struct"); memset(digi_channels, 0, sizeof(struct channel) * nbdevs); pcxe_table = kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL); if (!pcxe_table) panic("Unable to allocate pcxe_table struct"); memset(pcxe_table, 0, sizeof(struct tty_struct *) * nbdevs); pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL); if (!pcxe_termios) panic("Unable to allocate pcxe_termios struct"); memset(pcxe_termios,0,sizeof(struct termios *)*nbdevs); pcxe_termios_locked = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL); if (!pcxe_termios_locked) panic("Unable to allocate pcxe_termios_locked struct"); memset(pcxe_termios_locked,0,sizeof(struct termios *)*nbdevs); init_bh(DIGI_BH,do_pcxe_bh); enable_bh(DIGI_BH); timer_table[DIGI_TIMER].fn = pcxxpoll; timer_table[DIGI_TIMER].expires = 0; memset(&pcxe_driver, 0, sizeof(struct tty_driver)); pcxe_driver.magic = TTY_DRIVER_MAGIC; pcxe_driver.name = "ttyD"; pcxe_driver.major = DIGI_MAJOR; pcxe_driver.minor_start = 0; pcxe_driver.num = nbdevs; pcxe_driver.type = TTY_DRIVER_TYPE_SERIAL; pcxe_driver.subtype = SERIAL_TYPE_NORMAL; pcxe_driver.init_termios = tty_std_termios; pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; pcxe_driver.flags = TTY_DRIVER_REAL_RAW; pcxe_driver.refcount = &pcxe_refcount; pcxe_driver.table = pcxe_table; pcxe_driver.termios = pcxe_termios; pcxe_driver.termios_locked = pcxe_termios_locked; pcxe_driver.open = pcxe_open; pcxe_driver.close = pcxe_close; pcxe_driver.write = pcxe_write; pcxe_driver.put_char = pcxe_put_char; pcxe_driver.flush_chars = pcxe_flush_chars; pcxe_driver.write_room = pcxe_write_room; pcxe_driver.chars_in_buffer = pcxe_chars_in_buffer; pcxe_driver.flush_buffer = pcxe_flush_buffer; pcxe_driver.ioctl = pcxe_ioctl; pcxe_driver.throttle = pcxe_throttle; pcxe_driver.unthrottle = pcxe_unthrottle; pcxe_driver.set_termios = pcxe_set_termios; pcxe_driver.stop = pcxe_stop; pcxe_driver.start = pcxe_start; pcxe_driver.hangup = pcxe_hangup; pcxe_callout = pcxe_driver; pcxe_callout.name = "cud"; pcxe_callout.major = DIGICU_MAJOR; pcxe_callout.subtype = SERIAL_TYPE_CALLOUT; pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; for(crd=0; crd < numcards; crd++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -