isicom.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,938 行 · 第 1/4 页
C
1,938 行
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->name, "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->name, "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->name, "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->name, "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 */}static void isicom_hangup(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) return; isicom_shutdown_port(port); port->count = 0; port->flags &= ~ASYNC_NORMAL_ACTIVE; port->tty = NULL; 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->name, "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); tty_wakeup(tty);}static int register_ioregion(void){ int count, done=0; for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) if (!request_region(isi_card[count].base,16,ISICOM_NAME)) { 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; 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 struct tty_operations isicom_ops = { .open = isicom_open, .close = isicom_close, .write = isicom_write, .put_char = isicom_put_char, .flush_chars = isicom_flush_chars, .write_room = isicom_write_room, .chars_in_buffer = isicom_chars_in_buffer, .ioctl = isicom_ioctl, .set_termios = isicom_set_termios, .throttle = isicom_throttle, .unthrottle = isicom_unthrottle, .stop = isicom_stop, .start = isicom_start, .hangup = isicom_hangup, .flush_buffer = isicom_flush_buffer, .tiocmget = isicom_tiocmget, .tiocmset = isicom_tiocmset,};static int register_drivers(void){ int error; /* tty driver structure initialization */ isicom_normal = alloc_tty_driver(PORT_COUNT); if (!isicom_normal) return -ENOMEM; isicom_normal->owner = THIS_MODULE; isicom_normal->name = "ttyM"; isicom_normal->devfs_name = "isicom/"; isicom_normal->major = ISICOM_NMAJOR; isicom_normal->minor_start = 0; 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; tty_set_operations(isicom_normal, &isicom_ops); if ((error=tty_register_driver(isicom_normal))!=0) { printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n", error); put_tty_driver(isicom_normal); return error; } return 0;}static void unregister_drivers(void){ int error = tty_unregister_driver(isicom_normal); if (error) printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error); put_tty_driver(isicom_normal);}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_zeroed_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; } 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->close_delay = 50 * HZ/100; port->closing_wait = 3000 * HZ/100; INIT_WORK(&port->hangup_tq, do_isicom_hangup, port); INIT_WORK(&port->bh_tqueue, isicom_bottomhalf, 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_LICENSE("GPL");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 (card < BOARD_COUNT) { for (idx=0; idx < DEVID_COUNT; idx++) { dev = NULL; for (;;){ if (!(dev = pci_find_device(VENDOR_ID, isicom_pci_tbl[idx].device, 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", isicom_pci_tbl[idx].device); /* * 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 retval; } 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; msleep(1000);#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 + =
减小字号Ctrl + -
显示快捷键?