📄 mos7840.c
字号:
return status;}/***************************************************************************** * mos7840_change_port_settings * This routine is called to set the UART on the device to match * the specified new settings. *****************************************************************************/static void mos7840_change_port_settings(struct moschip_port *mos7840_port, struct ktermios *old_termios){ struct tty_struct *tty; int baud; unsigned cflag; unsigned iflag; __u8 lData; __u8 lParity; __u8 lStop; int status; __u16 Data; struct usb_serial_port *port; struct usb_serial *serial; if (mos7840_port == NULL) return; port = (struct usb_serial_port *)mos7840_port->port; if (mos7840_port_paranoia_check(port, __FUNCTION__)) { dbg("%s", "Invalid port \n"); return; } if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) { dbg("%s", "Invalid Serial \n"); return; } serial = port->serial; dbg("%s - port %d", __FUNCTION__, mos7840_port->port->number); if (!mos7840_port->open) { dbg("%s - port not opened", __FUNCTION__); return; } tty = mos7840_port->port->tty; dbg("%s", "Entering .......... \n"); lData = LCR_BITS_8; lStop = LCR_STOP_1; lParity = LCR_PAR_NONE; cflag = tty->termios->c_cflag; iflag = tty->termios->c_iflag; /* Change the number of bits */ if (cflag & CSIZE) { switch (cflag & CSIZE) { case CS5: lData = LCR_BITS_5; break; case CS6: lData = LCR_BITS_6; break; case CS7: lData = LCR_BITS_7; break; default: case CS8: lData = LCR_BITS_8; break; } } /* Change the Parity bit */ if (cflag & PARENB) { if (cflag & PARODD) { lParity = LCR_PAR_ODD; dbg("%s - parity = odd", __FUNCTION__); } else { lParity = LCR_PAR_EVEN; dbg("%s - parity = even", __FUNCTION__); } } else { dbg("%s - parity = none", __FUNCTION__); } if (cflag & CMSPAR) { lParity = lParity | 0x20; } /* Change the Stop bit */ if (cflag & CSTOPB) { lStop = LCR_STOP_2; dbg("%s - stop bits = 2", __FUNCTION__); } else { lStop = LCR_STOP_1; dbg("%s - stop bits = 1", __FUNCTION__); } /* Update the LCR with the correct value */ mos7840_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); mos7840_port->shadowLCR |= (lData | lParity | lStop); dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x\n", mos7840_port->shadowLCR); /* Disable Interrupts */ Data = 0x00; mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); Data = 0x00; mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); Data = 0xcf; mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); /* Send the updated LCR value to the mos7840 */ Data = mos7840_port->shadowLCR; mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); Data = 0x00b; mos7840_port->shadowMCR = Data; mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); Data = 0x00b; mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); /* set up the MCR register and send it to the mos7840 */ mos7840_port->shadowMCR = MCR_MASTER_IE; if (cflag & CBAUD) { mos7840_port->shadowMCR |= (MCR_DTR | MCR_RTS); } if (cflag & CRTSCTS) { mos7840_port->shadowMCR |= (MCR_XON_ANY); } else { mos7840_port->shadowMCR &= ~(MCR_XON_ANY); } Data = mos7840_port->shadowMCR; mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); /* Determine divisor based on baud rate */ baud = tty_get_baud_rate(tty); if (!baud) { /* pick a default, any default... */ dbg("%s\n", "Picked default baud..."); baud = 9600; } dbg("%s - baud rate = %d", __FUNCTION__, baud); status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud); /* Enable Interrupts */ Data = 0x0c; mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); if (mos7840_port->read_urb->status != -EINPROGRESS) { mos7840_port->read_urb->dev = serial->dev; status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); if (status) { dbg(" usb_submit_urb(read bulk) failed, status = %d", status); } } wake_up(&mos7840_port->delta_msr_wait); mos7840_port->delta_msr_cond = 1; dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x\n", mos7840_port->shadowLCR); return;}/***************************************************************************** * mos7840_set_termios * this function is called by the tty driver when it wants to change * the termios structure *****************************************************************************/static void mos7840_set_termios(struct usb_serial_port *port, struct ktermios *old_termios){ int status; unsigned int cflag; struct usb_serial *serial; struct moschip_port *mos7840_port; struct tty_struct *tty; dbg("mos7840_set_termios: START\n"); if (mos7840_port_paranoia_check(port, __FUNCTION__)) { dbg("%s", "Invalid port \n"); return; } serial = port->serial; if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) { dbg("%s", "Invalid Serial \n"); return; } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) return; tty = port->tty; if (!mos7840_port->open) { dbg("%s - port not opened", __FUNCTION__); return; } dbg("%s\n", "setting termios - "); cflag = tty->termios->c_cflag; dbg("%s - clfag %08x iflag %08x", __FUNCTION__, tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag)); dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); dbg("%s - port %d", __FUNCTION__, port->number); /* change the port settings to the new ones specified */ mos7840_change_port_settings(mos7840_port, old_termios); if (!mos7840_port->read_urb) { dbg("%s", "URB KILLED !!!!!\n"); return; } if (mos7840_port->read_urb->status != -EINPROGRESS) { mos7840_port->read_urb->dev = serial->dev; status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); if (status) { dbg(" usb_submit_urb(read bulk) failed, status = %d", status); } } return;}/***************************************************************************** * mos7840_get_lsr_info - get line status register info * * Purpose: Let user call ioctl() to get info when the UART physically * is emptied. On bus types like RS485, the transmitter must * release the bus after transmitting. This must be done when * the transmit shift register is empty, not be done when the * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. *****************************************************************************/static int mos7840_get_lsr_info(struct moschip_port *mos7840_port, unsigned int __user *value){ int count; unsigned int result = 0; count = mos7840_chars_in_buffer(mos7840_port->port); if (count == 0) { dbg("%s -- Empty", __FUNCTION__); result = TIOCSER_TEMT; } if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; return 0;}/***************************************************************************** * mos7840_set_modem_info * function to set modem info *****************************************************************************/static int mos7840_set_modem_info(struct moschip_port *mos7840_port, unsigned int cmd, unsigned int __user *value){ unsigned int mcr; unsigned int arg; __u16 Data; int status; struct usb_serial_port *port; if (mos7840_port == NULL) return -1; port = (struct usb_serial_port *)mos7840_port->port; if (mos7840_port_paranoia_check(port, __FUNCTION__)) { dbg("%s", "Invalid port \n"); return -1; } mcr = mos7840_port->shadowMCR; if (copy_from_user(&arg, value, sizeof(int))) return -EFAULT; switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) mcr |= MCR_RTS; if (arg & TIOCM_DTR) mcr |= MCR_RTS; if (arg & TIOCM_LOOP) mcr |= MCR_LOOPBACK; break; case TIOCMBIC: if (arg & TIOCM_RTS) mcr &= ~MCR_RTS; if (arg & TIOCM_DTR) mcr &= ~MCR_RTS; if (arg & TIOCM_LOOP) mcr &= ~MCR_LOOPBACK; break; case TIOCMSET: /* turn off the RTS and DTR and LOOPBACK * and then only turn on what was asked to */ mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK); mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0); mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0); mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0); break; } mos7840_port->shadowMCR = mcr; Data = mos7840_port->shadowMCR; status = 0; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); if (status < 0) { dbg("setting MODEM_CONTROL_REGISTER Failed\n"); return -1; } return 0;}/***************************************************************************** * mos7840_get_modem_info * function to get modem info *****************************************************************************/static int mos7840_get_modem_info(struct moschip_port *mos7840_port, unsigned int __user *value){ unsigned int result = 0; __u16 msr; unsigned int mcr = mos7840_port->shadowMCR; int status = 0; status = mos7840_get_uart_reg(mos7840_port->port, MODEM_STATUS_REGISTER, &msr); result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */ |((mcr & MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */ |((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */ |((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0) /* 0x040 */ |((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */ |((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */ dbg("%s -- %x", __FUNCTION__, result); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; return 0;}/***************************************************************************** * mos7840_get_serial_info * function to get information about serial port *****************************************************************************/static int mos7840_get_serial_info(struct moschip_port *mos7840_port, struct serial_struct __user *retinfo){ struct serial_struct tmp; if (mos7840_port == NULL) return -1; if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; tmp.line = mos7840_port->port->serial->minor; tmp.port = mos7840_port->port->number; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; tmp.baud_base = 9600; tmp.close_delay = 5 * HZ; tmp.closing_wait = 30 * HZ; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0;}/***************************************************************************** * SerialIoctl * this function handles any ioctl calls to the driver *****************************************************************************/static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg){ void __user *argp = (void __user *)arg; struct moschip_port *mos7840_port; struct tty_struct *tty; struct async_icount cnow; struct async_icount cprev; struct serial_icounter_struct icount; int mosret = 0; if (mos7840_port_paranoia_check(port, __FUNCTION__)) { dbg("%s", "Invalid port \n"); return -1; } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) return -1; tty = mos7840_port->port->tty; dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); switch (cmd) { /* return number of bytes available */ case TIOCSERGETLSR: dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); return mos7840_get_lsr_info(mos7840_port, argp); return 0; case TIOCMBIS: case TIOCMBIC: case TIOCMSET: dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, port->number); mosret = mos7840_set_modem_info(mos7840_port, cmd, argp); return mosret; case TIOCMGET: dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); return mos7840_get_modem_info(mos7840_port, argp); case TIOCGSERIAL: dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number); return mos7840_get_serial_info(mos7840_port, argp); case TIOCSSERIAL: dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number); break; case TIOCMIWAIT: dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); cprev = mos7840_port->icount; while (1) { //interruptible_sleep_on(&mos7840_port->
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -