📄 isicom.c
字号:
if (!arg) isicom_send_break(port, HZ/4); return 0; case TCSBRKP: retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); case TIOCSSOFTCAR: if(get_user(arg, (unsigned long *) arg)) return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCMGET: return isicom_get_modem_info(port, (unsigned int*) arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: return isicom_set_modem_info(port, cmd, (unsigned int *) arg); case TIOCGSERIAL: return isicom_get_serial_info(port, (struct serial_struct *) arg); case TIOCSSERIAL: return isicom_set_serial_info(port, (struct serial_struct *) arg); default: return -ENOIOCTLCMD; } return 0;}/* set_termios et all */static void isicom_set_termios(struct tty_struct * tty, struct termios * old_termios){ struct isi_port * port = (struct isi_port *) tty->driver_data; unsigned long flags; if (isicom_paranoia_check(port, tty->device, "isicom_set_termios")) return; if (tty->termios->c_cflag == old_termios->c_cflag && tty->termios->c_iflag == old_termios->c_iflag) 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) return; tty_hangup(tty); }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; for (count=0; count < BOARD_COUNT; count++ ) { if (isi_card[count].base) { if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, 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; for (count=0; count < BOARD_COUNT; count++ ) if (isi_card[count].base) { 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; /* . . . */ } } 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){ int retval, card; for(card=0; card < BOARD_COUNT; card++) { isi_card[card].base=io[card]; isi_card[card].irq=irq[card]; } for (card=0 ;card < BOARD_COUNT; card++) { if (!((isi_card[card].irq==2)||(isi_card[card].irq==3)|| (isi_card[card].irq==4)||(isi_card[card].irq==5)|| (isi_card[card].irq==7)||(isi_card[card].irq==10)|| (isi_card[card].irq==11)||(isi_card[card].irq==12)|| (isi_card[card].irq==15))) { if (isi_card[card].base) { printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n", isi_card[card].irq, card+1); isi_card[card].base=0; } } } 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); disable_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 + -