162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Infinity Unlimited USB Phoenix driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2010 James Courtier-Dutton (James@superbug.co.uk) 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás) 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * And tested with help of WB Electronics 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/tty.h> 1762306a36Sopenharmony_ci#include <linux/tty_driver.h> 1862306a36Sopenharmony_ci#include <linux/tty_flip.h> 1962306a36Sopenharmony_ci#include <linux/serial.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/moduleparam.h> 2262306a36Sopenharmony_ci#include <linux/spinlock.h> 2362306a36Sopenharmony_ci#include <linux/uaccess.h> 2462306a36Sopenharmony_ci#include <linux/usb.h> 2562306a36Sopenharmony_ci#include <linux/usb/serial.h> 2662306a36Sopenharmony_ci#include "iuu_phoenix.h" 2762306a36Sopenharmony_ci#include <linux/random.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const struct usb_device_id id_table[] = { 3262306a36Sopenharmony_ci {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)}, 3362306a36Sopenharmony_ci {} /* Terminating entry */ 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* turbo parameter */ 3862306a36Sopenharmony_cistatic int boost = 100; 3962306a36Sopenharmony_cistatic int clockmode = 1; 4062306a36Sopenharmony_cistatic int cdmode = 1; 4162306a36Sopenharmony_cistatic int iuu_cardin; 4262306a36Sopenharmony_cistatic int iuu_cardout; 4362306a36Sopenharmony_cistatic bool xmas; 4462306a36Sopenharmony_cistatic int vcc_default = 5; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int iuu_create_sysfs_attrs(struct usb_serial_port *port); 4762306a36Sopenharmony_cistatic int iuu_remove_sysfs_attrs(struct usb_serial_port *port); 4862306a36Sopenharmony_cistatic void read_rxcmd_callback(struct urb *urb); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistruct iuu_private { 5162306a36Sopenharmony_ci spinlock_t lock; /* store irq state */ 5262306a36Sopenharmony_ci u8 line_status; 5362306a36Sopenharmony_ci int tiostatus; /* store IUART SIGNAL for tiocmget call */ 5462306a36Sopenharmony_ci u8 reset; /* if 1 reset is needed */ 5562306a36Sopenharmony_ci int poll; /* number of poll */ 5662306a36Sopenharmony_ci u8 *writebuf; /* buffer for writing to device */ 5762306a36Sopenharmony_ci int writelen; /* num of byte to write to device */ 5862306a36Sopenharmony_ci u8 *buf; /* used for initialize speed */ 5962306a36Sopenharmony_ci u8 len; 6062306a36Sopenharmony_ci int vcc; /* vcc (either 3 or 5 V) */ 6162306a36Sopenharmony_ci u32 boost; 6262306a36Sopenharmony_ci u32 clk; 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int iuu_port_probe(struct usb_serial_port *port) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct iuu_private *priv; 6862306a36Sopenharmony_ci int ret; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL); 7162306a36Sopenharmony_ci if (!priv) 7262306a36Sopenharmony_ci return -ENOMEM; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci priv->buf = kzalloc(256, GFP_KERNEL); 7562306a36Sopenharmony_ci if (!priv->buf) { 7662306a36Sopenharmony_ci kfree(priv); 7762306a36Sopenharmony_ci return -ENOMEM; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci priv->writebuf = kzalloc(256, GFP_KERNEL); 8162306a36Sopenharmony_ci if (!priv->writebuf) { 8262306a36Sopenharmony_ci kfree(priv->buf); 8362306a36Sopenharmony_ci kfree(priv); 8462306a36Sopenharmony_ci return -ENOMEM; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci priv->vcc = vcc_default; 8862306a36Sopenharmony_ci spin_lock_init(&priv->lock); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci usb_set_serial_port_data(port, priv); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci ret = iuu_create_sysfs_attrs(port); 9362306a36Sopenharmony_ci if (ret) { 9462306a36Sopenharmony_ci kfree(priv->writebuf); 9562306a36Sopenharmony_ci kfree(priv->buf); 9662306a36Sopenharmony_ci kfree(priv); 9762306a36Sopenharmony_ci return ret; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void iuu_port_remove(struct usb_serial_port *port) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci iuu_remove_sysfs_attrs(port); 10862306a36Sopenharmony_ci kfree(priv->writebuf); 10962306a36Sopenharmony_ci kfree(priv->buf); 11062306a36Sopenharmony_ci kfree(priv); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int iuu_tiocmset(struct tty_struct *tty, 11462306a36Sopenharmony_ci unsigned int set, unsigned int clear) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 11762306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 11862306a36Sopenharmony_ci unsigned long flags; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* FIXME: locking on tiomstatus */ 12162306a36Sopenharmony_ci dev_dbg(&port->dev, "%s msg : SET = 0x%04x, CLEAR = 0x%04x\n", 12262306a36Sopenharmony_ci __func__, set, clear); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if ((set & TIOCM_RTS) && !(priv->tiostatus == TIOCM_RTS)) { 12762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s TIOCMSET RESET called !!!\n", __func__); 12862306a36Sopenharmony_ci priv->reset = 1; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci if (set & TIOCM_RTS) 13162306a36Sopenharmony_ci priv->tiostatus = TIOCM_RTS; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* This is used to provide a carrier detect mechanism 13862306a36Sopenharmony_ci * When a card is present, the response is 0x00 13962306a36Sopenharmony_ci * When no card , the reader respond with TIOCM_CD 14062306a36Sopenharmony_ci * This is known as CD autodetect mechanism 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_cistatic int iuu_tiocmget(struct tty_struct *tty) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 14562306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 14662306a36Sopenharmony_ci unsigned long flags; 14762306a36Sopenharmony_ci int rc; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 15062306a36Sopenharmony_ci rc = priv->tiostatus; 15162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return rc; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void iuu_rxcmd(struct urb *urb) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 15962306a36Sopenharmony_ci int status = urb->status; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (status) { 16262306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); 16362306a36Sopenharmony_ci /* error stop all */ 16462306a36Sopenharmony_ci return; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); 16962306a36Sopenharmony_ci usb_fill_bulk_urb(port->write_urb, port->serial->dev, 17062306a36Sopenharmony_ci usb_sndbulkpipe(port->serial->dev, 17162306a36Sopenharmony_ci port->bulk_out_endpointAddress), 17262306a36Sopenharmony_ci port->write_urb->transfer_buffer, 1, 17362306a36Sopenharmony_ci read_rxcmd_callback, port); 17462306a36Sopenharmony_ci usb_submit_urb(port->write_urb, GFP_ATOMIC); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int iuu_reset(struct usb_serial_port *port, u8 wt) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 18062306a36Sopenharmony_ci int result; 18162306a36Sopenharmony_ci char *buf_ptr = port->write_urb->transfer_buffer; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* Prepare the reset sequence */ 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci *buf_ptr++ = IUU_RST_SET; 18662306a36Sopenharmony_ci *buf_ptr++ = IUU_DELAY_MS; 18762306a36Sopenharmony_ci *buf_ptr++ = wt; 18862306a36Sopenharmony_ci *buf_ptr = IUU_RST_CLEAR; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* send the sequence */ 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci usb_fill_bulk_urb(port->write_urb, 19362306a36Sopenharmony_ci port->serial->dev, 19462306a36Sopenharmony_ci usb_sndbulkpipe(port->serial->dev, 19562306a36Sopenharmony_ci port->bulk_out_endpointAddress), 19662306a36Sopenharmony_ci port->write_urb->transfer_buffer, 4, iuu_rxcmd, port); 19762306a36Sopenharmony_ci result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 19862306a36Sopenharmony_ci priv->reset = 0; 19962306a36Sopenharmony_ci return result; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* Status Function 20362306a36Sopenharmony_ci * Return value is 20462306a36Sopenharmony_ci * 0x00 = no card 20562306a36Sopenharmony_ci * 0x01 = smartcard 20662306a36Sopenharmony_ci * 0x02 = sim card 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic void iuu_update_status_callback(struct urb *urb) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 21162306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 21262306a36Sopenharmony_ci u8 *st; 21362306a36Sopenharmony_ci int status = urb->status; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (status) { 21662306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); 21762306a36Sopenharmony_ci /* error stop all */ 21862306a36Sopenharmony_ci return; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci st = urb->transfer_buffer; 22262306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - enter\n", __func__); 22362306a36Sopenharmony_ci if (urb->actual_length == 1) { 22462306a36Sopenharmony_ci switch (st[0]) { 22562306a36Sopenharmony_ci case 0x1: 22662306a36Sopenharmony_ci priv->tiostatus = iuu_cardout; 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci case 0x0: 22962306a36Sopenharmony_ci priv->tiostatus = iuu_cardin; 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci default: 23262306a36Sopenharmony_ci priv->tiostatus = iuu_cardin; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci iuu_rxcmd(urb); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic void iuu_status_callback(struct urb *urb) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 24162306a36Sopenharmony_ci int status = urb->status; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); 24462306a36Sopenharmony_ci usb_fill_bulk_urb(port->read_urb, port->serial->dev, 24562306a36Sopenharmony_ci usb_rcvbulkpipe(port->serial->dev, 24662306a36Sopenharmony_ci port->bulk_in_endpointAddress), 24762306a36Sopenharmony_ci port->read_urb->transfer_buffer, 256, 24862306a36Sopenharmony_ci iuu_update_status_callback, port); 24962306a36Sopenharmony_ci usb_submit_urb(port->read_urb, GFP_ATOMIC); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int iuu_status(struct usb_serial_port *port) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci int result; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1); 25762306a36Sopenharmony_ci usb_fill_bulk_urb(port->write_urb, port->serial->dev, 25862306a36Sopenharmony_ci usb_sndbulkpipe(port->serial->dev, 25962306a36Sopenharmony_ci port->bulk_out_endpointAddress), 26062306a36Sopenharmony_ci port->write_urb->transfer_buffer, 1, 26162306a36Sopenharmony_ci iuu_status_callback, port); 26262306a36Sopenharmony_ci result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 26362306a36Sopenharmony_ci return result; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci int status; 27062306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 27162306a36Sopenharmony_ci int actual = 0; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* send the data out the bulk port */ 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci status = 27662306a36Sopenharmony_ci usb_bulk_msg(serial->dev, 27762306a36Sopenharmony_ci usb_sndbulkpipe(serial->dev, 27862306a36Sopenharmony_ci port->bulk_out_endpointAddress), buf, 27962306a36Sopenharmony_ci count, &actual, 1000); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) 28262306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status); 28362306a36Sopenharmony_ci else 28462306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - write OK !\n", __func__); 28562306a36Sopenharmony_ci return status; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci int status; 29162306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 29262306a36Sopenharmony_ci int actual = 0; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* send the data out the bulk port */ 29562306a36Sopenharmony_ci status = 29662306a36Sopenharmony_ci usb_bulk_msg(serial->dev, 29762306a36Sopenharmony_ci usb_rcvbulkpipe(serial->dev, 29862306a36Sopenharmony_ci port->bulk_in_endpointAddress), buf, 29962306a36Sopenharmony_ci count, &actual, 1000); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) 30262306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status); 30362306a36Sopenharmony_ci else 30462306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - read OK !\n", __func__); 30562306a36Sopenharmony_ci return status; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int iuu_led(struct usb_serial_port *port, unsigned int R, 30962306a36Sopenharmony_ci unsigned int G, unsigned int B, u8 f) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci int status; 31262306a36Sopenharmony_ci u8 *buf; 31362306a36Sopenharmony_ci buf = kmalloc(8, GFP_KERNEL); 31462306a36Sopenharmony_ci if (!buf) 31562306a36Sopenharmony_ci return -ENOMEM; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci buf[0] = IUU_SET_LED; 31862306a36Sopenharmony_ci buf[1] = R & 0xFF; 31962306a36Sopenharmony_ci buf[2] = (R >> 8) & 0xFF; 32062306a36Sopenharmony_ci buf[3] = G & 0xFF; 32162306a36Sopenharmony_ci buf[4] = (G >> 8) & 0xFF; 32262306a36Sopenharmony_ci buf[5] = B & 0xFF; 32362306a36Sopenharmony_ci buf[6] = (B >> 8) & 0xFF; 32462306a36Sopenharmony_ci buf[7] = f; 32562306a36Sopenharmony_ci status = bulk_immediate(port, buf, 8); 32662306a36Sopenharmony_ci kfree(buf); 32762306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) 32862306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - led error status = %2x\n", __func__, status); 32962306a36Sopenharmony_ci else 33062306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - led OK !\n", __func__); 33162306a36Sopenharmony_ci return IUU_OPERATION_OK; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1, 33562306a36Sopenharmony_ci u8 b2, u8 freq) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci *buf++ = IUU_SET_LED; 33862306a36Sopenharmony_ci *buf++ = r1; 33962306a36Sopenharmony_ci *buf++ = r2; 34062306a36Sopenharmony_ci *buf++ = g1; 34162306a36Sopenharmony_ci *buf++ = g2; 34262306a36Sopenharmony_ci *buf++ = b1; 34362306a36Sopenharmony_ci *buf++ = b2; 34462306a36Sopenharmony_ci *buf = freq; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void iuu_led_activity_on(struct urb *urb) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 35062306a36Sopenharmony_ci char *buf_ptr = port->write_urb->transfer_buffer; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (xmas) { 35362306a36Sopenharmony_ci buf_ptr[0] = IUU_SET_LED; 35462306a36Sopenharmony_ci get_random_bytes(buf_ptr + 1, 6); 35562306a36Sopenharmony_ci buf_ptr[7] = 1; 35662306a36Sopenharmony_ci } else { 35762306a36Sopenharmony_ci iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci usb_fill_bulk_urb(port->write_urb, port->serial->dev, 36162306a36Sopenharmony_ci usb_sndbulkpipe(port->serial->dev, 36262306a36Sopenharmony_ci port->bulk_out_endpointAddress), 36362306a36Sopenharmony_ci port->write_urb->transfer_buffer, 8 , 36462306a36Sopenharmony_ci iuu_rxcmd, port); 36562306a36Sopenharmony_ci usb_submit_urb(port->write_urb, GFP_ATOMIC); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic void iuu_led_activity_off(struct urb *urb) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 37162306a36Sopenharmony_ci char *buf_ptr = port->write_urb->transfer_buffer; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (xmas) { 37462306a36Sopenharmony_ci iuu_rxcmd(urb); 37562306a36Sopenharmony_ci return; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci usb_fill_bulk_urb(port->write_urb, port->serial->dev, 38162306a36Sopenharmony_ci usb_sndbulkpipe(port->serial->dev, 38262306a36Sopenharmony_ci port->bulk_out_endpointAddress), 38362306a36Sopenharmony_ci port->write_urb->transfer_buffer, 8 , 38462306a36Sopenharmony_ci iuu_rxcmd, port); 38562306a36Sopenharmony_ci usb_submit_urb(port->write_urb, GFP_ATOMIC); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int iuu_clk(struct usb_serial_port *port, int dwFrq) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci int status; 39362306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 39462306a36Sopenharmony_ci int Count = 0; 39562306a36Sopenharmony_ci u8 FrqGenAdr = 0x69; 39662306a36Sopenharmony_ci u8 DIV = 0; /* 8bit */ 39762306a36Sopenharmony_ci u8 XDRV = 0; /* 8bit */ 39862306a36Sopenharmony_ci u8 PUMP = 0; /* 3bit */ 39962306a36Sopenharmony_ci u8 PBmsb = 0; /* 2bit */ 40062306a36Sopenharmony_ci u8 PBlsb = 0; /* 8bit */ 40162306a36Sopenharmony_ci u8 PO = 0; /* 1bit */ 40262306a36Sopenharmony_ci u8 Q = 0; /* 7bit */ 40362306a36Sopenharmony_ci /* 24bit = 3bytes */ 40462306a36Sopenharmony_ci unsigned int P = 0; 40562306a36Sopenharmony_ci unsigned int P2 = 0; 40662306a36Sopenharmony_ci int frq = (int)dwFrq; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (frq == 0) { 40962306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; 41062306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 41162306a36Sopenharmony_ci priv->buf[Count++] = 0x09; 41262306a36Sopenharmony_ci priv->buf[Count++] = 0x00; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci status = bulk_immediate(port, (u8 *) priv->buf, Count); 41562306a36Sopenharmony_ci if (status != 0) { 41662306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - write error\n", __func__); 41762306a36Sopenharmony_ci return status; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci } else if (frq == 3579000) { 42062306a36Sopenharmony_ci DIV = 100; 42162306a36Sopenharmony_ci P = 1193; 42262306a36Sopenharmony_ci Q = 40; 42362306a36Sopenharmony_ci XDRV = 0; 42462306a36Sopenharmony_ci } else if (frq == 3680000) { 42562306a36Sopenharmony_ci DIV = 105; 42662306a36Sopenharmony_ci P = 161; 42762306a36Sopenharmony_ci Q = 5; 42862306a36Sopenharmony_ci XDRV = 0; 42962306a36Sopenharmony_ci } else if (frq == 6000000) { 43062306a36Sopenharmony_ci DIV = 66; 43162306a36Sopenharmony_ci P = 66; 43262306a36Sopenharmony_ci Q = 2; 43362306a36Sopenharmony_ci XDRV = 0x28; 43462306a36Sopenharmony_ci } else { 43562306a36Sopenharmony_ci unsigned int result = 0; 43662306a36Sopenharmony_ci unsigned int tmp = 0; 43762306a36Sopenharmony_ci unsigned int check; 43862306a36Sopenharmony_ci unsigned int check2; 43962306a36Sopenharmony_ci char found = 0x00; 44062306a36Sopenharmony_ci unsigned int lQ = 2; 44162306a36Sopenharmony_ci unsigned int lP = 2055; 44262306a36Sopenharmony_ci unsigned int lDiv = 4; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci for (lQ = 2; lQ <= 47 && !found; lQ++) 44562306a36Sopenharmony_ci for (lP = 2055; lP >= 8 && !found; lP--) 44662306a36Sopenharmony_ci for (lDiv = 4; lDiv <= 127 && !found; lDiv++) { 44762306a36Sopenharmony_ci tmp = (12000000 / lDiv) * (lP / lQ); 44862306a36Sopenharmony_ci if (abs((int)(tmp - frq)) < 44962306a36Sopenharmony_ci abs((int)(frq - result))) { 45062306a36Sopenharmony_ci check2 = (12000000 / lQ); 45162306a36Sopenharmony_ci if (check2 < 250000) 45262306a36Sopenharmony_ci continue; 45362306a36Sopenharmony_ci check = (12000000 / lQ) * lP; 45462306a36Sopenharmony_ci if (check > 400000000) 45562306a36Sopenharmony_ci continue; 45662306a36Sopenharmony_ci if (check < 100000000) 45762306a36Sopenharmony_ci continue; 45862306a36Sopenharmony_ci if (lDiv < 4 || lDiv > 127) 45962306a36Sopenharmony_ci continue; 46062306a36Sopenharmony_ci result = tmp; 46162306a36Sopenharmony_ci P = lP; 46262306a36Sopenharmony_ci DIV = lDiv; 46362306a36Sopenharmony_ci Q = lQ; 46462306a36Sopenharmony_ci if (result == frq) 46562306a36Sopenharmony_ci found = 0x01; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci P2 = ((P - PO) / 2) - 4; 47062306a36Sopenharmony_ci PUMP = 0x04; 47162306a36Sopenharmony_ci PBmsb = (P2 >> 8 & 0x03); 47262306a36Sopenharmony_ci PBlsb = P2 & 0xFF; 47362306a36Sopenharmony_ci PO = (P >> 10) & 0x01; 47462306a36Sopenharmony_ci Q = Q - 2; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 47762306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 47862306a36Sopenharmony_ci priv->buf[Count++] = 0x09; 47962306a36Sopenharmony_ci priv->buf[Count++] = 0x20; /* Adr = 0x09 */ 48062306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 48162306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 48262306a36Sopenharmony_ci priv->buf[Count++] = 0x0C; 48362306a36Sopenharmony_ci priv->buf[Count++] = DIV; /* Adr = 0x0C */ 48462306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 48562306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 48662306a36Sopenharmony_ci priv->buf[Count++] = 0x12; 48762306a36Sopenharmony_ci priv->buf[Count++] = XDRV; /* Adr = 0x12 */ 48862306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 48962306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 49062306a36Sopenharmony_ci priv->buf[Count++] = 0x13; 49162306a36Sopenharmony_ci priv->buf[Count++] = 0x6B; /* Adr = 0x13 */ 49262306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 49362306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 49462306a36Sopenharmony_ci priv->buf[Count++] = 0x40; 49562306a36Sopenharmony_ci priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) | 49662306a36Sopenharmony_ci (PBmsb & 0x03); /* Adr = 0x40 */ 49762306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 49862306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 49962306a36Sopenharmony_ci priv->buf[Count++] = 0x41; 50062306a36Sopenharmony_ci priv->buf[Count++] = PBlsb; /* Adr = 0x41 */ 50162306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 50262306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 50362306a36Sopenharmony_ci priv->buf[Count++] = 0x42; 50462306a36Sopenharmony_ci priv->buf[Count++] = Q | (((PO & 0x01) << 7)); /* Adr = 0x42 */ 50562306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 50662306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 50762306a36Sopenharmony_ci priv->buf[Count++] = 0x44; 50862306a36Sopenharmony_ci priv->buf[Count++] = (char)0xFF; /* Adr = 0x44 */ 50962306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 51062306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 51162306a36Sopenharmony_ci priv->buf[Count++] = 0x45; 51262306a36Sopenharmony_ci priv->buf[Count++] = (char)0xFE; /* Adr = 0x45 */ 51362306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 51462306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 51562306a36Sopenharmony_ci priv->buf[Count++] = 0x46; 51662306a36Sopenharmony_ci priv->buf[Count++] = 0x7F; /* Adr = 0x46 */ 51762306a36Sopenharmony_ci priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ 51862306a36Sopenharmony_ci priv->buf[Count++] = FrqGenAdr << 1; 51962306a36Sopenharmony_ci priv->buf[Count++] = 0x47; 52062306a36Sopenharmony_ci priv->buf[Count++] = (char)0x84; /* Adr = 0x47 */ 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci status = bulk_immediate(port, (u8 *) priv->buf, Count); 52362306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) 52462306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - write error\n", __func__); 52562306a36Sopenharmony_ci return status; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int iuu_uart_flush(struct usb_serial_port *port) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct device *dev = &port->dev; 53162306a36Sopenharmony_ci int i; 53262306a36Sopenharmony_ci int status; 53362306a36Sopenharmony_ci u8 *rxcmd; 53462306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0) 53762306a36Sopenharmony_ci return -EIO; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci rxcmd = kmalloc(1, GFP_KERNEL); 54062306a36Sopenharmony_ci if (!rxcmd) 54162306a36Sopenharmony_ci return -ENOMEM; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci rxcmd[0] = IUU_UART_RX; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 54662306a36Sopenharmony_ci status = bulk_immediate(port, rxcmd, 1); 54762306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) { 54862306a36Sopenharmony_ci dev_dbg(dev, "%s - uart_flush_write error\n", __func__); 54962306a36Sopenharmony_ci goto out_free; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci status = read_immediate(port, &priv->len, 1); 55362306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) { 55462306a36Sopenharmony_ci dev_dbg(dev, "%s - uart_flush_read error\n", __func__); 55562306a36Sopenharmony_ci goto out_free; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (priv->len > 0) { 55962306a36Sopenharmony_ci dev_dbg(dev, "%s - uart_flush datalen is : %i\n", __func__, priv->len); 56062306a36Sopenharmony_ci status = read_immediate(port, priv->buf, priv->len); 56162306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) { 56262306a36Sopenharmony_ci dev_dbg(dev, "%s - uart_flush_read error\n", __func__); 56362306a36Sopenharmony_ci goto out_free; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci dev_dbg(dev, "%s - uart_flush_read OK!\n", __func__); 56862306a36Sopenharmony_ci iuu_led(port, 0, 0xF000, 0, 0xFF); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ciout_free: 57162306a36Sopenharmony_ci kfree(rxcmd); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return status; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic void read_buf_callback(struct urb *urb) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 57962306a36Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 58062306a36Sopenharmony_ci int status = urb->status; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (status) { 58362306a36Sopenharmony_ci if (status == -EPROTO) { 58462306a36Sopenharmony_ci /* reschedule needed */ 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci return; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - %i chars to write\n", __func__, urb->actual_length); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (urb->actual_length) { 59262306a36Sopenharmony_ci tty_insert_flip_string(&port->port, data, urb->actual_length); 59362306a36Sopenharmony_ci tty_flip_buffer_push(&port->port); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci iuu_led_activity_on(urb); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int iuu_bulk_write(struct usb_serial_port *port) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 60162306a36Sopenharmony_ci unsigned long flags; 60262306a36Sopenharmony_ci int result; 60362306a36Sopenharmony_ci int buf_len; 60462306a36Sopenharmony_ci char *buf_ptr = port->write_urb->transfer_buffer; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 60762306a36Sopenharmony_ci *buf_ptr++ = IUU_UART_ESC; 60862306a36Sopenharmony_ci *buf_ptr++ = IUU_UART_TX; 60962306a36Sopenharmony_ci *buf_ptr++ = priv->writelen; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci memcpy(buf_ptr, priv->writebuf, priv->writelen); 61262306a36Sopenharmony_ci buf_len = priv->writelen; 61362306a36Sopenharmony_ci priv->writelen = 0; 61462306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 61562306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - writing %i chars : %*ph\n", __func__, 61662306a36Sopenharmony_ci buf_len, buf_len, buf_ptr); 61762306a36Sopenharmony_ci usb_fill_bulk_urb(port->write_urb, port->serial->dev, 61862306a36Sopenharmony_ci usb_sndbulkpipe(port->serial->dev, 61962306a36Sopenharmony_ci port->bulk_out_endpointAddress), 62062306a36Sopenharmony_ci port->write_urb->transfer_buffer, buf_len + 3, 62162306a36Sopenharmony_ci iuu_rxcmd, port); 62262306a36Sopenharmony_ci result = usb_submit_urb(port->write_urb, GFP_ATOMIC); 62362306a36Sopenharmony_ci usb_serial_port_softint(port); 62462306a36Sopenharmony_ci return result; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic int iuu_read_buf(struct usb_serial_port *port, int len) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci int result; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci usb_fill_bulk_urb(port->read_urb, port->serial->dev, 63262306a36Sopenharmony_ci usb_rcvbulkpipe(port->serial->dev, 63362306a36Sopenharmony_ci port->bulk_in_endpointAddress), 63462306a36Sopenharmony_ci port->read_urb->transfer_buffer, len, 63562306a36Sopenharmony_ci read_buf_callback, port); 63662306a36Sopenharmony_ci result = usb_submit_urb(port->read_urb, GFP_ATOMIC); 63762306a36Sopenharmony_ci return result; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic void iuu_uart_read_callback(struct urb *urb) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 64362306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 64462306a36Sopenharmony_ci unsigned long flags; 64562306a36Sopenharmony_ci int status = urb->status; 64662306a36Sopenharmony_ci int len = 0; 64762306a36Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 64862306a36Sopenharmony_ci priv->poll++; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (status) { 65162306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); 65262306a36Sopenharmony_ci /* error stop all */ 65362306a36Sopenharmony_ci return; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (urb->actual_length == 1) 65762306a36Sopenharmony_ci len = (int) data[0]; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (urb->actual_length > 1) { 66062306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - urb->actual_length = %i\n", __func__, 66162306a36Sopenharmony_ci urb->actual_length); 66262306a36Sopenharmony_ci return; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci /* if len > 0 call readbuf */ 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (len > 0) { 66762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - call read buf - len to read is %i\n", 66862306a36Sopenharmony_ci __func__, len); 66962306a36Sopenharmony_ci status = iuu_read_buf(port, len); 67062306a36Sopenharmony_ci return; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci /* need to update status ? */ 67362306a36Sopenharmony_ci if (priv->poll > 99) { 67462306a36Sopenharmony_ci status = iuu_status(port); 67562306a36Sopenharmony_ci priv->poll = 0; 67662306a36Sopenharmony_ci return; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* reset waiting ? */ 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (priv->reset == 1) { 68262306a36Sopenharmony_ci status = iuu_reset(port, 0xC); 68362306a36Sopenharmony_ci return; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci /* Writebuf is waiting */ 68662306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 68762306a36Sopenharmony_ci if (priv->writelen > 0) { 68862306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 68962306a36Sopenharmony_ci status = iuu_bulk_write(port); 69062306a36Sopenharmony_ci return; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 69362306a36Sopenharmony_ci /* if nothing to write call again rxcmd */ 69462306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - rxcmd recall\n", __func__); 69562306a36Sopenharmony_ci iuu_led_activity_off(urb); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port, 69962306a36Sopenharmony_ci const u8 *buf, int count) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 70262306a36Sopenharmony_ci unsigned long flags; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci count = min(count, 256 - priv->writelen); 70762306a36Sopenharmony_ci if (count == 0) 70862306a36Sopenharmony_ci goto out; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* fill the buffer */ 71162306a36Sopenharmony_ci memcpy(priv->writebuf + priv->writelen, buf, count); 71262306a36Sopenharmony_ci priv->writelen += count; 71362306a36Sopenharmony_ciout: 71462306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci return count; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic void read_rxcmd_callback(struct urb *urb) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 72262306a36Sopenharmony_ci int result; 72362306a36Sopenharmony_ci int status = urb->status; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (status) { 72662306a36Sopenharmony_ci /* error stop all */ 72762306a36Sopenharmony_ci return; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci usb_fill_bulk_urb(port->read_urb, port->serial->dev, 73162306a36Sopenharmony_ci usb_rcvbulkpipe(port->serial->dev, 73262306a36Sopenharmony_ci port->bulk_in_endpointAddress), 73362306a36Sopenharmony_ci port->read_urb->transfer_buffer, 256, 73462306a36Sopenharmony_ci iuu_uart_read_callback, port); 73562306a36Sopenharmony_ci result = usb_submit_urb(port->read_urb, GFP_ATOMIC); 73662306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - submit result = %d\n", __func__, result); 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic int iuu_uart_on(struct usb_serial_port *port) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci int status; 74262306a36Sopenharmony_ci u8 *buf; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci buf = kmalloc(4, GFP_KERNEL); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (!buf) 74762306a36Sopenharmony_ci return -ENOMEM; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci buf[0] = IUU_UART_ENABLE; 75062306a36Sopenharmony_ci buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF); 75162306a36Sopenharmony_ci buf[2] = (u8) (0x00FF & IUU_BAUD_9600); 75262306a36Sopenharmony_ci buf[3] = (u8) (0x0F0 & IUU_ONE_STOP_BIT) | (0x07 & IUU_PARITY_EVEN); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci status = bulk_immediate(port, buf, 4); 75562306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) { 75662306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - uart_on error\n", __func__); 75762306a36Sopenharmony_ci goto uart_enable_failed; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci /* iuu_reset() the card after iuu_uart_on() */ 76062306a36Sopenharmony_ci status = iuu_uart_flush(port); 76162306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) 76262306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - uart_flush error\n", __func__); 76362306a36Sopenharmony_ciuart_enable_failed: 76462306a36Sopenharmony_ci kfree(buf); 76562306a36Sopenharmony_ci return status; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/* Disables the IUU UART (a.k.a. the Phoenix voiderface) */ 76962306a36Sopenharmony_cistatic int iuu_uart_off(struct usb_serial_port *port) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci int status; 77262306a36Sopenharmony_ci u8 *buf; 77362306a36Sopenharmony_ci buf = kmalloc(1, GFP_KERNEL); 77462306a36Sopenharmony_ci if (!buf) 77562306a36Sopenharmony_ci return -ENOMEM; 77662306a36Sopenharmony_ci buf[0] = IUU_UART_DISABLE; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci status = bulk_immediate(port, buf, 1); 77962306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) 78062306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - uart_off error\n", __func__); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci kfree(buf); 78362306a36Sopenharmony_ci return status; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, 78762306a36Sopenharmony_ci u32 *actual, u8 parity) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci int status; 79062306a36Sopenharmony_ci u32 baud; 79162306a36Sopenharmony_ci u8 *dataout; 79262306a36Sopenharmony_ci u8 DataCount = 0; 79362306a36Sopenharmony_ci u8 T1Frekvens = 0; 79462306a36Sopenharmony_ci u8 T1reload = 0; 79562306a36Sopenharmony_ci unsigned int T1FrekvensHZ = 0; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - enter baud_base=%d\n", __func__, baud_base); 79862306a36Sopenharmony_ci dataout = kmalloc(5, GFP_KERNEL); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (!dataout) 80162306a36Sopenharmony_ci return -ENOMEM; 80262306a36Sopenharmony_ci /*baud = (((priv->clk / 35) * baud_base) / 100000); */ 80362306a36Sopenharmony_ci baud = baud_base; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (baud < 1200 || baud > 230400) { 80662306a36Sopenharmony_ci kfree(dataout); 80762306a36Sopenharmony_ci return IUU_INVALID_PARAMETER; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci if (baud > 977) { 81062306a36Sopenharmony_ci T1Frekvens = 3; 81162306a36Sopenharmony_ci T1FrekvensHZ = 500000; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (baud > 3906) { 81562306a36Sopenharmony_ci T1Frekvens = 2; 81662306a36Sopenharmony_ci T1FrekvensHZ = 2000000; 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (baud > 11718) { 82062306a36Sopenharmony_ci T1Frekvens = 1; 82162306a36Sopenharmony_ci T1FrekvensHZ = 6000000; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (baud > 46875) { 82562306a36Sopenharmony_ci T1Frekvens = 0; 82662306a36Sopenharmony_ci T1FrekvensHZ = 24000000; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2)); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* magic number here: ENTER_FIRMWARE_UPDATE; */ 83262306a36Sopenharmony_ci dataout[DataCount++] = IUU_UART_ESC; 83362306a36Sopenharmony_ci /* magic number here: CHANGE_BAUD; */ 83462306a36Sopenharmony_ci dataout[DataCount++] = IUU_UART_CHANGE; 83562306a36Sopenharmony_ci dataout[DataCount++] = T1Frekvens; 83662306a36Sopenharmony_ci dataout[DataCount++] = T1reload; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci *actual = (T1FrekvensHZ / (256 - T1reload)) / 2; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci switch (parity & 0x0F) { 84162306a36Sopenharmony_ci case IUU_PARITY_NONE: 84262306a36Sopenharmony_ci dataout[DataCount++] = 0x00; 84362306a36Sopenharmony_ci break; 84462306a36Sopenharmony_ci case IUU_PARITY_EVEN: 84562306a36Sopenharmony_ci dataout[DataCount++] = 0x01; 84662306a36Sopenharmony_ci break; 84762306a36Sopenharmony_ci case IUU_PARITY_ODD: 84862306a36Sopenharmony_ci dataout[DataCount++] = 0x02; 84962306a36Sopenharmony_ci break; 85062306a36Sopenharmony_ci case IUU_PARITY_MARK: 85162306a36Sopenharmony_ci dataout[DataCount++] = 0x03; 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci case IUU_PARITY_SPACE: 85462306a36Sopenharmony_ci dataout[DataCount++] = 0x04; 85562306a36Sopenharmony_ci break; 85662306a36Sopenharmony_ci default: 85762306a36Sopenharmony_ci kfree(dataout); 85862306a36Sopenharmony_ci return IUU_INVALID_PARAMETER; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci switch (parity & 0xF0) { 86262306a36Sopenharmony_ci case IUU_ONE_STOP_BIT: 86362306a36Sopenharmony_ci dataout[DataCount - 1] |= IUU_ONE_STOP_BIT; 86462306a36Sopenharmony_ci break; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci case IUU_TWO_STOP_BITS: 86762306a36Sopenharmony_ci dataout[DataCount - 1] |= IUU_TWO_STOP_BITS; 86862306a36Sopenharmony_ci break; 86962306a36Sopenharmony_ci default: 87062306a36Sopenharmony_ci kfree(dataout); 87162306a36Sopenharmony_ci return IUU_INVALID_PARAMETER; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci status = bulk_immediate(port, dataout, DataCount); 87562306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) 87662306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - uart_off error\n", __func__); 87762306a36Sopenharmony_ci kfree(dataout); 87862306a36Sopenharmony_ci return status; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic void iuu_set_termios(struct tty_struct *tty, 88262306a36Sopenharmony_ci struct usb_serial_port *port, 88362306a36Sopenharmony_ci const struct ktermios *old_termios) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci const u32 supported_mask = CMSPAR|PARENB|PARODD; 88662306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 88762306a36Sopenharmony_ci unsigned int cflag = tty->termios.c_cflag; 88862306a36Sopenharmony_ci int status; 88962306a36Sopenharmony_ci u32 actual; 89062306a36Sopenharmony_ci u32 parity; 89162306a36Sopenharmony_ci int csize = CS7; 89262306a36Sopenharmony_ci int baud; 89362306a36Sopenharmony_ci u32 newval = cflag & supported_mask; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* Just use the ospeed. ispeed should be the same. */ 89662306a36Sopenharmony_ci baud = tty->termios.c_ospeed; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - enter c_ospeed or baud=%d\n", __func__, baud); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci /* compute the parity parameter */ 90162306a36Sopenharmony_ci parity = 0; 90262306a36Sopenharmony_ci if (cflag & CMSPAR) { /* Using mark space */ 90362306a36Sopenharmony_ci if (cflag & PARODD) 90462306a36Sopenharmony_ci parity |= IUU_PARITY_SPACE; 90562306a36Sopenharmony_ci else 90662306a36Sopenharmony_ci parity |= IUU_PARITY_MARK; 90762306a36Sopenharmony_ci } else if (!(cflag & PARENB)) { 90862306a36Sopenharmony_ci parity |= IUU_PARITY_NONE; 90962306a36Sopenharmony_ci csize = CS8; 91062306a36Sopenharmony_ci } else if (cflag & PARODD) 91162306a36Sopenharmony_ci parity |= IUU_PARITY_ODD; 91262306a36Sopenharmony_ci else 91362306a36Sopenharmony_ci parity |= IUU_PARITY_EVEN; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci parity |= (cflag & CSTOPB ? IUU_TWO_STOP_BITS : IUU_ONE_STOP_BIT); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* set it */ 91862306a36Sopenharmony_ci status = iuu_uart_baud(port, 91962306a36Sopenharmony_ci baud * priv->boost / 100, 92062306a36Sopenharmony_ci &actual, parity); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* set the termios value to the real one, so the user now what has 92362306a36Sopenharmony_ci * changed. We support few fields so its easies to copy the old hw 92462306a36Sopenharmony_ci * settings back over and then adjust them 92562306a36Sopenharmony_ci */ 92662306a36Sopenharmony_ci if (old_termios) 92762306a36Sopenharmony_ci tty_termios_copy_hw(&tty->termios, old_termios); 92862306a36Sopenharmony_ci if (status != 0) /* Set failed - return old bits */ 92962306a36Sopenharmony_ci return; 93062306a36Sopenharmony_ci /* Re-encode speed, parity and csize */ 93162306a36Sopenharmony_ci tty_encode_baud_rate(tty, baud, baud); 93262306a36Sopenharmony_ci tty->termios.c_cflag &= ~(supported_mask|CSIZE); 93362306a36Sopenharmony_ci tty->termios.c_cflag |= newval | csize; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic void iuu_close(struct usb_serial_port *port) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci /* iuu_led (port,255,0,0,0); */ 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci iuu_uart_off(port); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci usb_kill_urb(port->write_urb); 94362306a36Sopenharmony_ci usb_kill_urb(port->read_urb); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci iuu_led(port, 0, 0, 0xF000, 0xFF); 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic void iuu_init_termios(struct tty_struct *tty) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci tty->termios.c_cflag = B9600 | CS8 | CSTOPB | CREAD | PARENB | CLOCAL; 95162306a36Sopenharmony_ci tty->termios.c_ispeed = 9600; 95262306a36Sopenharmony_ci tty->termios.c_ospeed = 9600; 95362306a36Sopenharmony_ci tty->termios.c_lflag = 0; 95462306a36Sopenharmony_ci tty->termios.c_oflag = 0; 95562306a36Sopenharmony_ci tty->termios.c_iflag = 0; 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cistatic int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 96162306a36Sopenharmony_ci struct device *dev = &port->dev; 96262306a36Sopenharmony_ci int result; 96362306a36Sopenharmony_ci int baud; 96462306a36Sopenharmony_ci u32 actual; 96562306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci baud = tty->termios.c_ospeed; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci dev_dbg(dev, "%s - baud %d\n", __func__, baud); 97062306a36Sopenharmony_ci usb_clear_halt(serial->dev, port->write_urb->pipe); 97162306a36Sopenharmony_ci usb_clear_halt(serial->dev, port->read_urb->pipe); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci priv->poll = 0; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci#define SOUP(a, b, c, d) do { \ 97662306a36Sopenharmony_ci result = usb_control_msg(port->serial->dev, \ 97762306a36Sopenharmony_ci usb_sndctrlpipe(port->serial->dev, 0), \ 97862306a36Sopenharmony_ci b, a, c, d, NULL, 0, 1000); \ 97962306a36Sopenharmony_ci dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d\n", a, b, c, d, result); } while (0) 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* This is not UART related but IUU USB driver related or something */ 98262306a36Sopenharmony_ci /* like that. Basically no IUU will accept any commands from the USB */ 98362306a36Sopenharmony_ci /* host unless it has received the following message */ 98462306a36Sopenharmony_ci /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */ 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci SOUP(0x03, 0x02, 0x02, 0x0); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci iuu_led(port, 0xF000, 0xF000, 0, 0xFF); 98962306a36Sopenharmony_ci iuu_uart_on(port); 99062306a36Sopenharmony_ci if (boost < 100) 99162306a36Sopenharmony_ci boost = 100; 99262306a36Sopenharmony_ci priv->boost = boost; 99362306a36Sopenharmony_ci switch (clockmode) { 99462306a36Sopenharmony_ci case 2: /* 3.680 Mhz */ 99562306a36Sopenharmony_ci priv->clk = IUU_CLK_3680000; 99662306a36Sopenharmony_ci iuu_clk(port, IUU_CLK_3680000 * boost / 100); 99762306a36Sopenharmony_ci result = 99862306a36Sopenharmony_ci iuu_uart_baud(port, baud * boost / 100, &actual, 99962306a36Sopenharmony_ci IUU_PARITY_EVEN); 100062306a36Sopenharmony_ci break; 100162306a36Sopenharmony_ci case 3: /* 6.00 Mhz */ 100262306a36Sopenharmony_ci iuu_clk(port, IUU_CLK_6000000 * boost / 100); 100362306a36Sopenharmony_ci priv->clk = IUU_CLK_6000000; 100462306a36Sopenharmony_ci /* Ratio of 6000000 to 3500000 for baud 9600 */ 100562306a36Sopenharmony_ci result = 100662306a36Sopenharmony_ci iuu_uart_baud(port, 16457 * boost / 100, &actual, 100762306a36Sopenharmony_ci IUU_PARITY_EVEN); 100862306a36Sopenharmony_ci break; 100962306a36Sopenharmony_ci default: /* 3.579 Mhz */ 101062306a36Sopenharmony_ci iuu_clk(port, IUU_CLK_3579000 * boost / 100); 101162306a36Sopenharmony_ci priv->clk = IUU_CLK_3579000; 101262306a36Sopenharmony_ci result = 101362306a36Sopenharmony_ci iuu_uart_baud(port, baud * boost / 100, &actual, 101462306a36Sopenharmony_ci IUU_PARITY_EVEN); 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* set the cardin cardout signals */ 101862306a36Sopenharmony_ci switch (cdmode) { 101962306a36Sopenharmony_ci case 0: 102062306a36Sopenharmony_ci iuu_cardin = 0; 102162306a36Sopenharmony_ci iuu_cardout = 0; 102262306a36Sopenharmony_ci break; 102362306a36Sopenharmony_ci case 1: 102462306a36Sopenharmony_ci iuu_cardin = TIOCM_CD; 102562306a36Sopenharmony_ci iuu_cardout = 0; 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci case 2: 102862306a36Sopenharmony_ci iuu_cardin = 0; 102962306a36Sopenharmony_ci iuu_cardout = TIOCM_CD; 103062306a36Sopenharmony_ci break; 103162306a36Sopenharmony_ci case 3: 103262306a36Sopenharmony_ci iuu_cardin = TIOCM_DSR; 103362306a36Sopenharmony_ci iuu_cardout = 0; 103462306a36Sopenharmony_ci break; 103562306a36Sopenharmony_ci case 4: 103662306a36Sopenharmony_ci iuu_cardin = 0; 103762306a36Sopenharmony_ci iuu_cardout = TIOCM_DSR; 103862306a36Sopenharmony_ci break; 103962306a36Sopenharmony_ci case 5: 104062306a36Sopenharmony_ci iuu_cardin = TIOCM_CTS; 104162306a36Sopenharmony_ci iuu_cardout = 0; 104262306a36Sopenharmony_ci break; 104362306a36Sopenharmony_ci case 6: 104462306a36Sopenharmony_ci iuu_cardin = 0; 104562306a36Sopenharmony_ci iuu_cardout = TIOCM_CTS; 104662306a36Sopenharmony_ci break; 104762306a36Sopenharmony_ci case 7: 104862306a36Sopenharmony_ci iuu_cardin = TIOCM_RNG; 104962306a36Sopenharmony_ci iuu_cardout = 0; 105062306a36Sopenharmony_ci break; 105162306a36Sopenharmony_ci case 8: 105262306a36Sopenharmony_ci iuu_cardin = 0; 105362306a36Sopenharmony_ci iuu_cardout = TIOCM_RNG; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci iuu_uart_flush(port); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci dev_dbg(dev, "%s - initialization done\n", __func__); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); 106162306a36Sopenharmony_ci usb_fill_bulk_urb(port->write_urb, port->serial->dev, 106262306a36Sopenharmony_ci usb_sndbulkpipe(port->serial->dev, 106362306a36Sopenharmony_ci port->bulk_out_endpointAddress), 106462306a36Sopenharmony_ci port->write_urb->transfer_buffer, 1, 106562306a36Sopenharmony_ci read_rxcmd_callback, port); 106662306a36Sopenharmony_ci result = usb_submit_urb(port->write_urb, GFP_KERNEL); 106762306a36Sopenharmony_ci if (result) { 106862306a36Sopenharmony_ci dev_err(dev, "%s - failed submitting read urb, error %d\n", __func__, result); 106962306a36Sopenharmony_ci iuu_close(port); 107062306a36Sopenharmony_ci } else { 107162306a36Sopenharmony_ci dev_dbg(dev, "%s - rxcmd OK\n", __func__); 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci return result; 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci/* how to change VCC */ 107862306a36Sopenharmony_cistatic int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci int status; 108162306a36Sopenharmony_ci u8 *buf; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci buf = kmalloc(5, GFP_KERNEL); 108462306a36Sopenharmony_ci if (!buf) 108562306a36Sopenharmony_ci return -ENOMEM; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci buf[0] = IUU_SET_VCC; 108862306a36Sopenharmony_ci buf[1] = vcc & 0xFF; 108962306a36Sopenharmony_ci buf[2] = (vcc >> 8) & 0xFF; 109062306a36Sopenharmony_ci buf[3] = (vcc >> 16) & 0xFF; 109162306a36Sopenharmony_ci buf[4] = (vcc >> 24) & 0xFF; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci status = bulk_immediate(port, buf, 5); 109462306a36Sopenharmony_ci kfree(buf); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (status != IUU_OPERATION_OK) 109762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - vcc error status = %2x\n", __func__, status); 109862306a36Sopenharmony_ci else 109962306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - vcc OK !\n", __func__); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci return status; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci/* 110562306a36Sopenharmony_ci * Sysfs Attributes 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_cistatic ssize_t vcc_mode_show(struct device *dev, 110962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci struct usb_serial_port *port = to_usb_serial_port(dev); 111262306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci return sprintf(buf, "%d\n", priv->vcc); 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic ssize_t vcc_mode_store(struct device *dev, 111862306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci struct usb_serial_port *port = to_usb_serial_port(dev); 112162306a36Sopenharmony_ci struct iuu_private *priv = usb_get_serial_port_data(port); 112262306a36Sopenharmony_ci unsigned long v; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (kstrtoul(buf, 10, &v)) { 112562306a36Sopenharmony_ci dev_err(dev, "%s - vcc_mode: %s is not a unsigned long\n", 112662306a36Sopenharmony_ci __func__, buf); 112762306a36Sopenharmony_ci goto fail_store_vcc_mode; 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci dev_dbg(dev, "%s: setting vcc_mode = %ld\n", __func__, v); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if ((v != 3) && (v != 5)) { 113362306a36Sopenharmony_ci dev_err(dev, "%s - vcc_mode %ld is invalid\n", __func__, v); 113462306a36Sopenharmony_ci } else { 113562306a36Sopenharmony_ci iuu_vcc_set(port, v); 113662306a36Sopenharmony_ci priv->vcc = v; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_cifail_store_vcc_mode: 113962306a36Sopenharmony_ci return count; 114062306a36Sopenharmony_ci} 114162306a36Sopenharmony_cistatic DEVICE_ATTR_RW(vcc_mode); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic int iuu_create_sysfs_attrs(struct usb_serial_port *port) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci return device_create_file(&port->dev, &dev_attr_vcc_mode); 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic int iuu_remove_sysfs_attrs(struct usb_serial_port *port) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci device_remove_file(&port->dev, &dev_attr_vcc_mode); 115162306a36Sopenharmony_ci return 0; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci/* 115562306a36Sopenharmony_ci * End Sysfs Attributes 115662306a36Sopenharmony_ci */ 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_cistatic struct usb_serial_driver iuu_device = { 115962306a36Sopenharmony_ci .driver = { 116062306a36Sopenharmony_ci .owner = THIS_MODULE, 116162306a36Sopenharmony_ci .name = "iuu_phoenix", 116262306a36Sopenharmony_ci }, 116362306a36Sopenharmony_ci .id_table = id_table, 116462306a36Sopenharmony_ci .num_ports = 1, 116562306a36Sopenharmony_ci .num_bulk_in = 1, 116662306a36Sopenharmony_ci .num_bulk_out = 1, 116762306a36Sopenharmony_ci .bulk_in_size = 512, 116862306a36Sopenharmony_ci .bulk_out_size = 512, 116962306a36Sopenharmony_ci .open = iuu_open, 117062306a36Sopenharmony_ci .close = iuu_close, 117162306a36Sopenharmony_ci .write = iuu_uart_write, 117262306a36Sopenharmony_ci .read_bulk_callback = iuu_uart_read_callback, 117362306a36Sopenharmony_ci .tiocmget = iuu_tiocmget, 117462306a36Sopenharmony_ci .tiocmset = iuu_tiocmset, 117562306a36Sopenharmony_ci .set_termios = iuu_set_termios, 117662306a36Sopenharmony_ci .init_termios = iuu_init_termios, 117762306a36Sopenharmony_ci .port_probe = iuu_port_probe, 117862306a36Sopenharmony_ci .port_remove = iuu_port_remove, 117962306a36Sopenharmony_ci}; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 118262306a36Sopenharmony_ci &iuu_device, NULL 118362306a36Sopenharmony_ci}; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ciMODULE_AUTHOR("Alain Degreffe eczema@ecze.com"); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 119062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cimodule_param(xmas, bool, 0644); 119362306a36Sopenharmony_ciMODULE_PARM_DESC(xmas, "Xmas colors enabled or not"); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cimodule_param(boost, int, 0644); 119662306a36Sopenharmony_ciMODULE_PARM_DESC(boost, "Card overclock boost (in percent 100-500)"); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_cimodule_param(clockmode, int, 0644); 119962306a36Sopenharmony_ciMODULE_PARM_DESC(clockmode, "Card clock mode (1=3.579 MHz, 2=3.680 MHz, " 120062306a36Sopenharmony_ci "3=6 Mhz)"); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_cimodule_param(cdmode, int, 0644); 120362306a36Sopenharmony_ciMODULE_PARM_DESC(cdmode, "Card detect mode (0=none, 1=CD, 2=!CD, 3=DSR, " 120462306a36Sopenharmony_ci "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING)"); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cimodule_param(vcc_default, int, 0644); 120762306a36Sopenharmony_ciMODULE_PARM_DESC(vcc_default, "Set default VCC (either 3 for 3.3V or 5 " 120862306a36Sopenharmony_ci "for 5V). Default to 5."); 1209