📄 mos7840.c
字号:
Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80 status = 0; status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); //Data = 0x0c; //status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); Data = 0x00; status = 0; status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data); dbg("mos7840_write:DLL value is %x\n", Data); Data = 0x0; status = 0; status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data); dbg("mos7840_write:DLM value is %x\n", Data); Data = Data & ~SERIAL_LCR_DLAB; dbg("mos7840_write: mos7840_port->shadowLCR is %x\n", mos7840_port->shadowLCR); status = 0; status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);#endif if (mos7840_port_paranoia_check(port, __FUNCTION__)) { dbg("%s", "Port Paranoia failed \n"); return -1; } serial = port->serial; if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) { dbg("%s", "Serial Paranoia failed \n"); return -1; } mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) { dbg("%s", "mos7840_port is NULL\n"); return -1; } /* try to find a free urb in the list */ urb = NULL; spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { if (!mos7840_port->busy[i]) { mos7840_port->busy[i] = 1; urb = mos7840_port->write_urb_pool[i]; dbg("\nURB:%d", i); break; } } spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); if (urb == NULL) { dbg("%s - no more free urbs", __FUNCTION__); goto exit; } if (urb->transfer_buffer == NULL) { urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); if (urb->transfer_buffer == NULL) { err("%s no more kernel memory...", __FUNCTION__); goto exit; } } transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); memcpy(urb->transfer_buffer, current_position, transfer_size); /* fill urb with data and submit */ usb_fill_bulk_urb(urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), urb->transfer_buffer, transfer_size, mos7840_bulk_out_data_callback, mos7840_port); data1 = urb->transfer_buffer; dbg("\nbulkout endpoint is %d", port->bulk_out_endpointAddress); /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { mos7840_port->busy[i] = 0; err("%s - usb_submit_urb(write bulk) failed with status = %d", __FUNCTION__, status); bytes_sent = status; goto exit; } bytes_sent = transfer_size; mos7840_port->icount.tx += transfer_size; smp_wmb(); dbg("mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx); exit: return bytes_sent;}/***************************************************************************** * mos7840_throttle * this function is called by the tty driver when it wants to stop the data * being read from the port. *****************************************************************************/static void mos7840_throttle(struct usb_serial_port *port){ struct moschip_port *mos7840_port; struct tty_struct *tty; int status; if (mos7840_port_paranoia_check(port, __FUNCTION__)) { dbg("%s", "Invalid port \n"); return; } dbg("- port %d\n", port->number); mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) return; if (!mos7840_port->open) { dbg("%s\n", "port not opened"); return; } dbg("%s", "Entering .......... \n"); tty = port->tty; if (!tty) { dbg("%s - no tty available", __FUNCTION__); return; } /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); status = mos7840_write(port, &stop_char, 1); if (status <= 0) { return; } } /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios->c_cflag & CRTSCTS) { mos7840_port->shadowMCR &= ~MCR_RTS; status = 0; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); if (status < 0) { return; } } return;}/***************************************************************************** * mos7840_unthrottle * this function is called by the tty driver when it wants to resume the data * being read from the port (called after SerialThrottle is called) *****************************************************************************/static void mos7840_unthrottle(struct usb_serial_port *port){ struct tty_struct *tty; int status; struct moschip_port *mos7840_port = mos7840_get_port_private(port); if (mos7840_port_paranoia_check(port, __FUNCTION__)) { dbg("%s", "Invalid port \n"); return; } if (mos7840_port == NULL) return; if (!mos7840_port->open) { dbg("%s - port not opened", __FUNCTION__); return; } dbg("%s", "Entering .......... \n"); tty = port->tty; if (!tty) { dbg("%s - no tty available", __FUNCTION__); return; } /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); status = mos7840_write(port, &start_char, 1); if (status <= 0) { return; } } /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios->c_cflag & CRTSCTS) { mos7840_port->shadowMCR |= MCR_RTS; status = 0; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); if (status < 0) { return; } } return;}static int mos7840_tiocmget(struct usb_serial_port *port, struct file *file){ struct moschip_port *mos7840_port; unsigned int result; __u16 msr; __u16 mcr; int status = 0; mos7840_port = mos7840_get_port_private(port); dbg("%s - port %d", __FUNCTION__, port->number); if (mos7840_port == NULL) return -ENODEV; status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr); status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr); result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | ((mcr & MCR_RTS) ? TIOCM_RTS : 0) | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0) | ((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0) | ((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0) | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); dbg("%s - 0x%04X", __FUNCTION__, result); return result;}static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear){ struct moschip_port *mos7840_port; unsigned int mcr; unsigned int status; dbg("%s - port %d", __FUNCTION__, port->number); mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) return -ENODEV; mcr = mos7840_port->shadowMCR; if (clear & TIOCM_RTS) mcr &= ~MCR_RTS; if (clear & TIOCM_DTR) mcr &= ~MCR_DTR; if (clear & TIOCM_LOOP) mcr &= ~MCR_LOOPBACK; if (set & TIOCM_RTS) mcr |= MCR_RTS; if (set & TIOCM_DTR) mcr |= MCR_DTR; if (set & TIOCM_LOOP) mcr |= MCR_LOOPBACK; mos7840_port->shadowMCR = mcr; status = 0; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr); if (status < 0) { dbg("setting MODEM_CONTROL_REGISTER Failed\n"); return -1; } return 0;}/***************************************************************************** * mos7840_calc_baud_rate_divisor * this function calculates the proper baud rate divisor for the specified * baud rate. *****************************************************************************/static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor, __u16 * clk_sel_val){ dbg("%s - %d", __FUNCTION__, baudRate); if (baudRate <= 115200) { *divisor = 115200 / baudRate; *clk_sel_val = 0x0; } if ((baudRate > 115200) && (baudRate <= 230400)) { *divisor = 230400 / baudRate; *clk_sel_val = 0x10; } else if ((baudRate > 230400) && (baudRate <= 403200)) { *divisor = 403200 / baudRate; *clk_sel_val = 0x20; } else if ((baudRate > 403200) && (baudRate <= 460800)) { *divisor = 460800 / baudRate; *clk_sel_val = 0x30; } else if ((baudRate > 460800) && (baudRate <= 806400)) { *divisor = 806400 / baudRate; *clk_sel_val = 0x40; } else if ((baudRate > 806400) && (baudRate <= 921600)) { *divisor = 921600 / baudRate; *clk_sel_val = 0x50; } else if ((baudRate > 921600) && (baudRate <= 1572864)) { *divisor = 1572864 / baudRate; *clk_sel_val = 0x60; } else if ((baudRate > 1572864) && (baudRate <= 3145728)) { *divisor = 3145728 / baudRate; *clk_sel_val = 0x70; } return 0;#ifdef NOTMCS7840 for (i = 0; i < ARRAY_SIZE(mos7840_divisor_table); i++) { if (mos7840_divisor_table[i].BaudRate == baudrate) { *divisor = mos7840_divisor_table[i].Divisor; return 0; } } /* After trying for all the standard baud rates * * Try calculating the divisor for this baud rate */ if (baudrate > 75 && baudrate < 230400) { /* get the divisor */ custom = (__u16) (230400L / baudrate); /* Check for round off */ round1 = (__u16) (2304000L / baudrate); round = (__u16) (round1 - (custom * 10)); if (round > 4) { custom++; } *divisor = custom; dbg(" Baud %d = %d\n", baudrate, custom); return 0; } dbg("%s\n", " Baud calculation Failed..."); return -1;#endif}/***************************************************************************** * mos7840_send_cmd_write_baud_rate * this function sends the proper command to change the baud rate of the * specified port. *****************************************************************************/static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, int baudRate){ int divisor = 0; int status; __u16 Data; unsigned char number; __u16 clk_sel_val; 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; } if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) { dbg("%s", "Invalid Serial \n"); return -1; } dbg("%s", "Entering .......... \n"); number = mos7840_port->port->number - mos7840_port->port->serial->minor; dbg("%s - port = %d, baud = %d", __FUNCTION__, mos7840_port->port->number, baudRate); //reset clk_uart_sel in spregOffset if (baudRate > 115200) {#ifdef HW_flow_control //NOTE: need to see the pther register to modify //setting h/w flow control bit to 1; status = 0; Data = 0x2b; mos7840_port->shadowMCR = Data; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); if (status < 0) { dbg("Writing spreg failed in set_serial_baud\n"); return -1; }#endif } else {#ifdef HW_flow_control //setting h/w flow control bit to 0; status = 0; Data = 0xb; mos7840_port->shadowMCR = Data; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); if (status < 0) { dbg("Writing spreg failed in set_serial_baud\n"); return -1; }#endif } if (1) //baudRate <= 115200) { clk_sel_val = 0x0; Data = 0x0; status = 0; status = mos7840_calc_baud_rate_divisor(baudRate, &divisor, &clk_sel_val); status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data); if (status < 0) { dbg("reading spreg failed in set_serial_baud\n"); return -1; } Data = (Data & 0x8f) | clk_sel_val; status = 0; status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); if (status < 0) { dbg("Writing spreg failed in set_serial_baud\n"); return -1; } /* Calculate the Divisor */ if (status) { err("%s - bad baud rate", __FUNCTION__); dbg("%s\n", "bad baud rate"); return status; } /* Enable access to divisor latch */ Data = mos7840_port->shadowLCR | SERIAL_LCR_DLAB; mos7840_port->shadowLCR = Data; mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); /* Write the divisor */ Data = (unsigned char)(divisor & 0xff); dbg("set_serial_baud Value to write DLL is %x\n", Data); mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data); Data = (unsigned char)((divisor & 0xff00) >> 8); dbg("set_serial_baud Value to write DLM is %x\n", Data); mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data); /* Disable access to divisor latch */ Data = mos7840_port->shadowLCR & ~SERIAL_LCR_DLAB; mos7840_port->shadowLCR = Data; mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -