pcxx.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,385 行 · 第 1/4 页
C
2,385 行
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); memoff(ch); restore_flags(flags); if (count) if (copy_from_user(ch->tmp_buf, buf, count)) count = 0; buf = ch->tmp_buf; } /* * 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); if(from_user) up(&ch->tmp_buf_sem); 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); tty_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. */void __init 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++;}#endifstatic struct tty_operations pcxe_ops = { .open = pcxe_open, .close = pcxe_close, .write = pcxe_write, .put_char = pcxe_put_char, .flush_chars = pcxe_flush_chars, .write_room = pcxe_write_room, .chars_in_buffer = pcxe_chars_in_buffer, .flush_buffer = pcxe_flush_buffer, .ioctl = pcxe_ioctl, .throttle = pcxe_throttle, .unthrottle = pcxe_unthrottle, .set_termios = pcxe_set_termios, .stop = pcxe_stop, .start = pcxe_start, .hangup = pcxe_hangup, .tiocmget = pcxe_tiocmget, .tiocmset = pcxe_tiocmset,};/* * function to initialize the driver with the given parameters, which are either * the default values from this file or the parameters given at boot. */static int __init pcxe_init(void){ ulong memory_seg=0, memory_size=0; int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L; int ret = -ENOMEM; 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 < MAX_DIGI_BOARDS; i++) { if (io[i]) { numcards = 0; break; } } if (numcards == 0) { int first_minor = 0; for (i = 0; i < MAX_DIGI_BOARDS; 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; boards[i].region = NULL; 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; } pcxe_driver = alloc_tty_driver(nbdevs); if (!pcxe_driver) return -ENOMEM; /* * 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) { printk(KERN_ERR "Unable to allocate digi_channel struct\n"); put_tty_driver(pcxe_driver); return -ENOMEM; } memset(digi_channels, 0, sizeof(struct channel) * nbdevs); init_timer(&pcxx_timer); pcxx_timer.function = pcxxpoll; pcxe_driver->owner = THIS_MODULE; pcxe_driver->name = "ttyD"; pcxe_driver->devfs_name = "pcxe/"; pcxe_driver->major = DIGI_MAJOR; pcxe_driver->minor_start = 0; 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; tty_set_operations(pcxe_driver, &pcxe_ops); for(crd=0; crd < numcards; crd++) { bd = &boards[crd]; outb(FEPRST, bd->port); mdelay(1); for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) { if(i > 100) { printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n", bd->port); bd->status = DISABLED; break; }#ifdef MODULE schedule();#endif mdelay(10); } if(bd->status == DISABLED) continue; v = inb(bd->port); if((v & 0x1) == 0x1) { if((v & 0x30) == 0) { /* PC/Xi 64K card */ memory_seg = 0xf000; memory_size = 0x10000; } if((v & 0x30) == 0x10) { /* PC/Xi 128K card */ memory_seg = 0xe000; memory_size = 0x20000; } if((v & 0x30) == 0x20) { /* PC/Xi 256K card */ memory_seg = 0xc000; memory_size = 0x40000; } if((v & 0x30) == 0x30) { /* PC/Xi 512K card */ memory_seg = 0x8000; memory_size = 0x80000; } bd->type = PCXI; } else { if((v & 0x1) == 0x1) { bd->status = DISABLED; /* PC/Xm unsupported card */ printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port); continue; } else { if(v & 0xC0) { topwin = 0x1f00L; outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2); outb(((ulong)bd->membase>>16) & 0xff, bd->port+3); bd->type = PCXEVE; /* PC/Xe 8K card */ } else { bd->type = PCXE; /* PC/Xe 64K card */ } memory_seg = 0xf000; memory_size = 0x10000; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?