📄 io_edgeport.c
字号:
/* * Edgeport USB Serial Converter driver * * Copyright (C) 2000 Inside Out Networks, All rights reserved. * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Supports the following devices: * Edgeport/4 * Edgeport/4t * Edgeport/2 * Edgeport/4i * Edgeport/2i * Edgeport/421 * Edgeport/21 * Rapidport/4 * Edgeport/8 * Edgeport/2D8 * Edgeport/4D8 * Edgeport/8i * * For questions or problems with this driver, contact Inside Out * Networks technical support, or Peter Berger <pberger@brimson.com>, * or Al Borchers <alborchers@steinerpoint.com>. * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/jiffies.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/serial.h>#include <linux/ioctl.h>#include <linux/wait.h>#include <asm/uaccess.h>#include <linux/usb.h>#include "usb-serial.h"#include "io_edgeport.h"#include "io_ionsp.h" /* info for the iosp messages */#include "io_16654.h" /* 16654 UART defines *//* * Version Information */#define DRIVER_VERSION "v2.7"#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"#define DRIVER_DESC "Edgeport USB Serial Driver"/* First, the latest boot code - for first generation edgeports */#define IMAGE_ARRAY_NAME BootCodeImage_GEN1#define IMAGE_VERSION_NAME BootCodeImageVersion_GEN1#include "io_fw_boot.h" /* the bootloader firmware to download to a device, if it needs it *//* for second generation edgeports */#define IMAGE_ARRAY_NAME BootCodeImage_GEN2#define IMAGE_VERSION_NAME BootCodeImageVersion_GEN2#include "io_fw_boot2.h" /* the bootloader firmware to download to a device, if it needs it *//* Then finally the main run-time operational code - for first generation edgeports */#define IMAGE_ARRAY_NAME OperationalCodeImage_GEN1#define IMAGE_VERSION_NAME OperationalCodeImageVersion_GEN1#include "io_fw_down.h" /* Define array OperationalCodeImage[] *//* for second generation edgeports */#define IMAGE_ARRAY_NAME OperationalCodeImage_GEN2#define IMAGE_VERSION_NAME OperationalCodeImageVersion_GEN2#include "io_fw_down2.h" /* Define array OperationalCodeImage[] */#define MAX_NAME_LEN 64#define CHASE_TIMEOUT (5*HZ) /* 5 seconds */#define OPEN_TIMEOUT (5*HZ) /* 5 seconds */#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds *//* receive port state */enum RXSTATE { EXPECT_HDR1 = 0, /* Expect header byte 1 */ EXPECT_HDR2 = 1, /* Expect header byte 2 */ EXPECT_DATA = 2, /* Expect 'RxBytesRemaining' data */ EXPECT_HDR3 = 3, /* Expect header byte 3 (for status hdrs only) */};/* Transmit Fifo * This Transmit queue is an extension of the edgeport Rx buffer. * The maximum amount of data buffered in both the edgeport * Rx buffer (maxTxCredits) and this buffer will never exceed maxTxCredits. */struct TxFifo { unsigned int head; /* index to head pointer (write) */ unsigned int tail; /* index to tail pointer (read) */ unsigned int count; /* Bytes in queue */ unsigned int size; /* Max size of queue (equal to Max number of TxCredits) */ unsigned char *fifo; /* allocated Buffer */};/* This structure holds all of the local port information */struct edgeport_port { __u16 txCredits; /* our current credits for this port */ __u16 maxTxCredits; /* the max size of the port */ struct TxFifo txfifo; /* transmit fifo -- size will be maxTxCredits */ struct urb *write_urb; /* write URB for this port */ char write_in_progress; /* TRUE while a write URB is outstanding */ spinlock_t ep_lock; __u8 shadowLCR; /* last LCR value received */ __u8 shadowMCR; /* last MCR value received */ __u8 shadowMSR; /* last MSR value received */ __u8 shadowLSR; /* last LSR value received */ __u8 shadowXonChar; /* last value set as XON char in Edgeport */ __u8 shadowXoffChar; /* last value set as XOFF char in Edgeport */ __u8 validDataMask; __u32 baudRate; char open; char openPending; char commandPending; char closePending; char chaseResponsePending; wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */ wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */ wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ struct async_icount icount; struct usb_serial_port *port; /* loop back to the owner of this object */};/* This structure holds all of the individual device information */struct edgeport_serial { char name[MAX_NAME_LEN+1]; /* string name of this device */ struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ struct edgeport_product_info product_info; /* Product Info */ __u8 interrupt_in_endpoint; /* the interrupt endpoint handle */ unsigned char * interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */ struct urb * interrupt_read_urb; /* our interrupt urb */ __u8 bulk_in_endpoint; /* the bulk in endpoint handle */ unsigned char * bulk_in_buffer; /* the buffer we use for the bulk in endpoint */ struct urb * read_urb; /* our bulk read urb */ int read_in_progress; spinlock_t es_lock; __u8 bulk_out_endpoint; /* the bulk out endpoint handle */ __s16 rxBytesAvail; /* the number of bytes that we need to read from this device */ enum RXSTATE rxState; /* the current state of the bulk receive processor */ __u8 rxHeader1; /* receive header byte 1 */ __u8 rxHeader2; /* receive header byte 2 */ __u8 rxHeader3; /* receive header byte 3 */ __u8 rxPort; /* the port that we are currently receiving data for */ __u8 rxStatusCode; /* the receive status code */ __u8 rxStatusParam; /* the receive status paramater */ __s16 rxBytesRemaining; /* the number of port bytes left to read */ struct usb_serial *serial; /* loop back to the owner of this object */};/* baud rate information */struct divisor_table_entry { __u32 BaudRate; __u16 Divisor;};//// Define table of divisors for Rev A EdgePort/4 hardware// These assume a 3.6864MHz crystal, the standard /16, and// MCR.7 = 0.//static struct divisor_table_entry divisor_table[] = { { 50, 4608}, { 75, 3072}, { 110, 2095}, /* 2094.545455 => 230450 => .0217 % over */ { 134, 1713}, /* 1713.011152 => 230398.5 => .00065% under */ { 150, 1536}, { 300, 768}, { 600, 384}, { 1200, 192}, { 1800, 128}, { 2400, 96}, { 4800, 48}, { 7200, 32}, { 9600, 24}, { 14400, 16}, { 19200, 12}, { 38400, 6}, { 57600, 4}, { 115200, 2}, { 230400, 1},};/* local variables */static int debug;static int low_latency = 1; /* tty low latency flag, on by default */static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs *//* local function prototypes *//* function prototypes for all URB callbacks */static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs);static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs);static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs);static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs);/* function prototypes for the usbserial callbacks */static int edge_open (struct usb_serial_port *port, struct file *filp);static void edge_close (struct usb_serial_port *port, struct file *filp);static int edge_write (struct usb_serial_port *port, const unsigned char *buf, int count);static int edge_write_room (struct usb_serial_port *port);static int edge_chars_in_buffer (struct usb_serial_port *port);static void edge_throttle (struct usb_serial_port *port);static void edge_unthrottle (struct usb_serial_port *port);static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios);static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);static void edge_break (struct usb_serial_port *port, int break_state);static int edge_tiocmget (struct usb_serial_port *port, struct file *file);static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);static int edge_startup (struct usb_serial *serial);static void edge_shutdown (struct usb_serial *serial);#include "io_tables.h" /* all of the devices that this driver supports */static struct usb_driver io_driver = { .owner = THIS_MODULE, .name = "io_edgeport", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table_combined,};/* function prototypes for all of our local functions */static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);static void edge_tty_recv (struct device *dev, struct tty_struct *tty, unsigned char *data, int length);static void handle_new_msr (struct edgeport_port *edge_port, __u8 newMsr);static void handle_new_lsr (struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data);static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param);static int calc_baud_rate_divisor (int baud_rate, int *divisor);static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate);static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios);static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue);static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer, int writeLength);static void send_more_port_data (struct edgeport_serial *edge_serial, struct edgeport_port *edge_port);static int sram_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data);static int rom_read (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data);static int rom_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data);static void get_manufacturing_desc (struct edgeport_serial *edge_serial);static void get_boot_desc (struct edgeport_serial *edge_serial);static void load_application_firmware (struct edgeport_serial *edge_serial);static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size);// ************************************************************************// ************************************************************************// ************************************************************************// ************************************************************************/************************************************************************ * * * update_edgeport_E2PROM() Compare current versions of * * Boot ROM and Manufacture * * Descriptors with versions * * embedded in this driver * * * ************************************************************************/static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial){ __u32 BootCurVer; __u32 BootNewVer; __u8 BootMajorVersion; __u8 BootMinorVersion; __le16 BootBuildNumber; __u8 *BootImage; __u32 BootSize; struct edge_firmware_image_record *record; unsigned char *firmware; int response; switch (edge_serial->product_info.iDownloadFile) { case EDGE_DOWNLOAD_FILE_I930: BootMajorVersion = BootCodeImageVersion_GEN1.MajorVersion; BootMinorVersion = BootCodeImageVersion_GEN1.MinorVersion; BootBuildNumber = cpu_to_le16(BootCodeImageVersion_GEN1.BuildNumber); BootImage = &BootCodeImage_GEN1[0]; BootSize = sizeof( BootCodeImage_GEN1 ); break; case EDGE_DOWNLOAD_FILE_80251: BootMajorVersion = BootCodeImageVersion_GEN2.MajorVersion; BootMinorVersion = BootCodeImageVersion_GEN2.MinorVersion; BootBuildNumber = cpu_to_le16(BootCodeImageVersion_GEN2.BuildNumber); BootImage = &BootCodeImage_GEN2[0]; BootSize = sizeof( BootCodeImage_GEN2 ); break; default: return; } // Check Boot Image Version BootCurVer = (edge_serial->boot_descriptor.MajorVersion << 24) + (edge_serial->boot_descriptor.MinorVersion << 16) + le16_to_cpu(edge_serial->boot_descriptor.BuildNumber); BootNewVer = (BootMajorVersion << 24) + (BootMinorVersion << 16) + le16_to_cpu(BootBuildNumber); dbg("Current Boot Image version %d.%d.%d", edge_serial->boot_descriptor.MajorVersion, edge_serial->boot_descriptor.MinorVersion, le16_to_cpu(edge_serial->boot_descriptor.BuildNumber)); if (BootNewVer > BootCurVer) { dbg("**Update Boot Image from %d.%d.%d to %d.%d.%d", edge_serial->boot_descriptor.MajorVersion, edge_serial->boot_descriptor.MinorVersion, le16_to_cpu(edge_serial->boot_descriptor.BuildNumber), BootMajorVersion, BootMinorVersion, le16_to_cpu(BootBuildNumber)); dbg("Downloading new Boot Image"); firmware = BootImage; for (;;) { record = (struct edge_firmware_image_record *)firmware; response = rom_write (edge_serial->serial, le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len), &record->Data[0]); if (response < 0) { dev_err(&edge_serial->serial->dev->dev, "rom_write failed (%x, %x, %d)\n", le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len)); break; } firmware += sizeof (struct edge_firmware_image_record) + le16_to_cpu(record->Len); if (firmware >= &BootImage[BootSize]) { break; } } } else { dbg("Boot Image -- already up to date"); }}/************************************************************************ * * * Get string descriptor from device * * * ************************************************************************/static int get_string (struct usb_device *dev, int Id, char *string){ struct usb_string_descriptor StringDesc; struct usb_string_descriptor *pStringDesc; dbg("%s - USB String ID = %d", __FUNCTION__, Id ); if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) { return 0; } pStringDesc = kmalloc (StringDesc.bLength, GFP_KERNEL); if (!pStringDesc) { return 0; } if (!usb_get_descriptor(dev, USB_DT_STRING, Id, pStringDesc, StringDesc.bLength )) { kfree(pStringDesc); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -