#include <linux/list.h>
#include "vizzini.h"
-#include "vzioctl.h"
#define DRIVER_AUTHOR "Ravi Reddy"
#define DRIVER_DESC "Exar USB UART Driver for XR21V141x "
return result;
}
-static int vizzini_get_reg(struct acm *acm,
- int block, int reg, char *value)
-{
- int result;
-
- result = usb_control_msg(acm->dev, /* usb device */
- usb_rcvctrlpipe(acm->dev, 0), /* endpoint pipe */
- XR_GETN_REG, /* request */
- USB_DIR_IN | USB_TYPE_VENDOR, /* request_type */
- 0, /* request value */
- reg | (block << 8), /* index */
- value, /* data */
- 1, /* size */
- 5000); /* timeout */
-
- return result;
-}
-
static void vizzini_disable(struct acm *acm)
{
int block = acm->block;
vizzini_set_reg(acm, URM_REG_BLOCK, URM_ENABLE_BASE + block, URM_ENABLE_0_TX | URM_ENABLE_0_RX);
}
-static void vizzini_loopback(struct acm *acm, int from)
-{
- int block = acm->block;
- int lb;
-
- switch (from)
- {
- case 0: lb = UART_LOOPBACK_CTL_RX_UART0; break;
- case 1: lb = UART_LOOPBACK_CTL_RX_UART1; break;
- case 2: lb = UART_LOOPBACK_CTL_RX_UART2; break;
- case 3: lb = UART_LOOPBACK_CTL_RX_UART3; break;
- default: return;
- }
-
- dev_info(&acm->control->dev, "Internal loopback from %d\n", from);
-
- vizzini_disable(acm);
- vizzini_set_reg(acm, block, UART_LOOPBACK_CTL, UART_LOOPBACK_CTL_ENABLE | lb);
- vizzini_enable(acm);
-}
-
-static int vizzini_test_mode(struct acm *acm,
- int selector)
-{
- int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
- USB_REQ_SET_FEATURE,
- USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
- USB_DEVICE_TEST_MODE,
- selector << 8,
- NULL, 0, 5000);
- dev_dbg(&acm->control->dev, "vz_test_mode: selector=0x%02x\n", selector);
- return retval < 0 ? retval : 0;
-}
-
static int acm_tty_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct acm *acm = tty->driver_data;
int rv = -ENOIOCTLCMD;
- unsigned int block, reg, val, match, preciseflags, unicast, broadcast, flow, selector;
- char *data;
-
switch (cmd) {
case TIOCGSERIAL: /* gets serial port data */
rv = get_serial_info(acm, (struct serial_struct __user *) arg);
case TIOCGICOUNT:
rv = get_serial_usage(acm, (struct serial_icounter_struct __user *) arg);
break;
-
- case VZIOC_GET_REG:
- if (get_user(block, (int __user *)arg))
- return -EFAULT;
- if (get_user(reg, (int __user *)(arg + sizeof(int))))
- return -EFAULT;
-
- data = kmalloc(1, GFP_KERNEL);
- if (data == NULL) {
- dev_err(&acm->control->dev, "%s - Cannot allocate USB buffer.\n", __func__);
- return -ENOMEM;
- }
-
- if (block == -1)
- block = acm->block;
-
- rv = vizzini_get_reg(acm, block, reg, data);
- if (rv != 1) {
- dev_err(&acm->control->dev, "Cannot get register (%d)\n", rv);
- kfree(data);
- return -EFAULT;
- }
-
- if (put_user(data[0], (int __user *)(arg + 2 * sizeof(int)))) {
- dev_err(&acm->control->dev, "Cannot put user result\n");
- kfree(data);
- return -EFAULT;
- }
-
- kfree(data);
- break;
-
- case VZIOC_SET_REG:
- if (get_user(block, (int __user *)arg))
- return -EFAULT;
- if (get_user(reg, (int __user *)(arg + sizeof(int))))
- return -EFAULT;
- if (get_user(val, (int __user *)(arg + 2 * sizeof(int))))
- return -EFAULT;
-
- if (block == -1)
- block = acm->block;
-
- rv = vizzini_set_reg(acm, block, reg, val);
- if (rv < 0)
- return -EFAULT;
- break;
-
- case VZIOC_SET_ADDRESS_MATCH:
- match = arg;
-
- dev_dbg(&acm->control->dev, "%s VIOC_SET_ADDRESS_MATCH %d\n", __func__, match);
-
- vizzini_disable(acm);
-
- if (match & VZ_ADDRESS_MATCH_DISABLE) {
- flow = UART_FLOW_MODE_NONE;
- } else {
- flow = UART_FLOW_MODE_ADDR_MATCH_TX;
- unicast = (match >> VZ_ADDRESS_UNICAST_S) & 0xff;
- broadcast = (match >> VZ_ADDRESS_BROADCAST_S) & 0xff;
- }
-
- dev_dbg(&acm->control->dev, "address match: flow=%d ucast=%d bcast=%u\n",
- flow, unicast, broadcast);
- vizzini_set_reg(acm, acm->block, UART_FLOW, flow);
- vizzini_set_reg(acm, acm->block, UART_XON_CHAR, unicast);
- vizzini_set_reg(acm, acm->block, UART_XOFF_CHAR, broadcast);
-
- vizzini_enable(acm);
- break;
-
- case VZIOC_SET_PRECISE_FLAGS:
- preciseflags = arg;
-
- dev_dbg(&acm->control->dev, "%s VIOC_SET_PRECISE_FLAGS %d\n", __func__, preciseflags);
-
- vizzini_disable(acm);
-
- if (preciseflags) {
- acm->preciseflags = 1;
- } else {
- acm->preciseflags = 0;
- }
-
- vizzini_set_reg(acm, EPLOCALS_REG_BLOCK,
- (acm->block * MEM_EP_LOCALS_SIZE) + EP_WIDE_MODE,
- acm->preciseflags);
-
- vizzini_enable(acm);
- rv = 0;
- break;
-
- case VZIOC_TEST_MODE:
- selector = arg;
- dev_dbg(&acm->control->dev, "%s VIOC_TEST_MODE 0x%02x\n", __func__, selector);
- vizzini_test_mode(acm, selector);
- rv = 0;
- break;
-
- case VZIOC_LOOPBACK:
- selector = arg;
- dev_dbg(&acm->control->dev, "VIOC_LOOPBACK 0x%02x\n", selector);
- vizzini_loopback(acm, selector);
- rv = 0;
- break;
}
return rv;