// SPDX-License-Identifier: GPL-2.0+ /* * Edgeport USB Serial Converter driver * * Copyright (C) 2000-2002 Inside Out Networks, All rights reserved. * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> * * Supports the following devices: * EP/1 EP/2 EP/4 EP/21 EP/22 EP/221 EP/42 EP/421 WATCHPORT * * 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>.
*/
/* IOCTL_PRIVATE_TI_GET_MODE Definitions */ #define TI_MODE_CONFIGURING 0 /* Device has not entered start device */ #define TI_MODE_BOOT 1 /* Staying in boot mode */ #define TI_MODE_DOWNLOAD 2 /* Made it to download mode */ #define TI_MODE_TRANSITIONING 3 /* * Currently in boot mode but * transitioning to download mode
*/
/* Product information read from the Edgeport */ struct product_info { int TiMode; /* Current TI Mode */
u8 hardware_type; /* Type of hardware */
} __packed;
/* * Edgeport firmware header * * "build_number" has been set to 0 in all three of the images I have * seen, and Digi Tech Support suggests that it is safe to ignore it. * * "length" is the number of bytes of actual data following the header. * * "checksum" is the low order byte resulting from adding the values of * all the data bytes.
*/ struct edgeport_fw_hdr {
u8 major_version;
u8 minor_version;
__le16 build_number;
__le16 length;
u8 checksum;
} __packed;
struct edgeport_port {
u16 uart_base;
u16 dma_address;
u8 shadow_msr;
u8 shadow_mcr;
u8 shadow_lsr;
u8 lsr_mask;
u32 ump_read_timeout; /* * Number of milliseconds the UMP will * wait without data before completing * a read short
*/ int baud_rate; int close_pending; int lsr_event;
struct edgeport_serial *edge_serial; struct usb_serial_port *port;
u8 bUartMode; /* Port type, 0: RS232, etc. */
spinlock_t ep_lock; int ep_read_urb_state; int ep_write_urb_in_use;
};
struct edgeport_serial { struct product_info product_info;
u8 TI_I2C_Type; /* Type of I2C in UMP */
u8 TiReadI2C; /* * Set to TRUE if we have read the * I2c in Boot Mode
*/ struct mutex es_lock; int num_ports_open; struct usb_serial *serial; struct delayed_work heartbeat_work; int fw_version; bool use_heartbeat;
};
/* * Some release of Edgeport firmware "down3.bin" after version 4.80 * introduced code to automatically disconnect idle devices on some * Edgeport models after periods of inactivity, typically ~60 seconds. * This occurs without regard to whether ports on the device are open * or not. Digi International Tech Support suggested: * * 1. Adding driver "heartbeat" code to reset the firmware timer by * requesting a descriptor record every 15 seconds, which should be * effective with newer firmware versions that require it, and benign * with older versions that do not. In practice 40 seconds seems often * enough. * 2. The heartbeat code is currently required only on Edgeport/416 models.
*/ #define FW_HEARTBEAT_VERSION_CUTOFF ((4 << 8) + 80) #define FW_HEARTBEAT_SECS 40
/* Timeouts in msecs: firmware downloads take longer */ #define TI_VSEND_TIMEOUT_DEFAULT 1000 #define TI_VSEND_TIMEOUT_FW_DOWNLOAD 10000
staticint ti_vread_sync(struct usb_device *dev, u8 request, u16 value,
u16 index, void *data, int size)
{ int status;
status = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN),
value, index, data, size, 1000); if (status < 0) return status; if (status != size) {
dev_dbg(&dev->dev, "%s - wanted to read %d, but only read %d\n",
__func__, size, status); return -ECOMM;
} return 0;
}
staticint ti_vsend_sync(struct usb_device *dev, u8 request, u16 value,
u16 index, void *data, int size, int timeout)
{ int status;
/** * read_download_mem - Read edgeport memory from TI chip * @dev: usb device pointer * @start_address: Device CPU address at which to read * @length: Length of above data * @address_type: Can read both XDATA and I2C * @buffer: pointer to input data buffer
*/ staticint read_download_mem(struct usb_device *dev, int start_address, int length, u8 address_type, u8 *buffer)
{ int status = 0;
u8 read_length;
u16 be_start_address;
dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length);
/* * Read in blocks of 64 bytes * (TI firmware can't handle more than 64 byte reads)
*/ while (length) { if (length > 64)
read_length = 64; else
read_length = (u8)length;
if (read_length > 1) {
dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length);
} /* * NOTE: Must use swab as wIndex is sent in little-endian * byte order regardless of host byte order.
*/
be_start_address = swab16((u16)start_address);
status = ti_vread_sync(dev, UMPC_MEMORY_READ,
(u16)address_type,
be_start_address,
buffer, read_length);
staticint read_ram(struct usb_device *dev, int start_address, int length, u8 *buffer)
{ return read_download_mem(dev, start_address, length,
DTK_ADDR_SPACE_XDATA, buffer);
}
/* Read edgeport memory to a given block */ staticint read_boot_mem(struct edgeport_serial *serial, int start_address, int length, u8 *buffer)
{ int status = 0; int i;
for (i = 0; i < length; i++) {
status = ti_vread_sync(serial->serial->dev,
UMPC_MEMORY_READ, serial->TI_I2C_Type,
(u16)(start_address+i), &buffer[i], 0x01); if (status) {
dev_dbg(&serial->serial->dev->dev, "%s - ERROR %x\n", __func__, status); return status;
}
}
/* Write given block to TI EPROM memory */ staticint write_boot_mem(struct edgeport_serial *serial, int start_address, int length, u8 *buffer)
{ int status = 0; int i;
u8 *temp;
/* Must do a read before write */ if (!serial->TiReadI2C) {
temp = kmalloc(1, GFP_KERNEL); if (!temp) return -ENOMEM;
status = read_boot_mem(serial, 0, 1, temp);
kfree(temp); if (status) return status;
}
for (i = 0; i < length; ++i) {
status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE,
buffer[i], (u16)(i + start_address), NULL,
0, TI_VSEND_TIMEOUT_DEFAULT); if (status) return status;
}
/* Write edgeport I2C memory to TI chip */ staticint write_i2c_mem(struct edgeport_serial *serial, int start_address, int length, u8 address_type, u8 *buffer)
{ struct device *dev = &serial->serial->dev->dev; int status = 0; int write_length;
u16 be_start_address;
/* We can only send a maximum of 1 aligned byte page at a time */
/* calculate the number of bytes left in the first page */
write_length = EPROM_PAGE_SIZE -
(start_address & (EPROM_PAGE_SIZE - 1));
/* * Write first page. * * NOTE: Must use swab as wIndex is sent in little-endian byte order * regardless of host byte order.
*/
be_start_address = swab16((u16)start_address);
status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE,
(u16)address_type, be_start_address,
buffer, write_length, TI_VSEND_TIMEOUT_DEFAULT); if (status) {
dev_dbg(dev, "%s - ERROR %d\n", __func__, status); return status;
}
/* * We should be aligned now -- can write max page size bytes at a * time.
*/ while (length) { if (length > EPROM_PAGE_SIZE)
write_length = EPROM_PAGE_SIZE; else
write_length = length;
/* * Write next page. * * NOTE: Must use swab as wIndex is sent in little-endian byte * order regardless of host byte order.
*/
be_start_address = swab16((u16)start_address);
status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE,
(u16)address_type, be_start_address, buffer,
write_length, TI_VSEND_TIMEOUT_DEFAULT); if (status) {
dev_err(dev, "%s - ERROR %d\n", __func__, status); return status;
}
/* * Examine the UMP DMA registers and LSR * * Check the MSBit of the X and Y DMA byte count registers. * A zero in this bit indicates that the TX DMA buffers are empty * then check the TX Empty bit in the UART.
*/ staticint tx_active(struct edgeport_port *port)
{ int status; struct out_endpoint_desc_block *oedb;
u8 *lsr; int bytes_left = 0;
oedb = kmalloc(sizeof(*oedb), GFP_KERNEL); if (!oedb) return -ENOMEM;
/* * Sigh, that's right, just one byte, as not all platforms can * do DMA from stack
*/
lsr = kmalloc(1, GFP_KERNEL); if (!lsr) {
kfree(oedb); return -ENOMEM;
} /* Read the DMA Count Registers */
status = read_ram(port->port->serial->dev, port->dma_address, sizeof(*oedb), (void *)oedb); if (status) goto exit_is_tx_active;
/* If either buffer has data or we are transmitting then return TRUE */ if ((oedb->XByteCount & 0x80) != 0)
bytes_left += 64;
if ((*lsr & UMP_UART_LSR_TX_MASK) == 0)
bytes_left += 1;
/* We return Not Active if we get any kind of error */
exit_is_tx_active:
dev_dbg(&port->port->dev, "%s - return %d\n", __func__, bytes_left);
kfree(lsr);
kfree(oedb); return bytes_left;
}
staticint choose_config(struct usb_device *dev)
{ /* * There may be multiple configurations on this device, in which case * we would need to read and parse all of them to find out which one * we want. However, we just support one config at this point, * configuration # 1, which is Config Descriptor 0.
*/
dev_dbg(&dev->dev, "%s - Number of Interfaces = %d\n",
__func__, dev->config->desc.bNumInterfaces);
dev_dbg(&dev->dev, "%s - MAX Power = %d\n",
__func__, dev->config->desc.bMaxPower * 2);
if (dev->config->desc.bNumInterfaces != 1) {
dev_err(&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", __func__); return -ENODEV;
}
return 0;
}
staticint read_rom(struct edgeport_serial *serial, int start_address, int length, u8 *buffer)
{ int status;
if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) {
status = read_download_mem(serial->serial->dev,
start_address,
length,
serial->TI_I2C_Type,
buffer);
} else {
status = read_boot_mem(serial, start_address, length,
buffer);
} return status;
}
staticint write_rom(struct edgeport_serial *serial, int start_address, int length, u8 *buffer)
{ if (serial->product_info.TiMode == TI_MODE_BOOT) return write_boot_mem(serial, start_address, length,
buffer);
/* Read a descriptor header from I2C based on type */ staticint get_descriptor_addr(struct edgeport_serial *serial, int desc_type, struct ti_i2c_desc *rom_desc)
{ int start_address; int status;
/* Search for requested descriptor in I2C */
start_address = 2; do {
status = read_rom(serial,
start_address, sizeof(struct ti_i2c_desc),
(u8 *)rom_desc); if (status) return 0;
if (rom_desc->Type == desc_type) return start_address;
/* Make sure that the I2C image is good */ staticint check_i2c_image(struct edgeport_serial *serial)
{ struct device *dev = &serial->serial->dev->dev; int status = 0; struct ti_i2c_desc *rom_desc; int start_address = 2;
u8 *buffer;
u16 ttype;
rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); if (!rom_desc) return -ENOMEM;
if (!start_address) {
dev_dbg(dev, "%s - Edge Descriptor not found in I2C\n", __func__);
status = -ENODEV; gotoexit;
}
/* Read the descriptor data */
status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc),
le16_to_cpu(rom_desc->Size), buffer); if (status) gotoexit;
/* * In order to update the I2C firmware we must change the type 2 record * to type 0xF2. This will force the UMP to come up in Boot Mode. * Then while in boot mode, the driver will download the latest * firmware (padded to 15.5k) into the UMP ram. And finally when the * device comes back up in download mode the driver will cause the new * firmware to be copied from the UMP Ram to I2C and the firmware will * update the record type from 0xf2 to 0x02.
*/
/* * Allocate a 15.5k buffer + 2 bytes for version number (Firmware * Record)
*/
buffer_size = (((1024 * 16) - 512 ) + sizeof(struct ti_i2c_firmware_rec));
buffer = kmalloc(buffer_size, GFP_KERNEL); if (!buffer) return -ENOMEM;
/* Set entire image of 0xffs */
memset(buffer, 0xff, buffer_size);
/* Copy version number into firmware record */
firmware_rec = (struct ti_i2c_firmware_rec *)buffer;
/* Try to figure out what type of I2c we have */ staticint i2c_type_bootmode(struct edgeport_serial *serial)
{ struct device *dev = &serial->serial->dev->dev; int status;
u8 *data;
data = kmalloc(1, GFP_KERNEL); if (!data) return -ENOMEM;
/* Try to read type 2 */
status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
DTK_ADDR_SPACE_I2C_TYPE_II, 0, data, 0x01); if (status)
dev_dbg(dev, "%s - read 2 status error = %d\n", __func__, status); else
dev_dbg(dev, "%s - read 2 data = 0x%x\n", __func__, *data); if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
dev_dbg(dev, "%s - ROM_TYPE_II\n", __func__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; goto out;
}
/* Try to read type 3 */
status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
DTK_ADDR_SPACE_I2C_TYPE_III, 0, data, 0x01); if (status)
dev_dbg(dev, "%s - read 3 status error = %d\n", __func__, status); else
dev_dbg(dev, "%s - read 2 data = 0x%x\n", __func__, *data); if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
dev_dbg(dev, "%s - ROM_TYPE_III\n", __func__);
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III; goto out;
}
/* Download given firmware image to the device (IN BOOT MODE) */ staticint download_code(struct edgeport_serial *serial, u8 *image, int image_length)
{ int status = 0; int pos; int transfer; int done;
/* Transfer firmware image */ for (pos = 0; pos < image_length; ) { /* Read the next buffer from file */
transfer = image_length - pos; if (transfer > EDGE_FW_BULK_MAX_PACKET_SIZE)
transfer = EDGE_FW_BULK_MAX_PACKET_SIZE;
/* Transfer data */
status = bulk_xfer(serial->serial, &image[pos],
transfer, &done); if (status) break; /* Advance buffer pointer */
pos += done;
}
/* * DownloadTIFirmware - Download run-time operating firmware to the TI5052 * * This routine downloads the main operating code into the TI5052, using the * boot code already burned into E2PROM or ROM.
*/ staticint download_fw(struct edgeport_serial *serial)
{ struct device *dev = &serial->serial->interface->dev; int status = 0; struct usb_interface_descriptor *interface; conststruct firmware *fw; constchar *fw_name = "edgeport/down3.bin"; struct edgeport_fw_hdr *fw_hdr;
status = request_firmware(&fw, fw_name, dev); if (status) {
dev_err(dev, "Failed to load image \"%s\" err %d\n",
fw_name, status); return status;
}
if (check_fw_sanity(serial, fw)) {
status = -EINVAL; goto out;
}
fw_hdr = (struct edgeport_fw_hdr *)fw->data;
/* If on-board version is newer, "fw_version" will be updated later. */
serial->fw_version = (fw_hdr->major_version << 8) +
fw_hdr->minor_version;
/* * This routine is entered by both the BOOT mode and the Download mode * We can determine which code is running by the reading the config * descriptor and if we have only one bulk pipe it is in boot mode
*/
serial->product_info.hardware_type = HARDWARE_TYPE_TIUMP;
/* Default to type 2 i2c */
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
status = choose_config(serial->serial->dev); if (status) goto out;
interface = &serial->serial->interface->cur_altsetting->desc; if (!interface) {
dev_err(dev, "%s - no interface set, error!\n", __func__);
status = -ENODEV; goto out;
}
/* * Setup initial mode -- the default mode 0 is TI_MODE_CONFIGURING * if we have more than one endpoint we are definitely in download * mode
*/ if (interface->bNumEndpoints > 1) {
serial->product_info.TiMode = TI_MODE_DOWNLOAD;
status = do_download_mode(serial, fw);
} else { /* Otherwise we will remain in configuring mode */
serial->product_info.TiMode = TI_MODE_CONFIGURING;
status = do_boot_mode(serial, fw);
}
out:
release_firmware(fw); return status;
}
staticint do_download_mode(struct edgeport_serial *serial, conststruct firmware *fw)
{ struct device *dev = &serial->serial->interface->dev; int status = 0; int start_address; struct edge_ti_manuf_descriptor *ti_manuf_desc; int download_cur_ver; int download_new_ver; struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; struct ti_i2c_desc *rom_desc;
dev_dbg(dev, "%s - RUNNING IN DOWNLOAD MODE\n", __func__);
status = check_i2c_image(serial); if (status) {
dev_dbg(dev, "%s - DOWNLOAD MODE -- BAD I2C\n", __func__); return status;
}
/* * Validate Hardware version number * Read Manufacturing Descriptor from TI Based Edgeport
*/
ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); if (!ti_manuf_desc) return -ENOMEM;
status = get_manuf_info(serial, (u8 *)ti_manuf_desc); if (status) {
kfree(ti_manuf_desc); return status;
}
/* Check version number of ION descriptor */ if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) {
dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n",
__func__, ti_cpu_rev(ti_manuf_desc));
kfree(ti_manuf_desc); return -EINVAL;
}
/* * Validate version number * Read the descriptor data
*/
status = read_rom(serial, start_address + sizeof(struct ti_i2c_desc), sizeof(struct ti_i2c_firmware_rec),
(u8 *)firmware_version); if (status) {
kfree(firmware_version);
kfree(rom_desc);
kfree(ti_manuf_desc); return status;
}
/* * Check version number of download with current * version in I2c
*/
download_cur_ver = (firmware_version->Ver_Major << 8) +
(firmware_version->Ver_Minor);
download_new_ver = (fw_hdr->major_version << 8) +
(fw_hdr->minor_version);
/* * Check if we have an old version in the I2C and * update if necessary
*/ if (download_cur_ver < download_new_ver) {
dev_dbg(dev, "%s - Update I2C dld from %d.%d to %d.%d\n",
__func__,
firmware_version->Ver_Major,
firmware_version->Ver_Minor,
fw_hdr->major_version,
fw_hdr->minor_version);
record = kmalloc(1, GFP_KERNEL); if (!record) {
kfree(firmware_version);
kfree(rom_desc);
kfree(ti_manuf_desc); return -ENOMEM;
} /* * In order to update the I2C firmware we must * change the type 2 record to type 0xF2. This * will force the UMP to come up in Boot Mode. * Then while in boot mode, the driver will * download the latest firmware (padded to * 15.5k) into the UMP ram. Finally when the * device comes back up in download mode the * driver will cause the new firmware to be * copied from the UMP Ram to I2C and the * firmware will update the record type from * 0xf2 to 0x02.
*/
*record = I2C_DESC_TYPE_FIRMWARE_BLANK;
/* * Change the I2C Firmware record type to * 0xf2 to trigger an update
*/
status = write_rom(serial, start_address, sizeof(*record), record); if (status) {
kfree(record);
kfree(firmware_version);
kfree(rom_desc);
kfree(ti_manuf_desc); return status;
}
/* * verify the write -- must do this in order * for write to complete before we do the * hardware reset
*/
status = read_rom(serial,
start_address, sizeof(*record),
record); if (status) {
kfree(record);
kfree(firmware_version);
kfree(rom_desc);
kfree(ti_manuf_desc); return status;
}
dev_dbg(dev, "%s - Found Type BLANK FIRMWARE (Type F2) record\n",
__func__);
/* * In order to update the I2C firmware we must change * the type 2 record to type 0xF2. This will force the * UMP to come up in Boot Mode. Then while in boot * mode, the driver will download the latest firmware * (padded to 15.5k) into the UMP ram. Finally when the * device comes back up in download mode the driver * will cause the new firmware to be copied from the * UMP Ram to I2C and the firmware will update the * record type from 0xf2 to 0x02.
*/
status = build_i2c_fw_hdr(header, fw); if (status) {
kfree(vheader);
kfree(header);
kfree(rom_desc);
kfree(ti_manuf_desc); return -EINVAL;
}
/* * Update I2C with type 0xf2 record with correct * size and checksum
*/
status = write_rom(serial,
start_address,
HEADER_SIZE,
header); if (status) {
kfree(vheader);
kfree(header);
kfree(rom_desc);
kfree(ti_manuf_desc); return -EINVAL;
}
/* * verify the write -- must do this in order for * write to complete before we do the hardware reset
*/
status = read_rom(serial, start_address,
HEADER_SIZE, vheader);
dev_dbg(dev, "%s - RUNNING IN BOOT MODE\n", __func__);
/* Configure the TI device so we can use the BULK pipes for download */
status = config_boot_dev(serial->serial->dev); if (status) return status;
if (le16_to_cpu(serial->serial->dev->descriptor.idVendor)
!= USB_VENDOR_ID_ION) {
dev_dbg(dev, "%s - VID = 0x%x\n", __func__,
le16_to_cpu(serial->serial->dev->descriptor.idVendor));
serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; goto stayinbootmode;
}
/* * We have an ION device (I2c Must be programmed) * Determine I2C image type
*/ if (i2c_type_bootmode(serial)) goto stayinbootmode;
/* Check for ION Vendor ID and that the I2C is valid */ if (!check_i2c_image(serial)) { struct ti_i2c_image_header *header; int i;
u8 cs = 0;
u8 *buffer; int buffer_size;
/* * Validate Hardware version number * Read Manufacturing Descriptor from TI Based Edgeport
*/
ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); if (!ti_manuf_desc) return -ENOMEM;
status = get_manuf_info(serial, (u8 *)ti_manuf_desc); if (status) {
kfree(ti_manuf_desc); goto stayinbootmode;
}
/* Check for version 2 */ if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) {
dev_dbg(dev, "%s - Wrong CPU Rev %d (Must be 2)\n",
__func__, ti_cpu_rev(ti_manuf_desc));
kfree(ti_manuf_desc); goto stayinbootmode;
}
kfree(ti_manuf_desc);
/* * In order to update the I2C firmware we must change the type * 2 record to type 0xF2. This will force the UMP to come up * in Boot Mode. Then while in boot mode, the driver will * download the latest firmware (padded to 15.5k) into the * UMP ram. Finally when the device comes back up in download * mode the driver will cause the new firmware to be copied * from the UMP Ram to I2C and the firmware will update the * record type from 0xf2 to 0x02. * * Do we really have to copy the whole firmware image, * or could we do this in place!
*/
if (new_lsr & LSR_BREAK) /* * Parity and Framing errors only count if they * occur exclusive of a break being received.
*/
new_lsr &= (u8)(LSR_OVER_ERR | LSR_BREAK);
/* Place LSR data byte into Rx buffer */ if (lsr_data)
edge_tty_recv(edge_port->port, &data, 1);
/* update input line counters */
icount = &edge_port->port->icount; if (new_lsr & LSR_BREAK)
icount->brk++; if (new_lsr & LSR_OVER_ERR)
icount->overrun++; if (new_lsr & LSR_PAR_ERR)
icount->parity++; if (new_lsr & LSR_FRM_ERR)
icount->frame++;
}
staticvoid edge_interrupt_callback(struct urb *urb)
{ struct edgeport_serial *edge_serial = urb->context; struct usb_serial_port *port; struct edgeport_port *edge_port; struct device *dev; unsignedchar *data = urb->transfer_buffer; int length = urb->actual_length; int port_number; int function; int retval;
u8 lsr;
u8 msr; int status = urb->status;
switch (status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */
dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
__func__, status); return; default:
dev_err(&urb->dev->dev, "%s - nonzero urb status received: " "%d\n", __func__, status); gotoexit;
}
if (!length) {
dev_dbg(&urb->dev->dev, "%s - no data in urb\n", __func__); gotoexit;
}
dev = &edge_serial->serial->dev->dev;
usb_serial_debug_data(dev, __func__, length, data);
if (length != 2) {
dev_dbg(dev, "%s - expecting packet of size 2, got %d\n", __func__, length); gotoexit;
}
port_number = TIUMP_GET_PORT_FROM_CODE(data[0]);
function = TIUMP_GET_FUNC_FROM_CODE(data[0]);
dev_dbg(dev, "%s - port_number %d, function %d, info 0x%x\n", __func__,
port_number, function, data[1]);
if (port_number >= edge_serial->serial->num_ports) {
dev_err(dev, "bad port number %d\n", port_number); gotoexit;
}
port = edge_serial->serial->port[port_number];
edge_port = usb_get_serial_port_data(port); if (!edge_port) {
dev_dbg(dev, "%s - edge_port not found\n", __func__); return;
} switch (function) { case TIUMP_INTERRUPT_CODE_LSR:
lsr = map_line_status(data[1]); if (lsr & UMP_UART_LSR_DATA_MASK) { /* * Save the LSR event for bulk read completion routine
*/
dev_dbg(dev, "%s - LSR Event Port %u LSR Status = %02x\n",
__func__, port_number, lsr);
edge_port->lsr_event = 1;
edge_port->lsr_mask = lsr;
} else {
dev_dbg(dev, "%s - ===== Port %d LSR Status = %02x ======\n",
__func__, port_number, lsr);
handle_new_lsr(edge_port, 0, lsr, 0);
} break;
case TIUMP_INTERRUPT_CODE_MSR: /* MSR */ /* Copy MSR from UMP */
msr = data[1];
dev_dbg(dev, "%s - ===== Port %u MSR Status = %02x ======\n",
__func__, port_number, msr);
handle_new_msr(edge_port, msr); break;
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval)
dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
__func__, retval);
}
staticvoid edge_bulk_in_callback(struct urb *urb)
{ struct edgeport_port *edge_port = urb->context; struct device *dev = &edge_port->port->dev; unsignedchar *data = urb->transfer_buffer; unsignedlong flags; int retval = 0; int port_number; int status = urb->status;
switch (status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */
dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); return; default:
dev_err(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", __func__, status);
}
if (urb->actual_length > 0 && edge_port->lsr_event) {
edge_port->lsr_event = 0;
dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n",
__func__, port_number, edge_port->lsr_mask, *data);
handle_new_lsr(edge_port, 1, edge_port->lsr_mask, *data); /* Adjust buffer length/pointer */
--urb->actual_length;
++data;
}
if (urb->actual_length) {
usb_serial_debug_data(dev, __func__, urb->actual_length, data); if (edge_port->close_pending)
dev_dbg(dev, "%s - close pending, dropping data on the floor\n",
__func__); else
edge_tty_recv(edge_port->port, data,
urb->actual_length);
edge_port->port->icount.rx += urb->actual_length;
}
switch (status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */
dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n",
__func__, status); return; default:
dev_err_console(port, "%s - nonzero write bulk status " "received: %d\n", __func__, status);
}
/* send any buffered data */
tty = tty_port_tty_get(&port->port);
edge_send(port, tty);
tty_kref_put(tty);
}
/* Tell TI to open and start the port */
status = send_port_cmd(port, UMPC_OPEN_PORT, open_settings, NULL, 0); if (status) {
dev_err(&port->dev, "%s - cannot send open command, %d\n",
__func__, status); return status;
}
/* Start the DMA? */
status = send_port_cmd(port, UMPC_START_PORT, 0, NULL, 0); if (status) {
dev_err(&port->dev, "%s - cannot send start DMA command, %d\n",
__func__, status); return status;
}
/* Clear TX and RX buffers in UMP */
status = purge_port(port, UMP_PORT_DIR_OUT | UMP_PORT_DIR_IN); if (status) {
dev_err(&port->dev, "%s - cannot send clear buffers command, %d\n",
__func__, status); return status;
}
edge_serial = edge_port->edge_serial; if (mutex_lock_interruptible(&edge_serial->es_lock)) return -ERESTARTSYS; if (edge_serial->num_ports_open == 0) { /* we are the first port to open, post the interrupt urb */
urb = edge_serial->serial->port[0]->interrupt_in_urb;
urb->context = edge_serial;
status = usb_submit_urb(urb, GFP_KERNEL); if (status) {
dev_err(&port->dev, "%s - usb_submit_urb failed with value %d\n",
__func__, status); goto release_es_lock;
}
}
/* * reset the data toggle on the bulk endpoints to work around bug in * host controllers where things get out of sync some times
*/
usb_clear_halt(dev, port->write_urb->pipe);
usb_clear_halt(dev, port->read_urb->pipe);
/* start up our bulk read urb */
urb = port->read_urb;
edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
urb->context = edge_port;
status = usb_submit_urb(urb, GFP_KERNEL); if (status) {
dev_err(&port->dev, "%s - read bulk usb_submit_urb failed with value %d\n",
__func__, status); goto unlink_int_urb;
}
mutex_lock(&edge_serial->es_lock);
--edge_port->edge_serial->num_ports_open; if (edge_port->edge_serial->num_ports_open <= 0) { /* last port is now closed, let's shut down our interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
edge_port->edge_serial->num_ports_open = 0;
}
mutex_unlock(&edge_serial->es_lock);
edge_port->close_pending = 0;
}
/* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsignedchar stop_char = STOP_CHAR(tty);
status = edge_write(tty, port, &stop_char, 1); if (status <= 0) {
dev_err(&port->dev, "%s - failed to write stop character, %d\n", __func__, status);
}
}
/* * if we are implementing RTS/CTS, stop reads * and the Edgeport will clear the RTS line
*/ if (C_CRTSCTS(tty))
stop_read(edge_port);
/* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsignedchar start_char = START_CHAR(tty);
status = edge_write(tty, port, &start_char, 1); if (status <= 0) {
dev_err(&port->dev, "%s - failed to write start character, %d\n", __func__, status);
}
} /* * if we are implementing RTS/CTS, restart reads * are the Edgeport will assert the RTS line
*/ if (C_CRTSCTS(tty)) {
status = restart_read(edge_port); if (status)
dev_err(&port->dev, "%s - read bulk usb_submit_urb failed: %d\n",
__func__, status);
}
/* These flags must be set */
config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT;
config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR;
config->bUartMode = (u8)(edge_port->bUartMode);
switch (cflag & CSIZE) { case CS5:
config->bDataBits = UMP_UART_CHAR5BITS;
dev_dbg(dev, "%s - data bits = 5\n", __func__); break; case CS6:
config->bDataBits = UMP_UART_CHAR6BITS;
dev_dbg(dev, "%s - data bits = 6\n", __func__); break; case CS7:
config->bDataBits = UMP_UART_CHAR7BITS;
dev_dbg(dev, "%s - data bits = 7\n", __func__); break; default: case CS8:
config->bDataBits = UMP_UART_CHAR8BITS;
dev_dbg(dev, "%s - data bits = 8\n", __func__); break;
}
/* figure out the flow control settings */ if (cflag & CRTSCTS) {
config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW;
config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW;
dev_dbg(dev, "%s - RTS/CTS is enabled\n", __func__);
} else {
dev_dbg(dev, "%s - RTS/CTS is disabled\n", __func__);
restart_read(edge_port);
}
/* * if we are implementing XON/XOFF, set the start and stop * character in the device
*/
config->cXon = START_CHAR(tty);
config->cXoff = STOP_CHAR(tty);
/* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) {
config->wFlags |= UMP_MASK_UART_FLAGS_IN_X;
dev_dbg(dev, "%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n",
__func__, config->cXon, config->cXoff);
} else
dev_dbg(dev, "%s - INBOUND XON/XOFF is disabled\n", __func__);
/* if we are implementing OUTBOUND XON/XOFF */ if (I_IXON(tty)) {
config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X;
dev_dbg(dev, "%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n",
__func__, config->cXon, config->cXoff);
} else
dev_dbg(dev, "%s - OUTBOUND XON/XOFF is disabled\n", __func__);
tty->termios.c_cflag &= ~CMSPAR;
/* Round the baud rate */
baud = tty_get_baud_rate(tty); if (!baud) { /* pick a default, any default... */
baud = 9600;
} else { /* Avoid a zero divisor. */
baud = min(baud, 461550);
tty_encode_baud_rate(tty, baud, baud);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.