📄 isicom.c
字号:
struct isi_board * card; unsigned int line, board; unsigned long flags; int error;#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: open start!!!.\n");#endif line = MINOR(tty->device) - tty->driver.minor_start; #ifdef ISICOM_DEBUG printk(KERN_DEBUG "line = %d.\n", line);#endif if ((line < 0) || (line > (PORT_COUNT-1))) return -ENODEV; board = BOARD(line); #ifdef ISICOM_DEBUG printk(KERN_DEBUG "board = %d.\n", board);#endif card = &isi_card[board]; if (!(card->status & FIRMWARE_LOADED)) {#ifdef ISICOM_DEBUG printk(KERN_DEBUG"ISICOM: Firmware not loaded to card%d.\n", board);#endif return -ENODEV; } /* open on higher 8 dev files on a 8 port card !!! */ if (card->port_count == 8) if (line > ((board * 16)+7)) { printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n"); return -ENODEV; } port = &isi_ports[line]; if (isicom_paranoia_check(port, tty->device, "isicom_open")) return -ENODEV; #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: isicom_setup_board ...\n"); #endif isicom_setup_board(card); port->count++; tty->driver_data = port; port->tty = tty;#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: isicom_setup_port ...\n");#endif if ((error = isicom_setup_port(port))!=0) return error;#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: block_til_ready ...\n"); #endif if ((error = block_til_ready(tty, filp, port))!=0) return error; if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = port->normal_termios; else *tty->termios = port->callout_termios; save_flags(flags); cli(); isicom_config_port(port); restore_flags(flags); } port->session = current->session; port->pgrp = current->pgrp;#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: open end!!!.\n");#endif return 0; } /* close et all */extern inline void isicom_shutdown_board(struct isi_board * bp){ int channel; struct isi_port * port; if (!(bp->status & BOARD_ACTIVE)) return; bp->status &= ~BOARD_ACTIVE; port = bp->ports; for(channel = 0; channel < bp->port_count; channel++, port++) { drop_dtr_rts(port); } MOD_DEC_USE_COUNT;}static void isicom_shutdown_port(struct isi_port * port){ struct isi_board * card = port->card; struct tty_struct * tty; if (!(port->flags & ASYNC_INITIALIZED)) return; if (port->xmit_buf) { free_page((unsigned long) port->xmit_buf); port->xmit_buf = NULL; } if (!(tty = port->tty) || C_HUPCL(tty)) /* drop dtr on this port */ drop_dtr(port); /* any other port uninits */ if (tty) set_bit(TTY_IO_ERROR, &tty->flags); port->flags &= ~ASYNC_INITIALIZED; if (--card->count < 0) { printk(KERN_DEBUG "ISICOM: isicom_shutdown_port: bad board(0x%x) count %d.\n", card->base, card->count); card->count = 0; } /* last port was closed , shutdown that boad too */ if (!card->count) isicom_shutdown_board(card);}static void isicom_close(struct tty_struct * tty, struct file * filp){ struct isi_port * port = (struct isi_port *) tty->driver_data; struct isi_board * card = port->card; unsigned long flags; if (!port) return; if (isicom_paranoia_check(port, tty->device, "isicom_close")) return; #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: Close start!!!.\n");#endif save_flags(flags); cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } if ((tty->count == 1) && (port->count != 1)) { printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count" "tty->count = 1 port count = %d.\n", card->base, port->count); port->count = 1; } if (--port->count < 0) { printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count for" "channel%d = %d", card->base, port->channel, port->count); port->count = 0; } if (port->count) { restore_flags(flags); return; } port->flags |= ASYNC_CLOSING; /* * save termios struct since callout and dialin termios may be * different. */ if (port->flags & ASYNC_NORMAL_ACTIVE) port->normal_termios = *tty->termios; if (port->flags & ASYNC_CALLOUT_ACTIVE) port->callout_termios = *tty->termios; tty->closing = 1; if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, port->closing_wait); /* indicate to the card that no more data can be received on this port */ if (port->flags & ASYNC_INITIALIZED) { card->port_status &= ~(1 << port->channel); outw(card->port_status, card->base + 0x02); } isicom_shutdown_port(port); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); tty->closing = 0; port->tty = 0; if (port->blocked_open) { if (port->close_delay) { current->state = TASK_INTERRUPTIBLE;#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: scheduling until time out.\n");#endif schedule_timeout(port->close_delay); } wake_up_interruptible(&port->open_wait); } port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); restore_flags(flags);#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: Close end!!!.\n");#endif }/* write et all */static int isicom_write(struct tty_struct * tty, int from_user, const unsigned char * buf, int count){ struct isi_port * port = (struct isi_port *) tty->driver_data; unsigned long flags; int cnt, total = 0;#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n", port->channel+1, count);#endif if (isicom_paranoia_check(port, tty->device, "isicom_write")) return 0; if (!tty || !port->xmit_buf || !tmp_buf) return 0; if (from_user) down(&tmp_buf_sem); /* acquire xclusive access to tmp_buf */ save_flags(flags); while(1) { cli(); cnt = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (cnt <= 0) break; if (from_user) { /* the following may block for paging... hence enabling interrupts but tx routine may have created more space in xmit_buf when the ctrl gets back here */ sti(); copy_from_user(tmp_buf, buf, cnt); cli(); cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt); } else memcpy(port->xmit_buf + port->xmit_head, buf, cnt); port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1); port->xmit_cnt += cnt; restore_flags(flags); buf += cnt; count -= cnt; total += cnt; } if (from_user) up(&tmp_buf_sem); if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped) port->status |= ISI_TXOK; restore_flags(flags);#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: isicom_write %d bytes written.\n", total);#endif return total; }/* put_char et all */static void isicom_put_char(struct tty_struct * tty, unsigned char ch){ struct isi_port * port = (struct isi_port *) tty->driver_data; unsigned long flags; if (isicom_paranoia_check(port, tty->device, "isicom_put_char")) return; if (!tty || !port->xmit_buf) return;#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", port->channel+1, ch);#endif save_flags(flags); cli(); if (port->xmit_cnt >= (SERIAL_XMIT_SIZE - 1)) { restore_flags(flags); return; } port->xmit_buf[port->xmit_head++] = ch; port->xmit_head &= (SERIAL_XMIT_SIZE - 1); port->xmit_cnt++; restore_flags(flags);}/* flush_chars et all */static void isicom_flush_chars(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; if (isicom_paranoia_check(port, tty->device, "isicom_flush_chars")) return; if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !port->xmit_buf) return; /* this tells the transmitter to consider this port for data output to the card ... that's the best we can do. */ port->status |= ISI_TXOK; }/* write_room et all */static int isicom_write_room(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; int free; if (isicom_paranoia_check(port, tty->device, "isicom_write_room")) return 0; free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; if (free < 0) free = 0; return free;}/* chars_in_buffer et all */static int isicom_chars_in_buffer(struct tty_struct * tty){ struct isi_port * port = (struct isi_port *) tty->driver_data; if (isicom_paranoia_check(port, tty->device, "isicom_chars_in_buffer")) return 0; return port->xmit_cnt;}/* ioctl et all */extern inline void isicom_send_break(struct isi_port * port, unsigned long length){ struct isi_board * card = port->card; short wait = 10; unsigned short base = card->base; unsigned long flags; save_flags(flags); cli(); while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); if (!wait) { printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n"); return; } outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); outw((length & 0xff) << 8 | 0x00, base); outw((length & 0xff00), base); InterruptTheCard(base); restore_flags(flags);}static int isicom_get_modem_info(struct isi_port * port, unsigned int * value){ /* just send the port status */ unsigned int info; unsigned short status = port->status; info = ((status & ISI_RTS) ? TIOCM_RTS : 0) | ((status & ISI_DTR) ? TIOCM_DTR : 0) | ((status & ISI_DCD) ? TIOCM_CAR : 0) | ((status & ISI_DSR) ? TIOCM_DSR : 0) | ((status & ISI_CTS) ? TIOCM_CTS : 0) | ((status & ISI_RI ) ? TIOCM_RI : 0); put_user(info, (unsigned long *) value); return 0; }static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd, unsigned int * value){ unsigned int arg; unsigned long flags; if(get_user(arg, value)) return -EFAULT; save_flags(flags); cli(); switch(cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) raise_rts(port); if (arg & TIOCM_DTR) raise_dtr(port); break; case TIOCMBIC: if (arg & TIOCM_RTS) drop_rts(port); if (arg & TIOCM_DTR) drop_dtr(port); break; case TIOCMSET: if (arg & TIOCM_RTS) raise_rts(port); else drop_rts(port); if (arg & TIOCM_DTR) raise_dtr(port); else drop_dtr(port); break; default: restore_flags(flags); return -EINVAL; } restore_flags(flags); return 0;} static int isicom_set_serial_info(struct isi_port * port, struct serial_struct * info){ struct serial_struct newinfo; unsigned long flags; int reconfig_port; if(copy_from_user(&newinfo, info, sizeof(newinfo))) return -EFAULT; reconfig_port = ((port->flags & ASYNC_SPD_MASK) != (newinfo.flags & ASYNC_SPD_MASK)); if (!suser()) { if ((newinfo.close_delay != port->close_delay) || (newinfo.closing_wait != port->closing_wait) || ((newinfo.flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) return -EPERM; port->flags = ((port->flags & ~ ASYNC_USR_MASK) | (newinfo.flags & ASYNC_USR_MASK)); } else { port->close_delay = newinfo.close_delay; port->closing_wait = newinfo.closing_wait; port->flags = ((port->flags & ~ASYNC_FLAGS) | (newinfo.flags & ASYNC_FLAGS)); } if (reconfig_port) { save_flags(flags); cli(); isicom_config_port(port); restore_flags(flags); } return 0; } static int isicom_get_serial_info(struct isi_port * port, struct serial_struct * info){ struct serial_struct out_info; memset(&out_info, 0, sizeof(out_info));/* out_info.type = ? */ out_info.line = port - isi_ports; out_info.port = port->card->base; out_info.irq = port->card->irq; out_info.flags = port->flags;/* out_info.baud_base = ? */ out_info.close_delay = port->close_delay; out_info.closing_wait = port->closing_wait; if(copy_to_user(info, &out_info, sizeof(out_info))) return -EFAULT; return 0;} static int isicom_ioctl(struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg) { struct isi_port * port = (struct isi_port *) tty->driver_data; int retval; if (isicom_paranoia_check(port, tty->device, "isicom_ioctl")) return -ENODEV; switch(cmd) { case TCSBRK: retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -