📄 isicom.c
字号:
return; save_flags(flags); cli(); isicom_config_port(port); restore_flags(flags); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; isicom_start(tty); } }/* throttle et all */static void isicom_throttle(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; struct isi_board * card = port->card; unsigned long flags; if (isicom_paranoia_check(port, tty->device, "isicom_throttle")) return; /* tell the card that this port cannot handle any more data for now */ save_flags(flags); cli(); card->port_status &= ~(1 << port->channel); outw(card->port_status, card->base + 0x02); restore_flags(flags);}/* unthrottle et all */static void isicom_unthrottle(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; struct isi_board * card = port->card; unsigned long flags; if (isicom_paranoia_check(port, tty->device, "isicom_unthrottle")) return; /* tell the card that this port is ready to accept more data */ save_flags(flags); cli(); card->port_status |= (1 << port->channel); outw(card->port_status, card->base + 0x02); restore_flags(flags);}/* stop et all */static void isicom_stop(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; if (isicom_paranoia_check(port, tty->device, "isicom_stop")) return; /* this tells the transmitter not to consider this port for data output to the card. */ port->status &= ~ISI_TXOK;}/* start et all */static void isicom_start(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; if (isicom_paranoia_check(port, tty->device, "isicom_start")) return; /* this tells the transmitter to consider this port for data output to the card. */ port->status |= ISI_TXOK;}/* hangup et all */static void do_isicom_hangup(void * data){ struct isi_port * port = (struct isi_port *) data; struct tty_struct * tty; tty = port->tty; if (tty) tty_hangup(tty); /* FIXME: module removal race here - AKPM */ MOD_DEC_USE_COUNT;}static void isicom_hangup(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; if (isicom_paranoia_check(port, tty->device, "isicom_hangup")) return; isicom_shutdown_port(port); port->count = 0; port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); port->tty = 0; wake_up_interruptible(&port->open_wait);}/* flush_buffer et all */static void isicom_flush_buffer(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; unsigned long flags; if (isicom_paranoia_check(port, tty->device, "isicom_flush_buffer")) return; save_flags(flags); cli(); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; 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 int register_ioregion(void){ int count, done=0; for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { if (check_region(isi_card[count].base,16)) { printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x is busy. Card%d will be disabled.\n", isi_card[count].base,isi_card[count].base+15,count+1); isi_card[count].base=0; } else { request_region(isi_card[count].base,16,ISICOM_NAME);#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x requested for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1);#endif done++; } } } return done;}static void unregister_ioregion(void){ int count; for (count=0; count < BOARD_COUNT; count++ ) if (isi_card[count].base) { release_region(isi_card[count].base,16);#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x released for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1);#endif }}static int register_drivers(void){ int error; /* tty driver structure initialization */ memset(&isicom_normal, 0, sizeof(struct tty_driver)); isicom_normal.magic = TTY_DRIVER_MAGIC; isicom_normal.name = "ttyM"; isicom_normal.major = ISICOM_NMAJOR; isicom_normal.minor_start = 0; isicom_normal.num = PORT_COUNT; isicom_normal.type = TTY_DRIVER_TYPE_SERIAL; isicom_normal.subtype = SERIAL_TYPE_NORMAL; isicom_normal.init_termios = tty_std_termios; isicom_normal.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |CLOCAL; isicom_normal.flags = TTY_DRIVER_REAL_RAW; isicom_normal.refcount = &isicom_refcount; isicom_normal.table = isicom_table; isicom_normal.termios = isicom_termios; isicom_normal.termios_locked = isicom_termios_locked; isicom_normal.open = isicom_open; isicom_normal.close = isicom_close; isicom_normal.write = isicom_write; isicom_normal.put_char = isicom_put_char; isicom_normal.flush_chars = isicom_flush_chars; isicom_normal.write_room = isicom_write_room; isicom_normal.chars_in_buffer = isicom_chars_in_buffer; isicom_normal.ioctl = isicom_ioctl; isicom_normal.set_termios = isicom_set_termios; isicom_normal.throttle = isicom_throttle; isicom_normal.unthrottle = isicom_unthrottle; isicom_normal.stop = isicom_stop; isicom_normal.start = isicom_start; isicom_normal.hangup = isicom_hangup; isicom_normal.flush_buffer = isicom_flush_buffer; /* callout device */ isicom_callout = isicom_normal; isicom_callout.name = "cum"; isicom_callout.major = ISICOM_CMAJOR; isicom_callout.subtype = SERIAL_TYPE_CALLOUT; if ((error=tty_register_driver(&isicom_normal))!=0) { printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n", error); return error; } if ((error=tty_register_driver(&isicom_callout))!=0) { tty_unregister_driver(&isicom_normal); printk(KERN_DEBUG "ISICOM: Couldn't register the callout driver, error=%d\n", error); return error; } return 0;}static void unregister_drivers(void){ int error; if ((error=tty_unregister_driver(&isicom_callout))!=0) printk(KERN_DEBUG "ISICOM: couldn't unregister callout driver error=%d.\n",error); if (tty_unregister_driver(&isicom_normal)) printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error);}static int register_isr(void){ int count, done=0, card; int flag; unsigned char request; for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { /* * verify if the required irq has already been requested for * another ISI Card, if so we already have it, else request it */ request = YES; for(card = 0; card < count; card++) if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { request = NO; if ((isi_card[count].isa == NO) && (isi_card[card].isa == NO)) break; /* * ISA cards cannot share interrupts with other * PCI or ISA devices hence disable this card. */ release_region(isi_card[count].base,16); isi_card[count].base = 0; break; } flag=0; if(isi_card[count].isa == NO) flag |= SA_SHIRQ; if (request == YES) { if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT|flag, ISICOM_NAME, NULL)) { printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", isi_card[count].irq, count+1); release_region(isi_card[count].base,16); isi_card[count].base=0; } else { printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", count+1, isi_card[count].base, isi_card[count].irq); irq_to_board[isi_card[count].irq]=&isi_card[count]; done++; } } } } return done;}static void unregister_isr(void){ int count, card; unsigned char freeirq; for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { freeirq = YES; for(card = 0; card < count; card++) if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) { freeirq = NO; break; } if (freeirq == YES) { free_irq(isi_card[count].irq, NULL);#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1);#endif } } }}static int isicom_init(void){ int card, channel, base; struct isi_port * port; unsigned long page; if (!tmp_buf) { page = get_free_page(GFP_KERNEL); if (!page) {#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n");#else printk(KERN_ERR "ISICOM: Not enough memory...\n");#endif return 0; } tmp_buf = (unsigned char *) page; } if (!register_ioregion()) { printk(KERN_ERR "ISICOM: All required I/O space found busy.\n"); free_page((unsigned long)tmp_buf); return 0; } if (register_drivers()) { unregister_ioregion(); free_page((unsigned long)tmp_buf); return 0; } if (!register_isr()) { unregister_drivers(); /* ioports already uregistered in register_isr */ free_page((unsigned long)tmp_buf); return 0; } /* initialize bottom half */ init_bh(ISICOM_BH, do_isicom_bh); memset(isi_ports, 0, sizeof(isi_ports)); for (card = 0; card < BOARD_COUNT; card++) { port = &isi_ports[card * 16]; isi_card[card].ports = port; base = isi_card[card].base; for (channel = 0; channel < 16; channel++, port++) { port->magic = ISICOM_MAGIC; port->card = &isi_card[card]; port->channel = channel; port->normal_termios = isicom_normal.init_termios; port->callout_termios = isicom_callout.init_termios; port->close_delay = 50 * HZ/100; port->closing_wait = 3000 * HZ/100; port->hangup_tq.routine = do_isicom_hangup; port->hangup_tq.data = port; port->bh_tqueue.routine = isicom_bottomhalf; port->bh_tqueue.data = port; port->status = 0; init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); /* . . . */ } } return 1; }/* * Insmod can set static symbols so keep these static */ static int io[4];static int irq[4];MODULE_AUTHOR("MultiTech");MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");MODULE_PARM(io, "1-4i");MODULE_PARM_DESC(io, "I/O ports for the cards");MODULE_PARM(irq, "1-4i");MODULE_PARM_DESC(irq, "Interrupts for the cards");int init_module(void){ struct pci_dev *dev = NULL; int retval, card, idx, count; unsigned char pciirq; unsigned int ioaddr; card = 0; for(idx=0; idx < BOARD_COUNT; idx++) { if (io[idx]) { isi_card[idx].base=io[idx]; isi_card[idx].irq=irq[idx]; isi_card[idx].isa=YES; card++; } else { isi_card[idx].base = 0; isi_card[idx].irq = 0; } } for (idx=0 ;idx < card; idx++) { if (!((isi_card[idx].irq==2)||(isi_card[idx].irq==3)|| (isi_card[idx].irq==4)||(isi_card[idx].irq==5)|| (isi_card[idx].irq==7)||(isi_card[idx].irq==10)|| (isi_card[idx].irq==11)||(isi_card[idx].irq==12)|| (isi_card[idx].irq==15))) { if (isi_card[idx].base) { printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n", isi_card[idx].irq, idx+1); isi_card[idx].base=0; card--; } } } if (pci_present() && (card < BOARD_COUNT)) { for (idx=0; idx < DEVID_COUNT; idx++) { dev = NULL; for (;;){ if (!(dev = pci_find_device(VENDOR_ID, device_id[idx], dev))) break; if (card >= BOARD_COUNT) break; if (pci_enable_device(dev)) break; /* found a PCI ISI card! */ ioaddr = pci_resource_start (dev, 3); /* i.e at offset 0x1c in the * PCI configuration register * space. */ pciirq = dev->irq; printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]); /* * allot the first empty slot in the array */ for (count=0; count < BOARD_COUNT; count++) { if (isi_card[count].base == 0) { isi_card[count].base = ioaddr; isi_card[count].irq = pciirq; isi_card[count].isa = NO; card++; break; } } } if (card >= BOARD_COUNT) break; } } if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) { printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n"); return -EIO; } retval=misc_register(&isiloader_device); if (retval<0) { printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n"); return -EIO; } if (!isicom_init()) { if (misc_deregister(&isiloader_device)) printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n"); return -EIO; } init_timer(&tx); tx.expires = jiffies + 1; tx.data = 0; tx.function = isicom_tx; re_schedule = 1; add_timer(&tx); return 0;}void cleanup_module(void){ re_schedule = 0; current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ); remove_bh(ISICOM_BH); #ifdef ISICOM_DEBUG printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count);#endif #ifdef ISICOM_DEBUG printk("ISICOM: uregistering isr ...\n");#endif unregister_isr();#ifdef ISICOM_DEBUG printk("ISICOM: unregistering drivers ...\n");#endif unregister_drivers(); #ifdef ISICOM_DEBUG printk("ISICOM: unregistering ioregion ...\n");#endif unregister_ioregion(); #ifdef ISICOM_DEBUG printk("ISICOM: freeing tmp_buf ...\n");#endif free_page((unsigned long)tmp_buf); #ifdef ISICOM_DEBUG printk("ISICOM: unregistering firmware loader ...\n"); #endif if (misc_deregister(&isiloader_device)) printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -