isicom.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,938 行 · 第 1/4 页
C
1,938 行
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 a port greater than the port count for the card !!! */ if (line > ((board * 16) + card->port_count - 1)) { printk(KERN_ERR "ISICOM: Open on a port which exceeds the port_count of the card!\n"); return -ENODEV; } port = &isi_ports[line]; if (isicom_paranoia_check(port, tty->name, "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;#ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: open end!!!.\n");#endif return 0; } /* close et all */static 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); } }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->name, "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; 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); tty_ldisc_flush(tty); tty->closing = 0; port->tty = NULL; if (port->blocked_open) { if (port->close_delay) { set_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_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->name, "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_t(int, 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(); if (copy_from_user(tmp_buf, buf, cnt)) { up(&tmp_buf_sem); restore_flags(flags); return -EFAULT; } cli(); cnt = min_t(int, 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->name, "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->name, "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->name, "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->name, "isicom_chars_in_buffer")) return 0; return port->xmit_cnt;}/* ioctl et all */static 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"); goto out; } outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); outw((length & 0xff) << 8 | 0x00, base); outw((length & 0xff00), base); InterruptTheCard(base);out: restore_flags(flags);}static int isicom_tiocmget(struct tty_struct *tty, struct file *file){ struct isi_port * port = (struct isi_port *) tty->driver_data; /* just send the port status */ unsigned short status = port->status; if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) return -ENODEV; return ((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);}static int isicom_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear){ struct isi_port * port = (struct isi_port *) tty->driver_data; unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) return -ENODEV; save_flags(flags); cli(); if (set & TIOCM_RTS) raise_rts(port); if (set & TIOCM_DTR) raise_dtr(port); if (clear & TIOCM_RTS) drop_rts(port); if (clear & TIOCM_DTR) drop_dtr(port); restore_flags(flags); return 0;} static int isicom_set_serial_info(struct isi_port * port, struct serial_struct __user *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 (!capable(CAP_SYS_ADMIN)) { 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 __user *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; void __user *argp = (void __user *)arg; int retval; if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) return -ENODEV; switch(cmd) { case TCSBRK: retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); 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 __user *)argp); case TIOCSSOFTCAR: if(get_user(arg, (unsigned long __user *) argp)) return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCGSERIAL: return isicom_get_serial_info(port, argp); case TIOCSSERIAL: return isicom_set_serial_info(port, argp); 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->name, "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();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?