📄 mos7720.c
字号:
/* Freeing Write URBs */ for (j = 0; j < NUM_URBS; ++j) { if (mos7720_port->write_urb_pool[j]) { kfree(mos7720_port->write_urb_pool[j]->transfer_buffer); usb_free_urb(mos7720_port->write_urb_pool[j]); } } /* While closing port, shutdown all bulk read, write * * and interrupt read if they exists */ if (serial->dev) { dbg("Shutdown bulk write"); usb_kill_urb(port->write_urb); dbg("Shutdown bulk read"); usb_kill_urb(port->read_urb); } data = 0x00; send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, 0x04, &data); data = 0x00; send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, 0x01, &data); mos7720_port->open = 0; dbg("Leaving %s", __FUNCTION__);}static void mos7720_break(struct usb_serial_port *port, int break_state){ unsigned char data; struct usb_serial *serial; struct moschip_port *mos7720_port; dbg("Entering %s", __FUNCTION__); serial = port->serial; mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) return; if (break_state == -1) data = mos7720_port->shadowLCR | UART_LCR_SBC; else data = mos7720_port->shadowLCR & ~UART_LCR_SBC; mos7720_port->shadowLCR = data; send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, 0x03, &data); return;}/* * mos7720_write_room * this function is called by the tty driver when it wants to know how many * bytes of data we can accept for a specific port. * If successful, we return the amount of room that we have for this port * Otherwise we return a negative error number. */static int mos7720_write_room(struct usb_serial_port *port){ struct moschip_port *mos7720_port; int room = 0; int i; dbg("%s:entering ...........", __FUNCTION__); mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) { dbg("%s:leaving ...........", __FUNCTION__); return -ENODEV; } for (i = 0; i < NUM_URBS; ++i) { if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) room += URB_TRANSFER_BUFFER_SIZE; } dbg("%s - returns %d", __FUNCTION__, room); return room;}static int mos7720_write(struct usb_serial_port *port, const unsigned char *data, int count){ int status; int i; int bytes_sent = 0; int transfer_size; struct moschip_port *mos7720_port; struct usb_serial *serial; struct urb *urb; const unsigned char *current_position = data; dbg("%s:entering ...........", __FUNCTION__); serial = port->serial; mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) { dbg("mos7720_port is NULL"); return -ENODEV; } /* try to find a free urb in the list */ urb = NULL; for (i = 0; i < NUM_URBS; ++i) { if (mos7720_port->write_urb_pool[i] && mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { urb = mos7720_port->write_urb_pool[i]; dbg("URB:%d",i); break; } } 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); usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, urb->transfer_buffer); /* 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, mos7720_bulk_out_data_callback, mos7720_port); /* send it down the pipe */ status = usb_submit_urb(urb,GFP_ATOMIC); if (status) { err("%s - usb_submit_urb(write bulk) failed with status = %d", __FUNCTION__, status); bytes_sent = status; goto exit; } bytes_sent = transfer_size;exit: return bytes_sent;}static void mos7720_throttle(struct usb_serial_port *port){ struct moschip_port *mos7720_port; struct tty_struct *tty; int status; dbg("%s- port %d\n", __FUNCTION__, port->number); mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) return; if (!mos7720_port->open) { dbg("port not opened"); return; } dbg("%s: Entering ..........", __FUNCTION__); 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 = mos7720_write(port, &stop_char, 1); if (status <= 0) return; } /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios->c_cflag & CRTSCTS) { mos7720_port->shadowMCR &= ~UART_MCR_RTS; status = send_mos_cmd(port->serial, MOS_WRITE, port->number - port->serial->minor, UART_MCR, &mos7720_port->shadowMCR); if (status != 0) return; }}static void mos7720_unthrottle(struct usb_serial_port *port){ struct tty_struct *tty; int status; struct moschip_port *mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) return; if (!mos7720_port->open) { dbg("%s - port not opened", __FUNCTION__); return; } dbg("%s: Entering ..........", __FUNCTION__); 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 = mos7720_write(port, &start_char, 1); if (status <= 0) return; } /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios->c_cflag & CRTSCTS) { mos7720_port->shadowMCR |= UART_MCR_RTS; status = send_mos_cmd(port->serial, MOS_WRITE, port->number - port->serial->minor, UART_MCR, &mos7720_port->shadowMCR); if (status != 0) return; }}static int set_higher_rates(struct moschip_port *mos7720_port, unsigned int baud){ unsigned char data; struct usb_serial_port *port; struct usb_serial *serial; int port_number; if (mos7720_port == NULL) return -EINVAL; port = mos7720_port->port; serial = port->serial; /*********************************************** * Init Sequence for higher rates ***********************************************/ dbg("Sending Setting Commands .........."); port_number = port->number - port->serial->minor; data = 0x000; send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); data = 0x000; send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); data = 0x0CF; send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data); data = 0x00b; mos7720_port->shadowMCR = data; send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); data = 0x00b; send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); data = 0x000; send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); data = 0x000; send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); /*********************************************** * Set for higher rates * ***********************************************/ data = baud * 0x10; send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data); data = 0x003; send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); data = 0x003; send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); data = 0x02b; mos7720_port->shadowMCR = data; send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); data = 0x02b; send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); /*********************************************** * Set DLL/DLM ***********************************************/ data = mos7720_port->shadowLCR | UART_LCR_DLAB; mos7720_port->shadowLCR = data; send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); data = 0x001; /* DLL */ send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); data = 0x000; /* DLM */ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; mos7720_port->shadowLCR = data; send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); return 0;}/* baud rate information */struct divisor_table_entry{ __u32 baudrate; __u16 divisor;};/* Define table of divisors for moschip 7720 hardware * * These assume a 3.6864MHz crystal, the standard /16, and * * MCR.7 = 0. */static struct divisor_table_entry divisor_table[] = { { 50, 2304}, { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */ { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */ { 150, 768}, { 300, 384}, { 600, 192}, { 1200, 96}, { 1800, 64}, { 2400, 48}, { 4800, 24}, { 7200, 16}, { 9600, 12}, { 19200, 6}, { 38400, 3}, { 57600, 2}, { 115200, 1},};/***************************************************************************** * calc_baud_rate_divisor * this function calculates the proper baud rate divisor for the specified * baud rate. *****************************************************************************/static int calc_baud_rate_divisor(int baudrate, int *divisor){ int i; __u16 custom; __u16 round1; __u16 round; dbg("%s - %d", __FUNCTION__, baudrate); for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { if (divisor_table[i].baudrate == baudrate) { *divisor = 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",baudrate, custom); return 0; } dbg("Baud calculation Failed..."); return -EINVAL;}/* * send_cmd_write_baud_rate * this function sends the proper command to change the baud rate of the * specified port. */static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, int baudrate){ struct usb_serial_port *port; struct usb_serial *serial; int divisor; int status; unsigned char data; unsigned char number; if (mos7720_port == NULL) return -1; port = mos7720_port->port; serial = port->serial; dbg("%s: Entering ..........", __FUNCTION__); number = port->number - port->serial->minor; dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate); /* Calculate the Divisor */ status = calc_baud_rate_divisor(baudrate, &divisor); if (status) { err("%s - bad baud rate", __FUNCTION__); return status; } /* Enable access to divisor latch */ data = mos7720_port->shadowLCR | UART_LCR_DLAB; mos7720_port->shadowLCR = data; send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data); /* Write the divisor */ data = ((unsigned char)(divisor & 0xff)); send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data); data = ((unsigned char)((divisor & 0xff00) >> 8)); send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data); /* Disable access to divisor latch */ data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; mos7720_port->shadowLCR = data; send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data); return status;}/* * change_port_settings * This routine is called to set the UART on the device to match * the specified new settings. */static void change_port_settings(struct moschip_port *mos7720_port, struct ktermios *old_termios){ struct usb_serial_port *port; struct usb_serial *serial; struct tty_struct *tty; int baud; unsigned cflag; unsigned iflag; __u8 mask = 0xff; __u8 lData; __u8 lParity; __u8 lStop; int status; int port_number; char data; if (mos7720_port == NULL) return ; port = mos7720_port->port; serial = port->serial; port_number = port->number - port->serial->minor; dbg("%s - port %d", __FUNCTION__, port->number); if (!mos7720_port->open) { dbg("%s - port not opened", __FUNCTION__); return; } tty = mos7720_port->port->tty; if ((!tty) || (!tty->termios)) { dbg("%s - no tty structures", __FUNCTION__); return; } dbg("%s: Entering ..........", __FUNCTION__); lData = UART_LCR_WLEN8; lStop = 0x00; /* 1 stop bit */ lParity = 0x00; /* No parity */ cflag = tty->termios->c_cflag; iflag = tty->termios->c_iflag; /* Change the number of bits */ switch (cflag & CSIZE) { case CS5: lData = UART_LCR_WLEN5; mask = 0x1f; break; case CS6: lData = UART_LCR_WLEN6; mask = 0x3f; break; case CS7: lData = UART_LCR_WLEN7; mask = 0x7f; break; default: case CS8: lData = UART_LCR_WLEN8; break; } /* Change the Parity bit */ if (cflag & PARENB) { if (cflag & PARODD) { lParity = UART_LCR_PARITY; dbg("%s - parity = odd", __FUNCTION__); } else { lParity = (UART_LCR_EPAR | UART_LCR_PARITY); 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 = UART_LCR_STOP; dbg("%s - stop bits = 2", __FUNCTION__); } else { lStop = 0x00; dbg("%s - stop bits = 1", __FUNCTION__); }#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */#define LCR_PAR_MASK 0x38 /* Mask for parity field */ /* Update the LCR with the correct value */ mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); mos7720_port->shadowLCR |= (lData | lParity | lStop); /* Disable Interrupts */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -