static int xr_usb_serial_tty_ioctl()

in meta-facebook/meta-fby3/recipes-kernel/exar1420/files/xr_usb_serial_common.c [901:1071]


static int xr_usb_serial_tty_ioctl(struct tty_struct *tty,
					unsigned int cmd, unsigned long arg)
{
	struct xr_usb_serial *xr_usb_serial = tty->driver_data;
	int rv = -ENOIOCTLCMD;
	unsigned int  channel, reg, val,preciseflags;
	int           baud_rate = 0;
	struct usb_cdc_line_coding newline;
	short	*data;
	switch (cmd) {
	case TIOCGSERIAL: /* gets serial port data */
		rv = get_serial_info(xr_usb_serial, (struct serial_struct __user *) arg);
		break;
	case TIOCSSERIAL:
		rv = set_serial_info(xr_usb_serial, (struct serial_struct __user *) arg);
		break;
	case XR_USB_SERIAL_GET_REG:
		if (get_user(channel, (int __user *)arg))
			return -EFAULT;
		if (get_user(reg, (int __user *)(arg + sizeof(int))))
			return -EFAULT;

		data = kmalloc(2, GFP_KERNEL);
		if (data == NULL) {
			dev_err(&xr_usb_serial->control->dev, "%s - Cannot allocate USB buffer.\n", __func__);
			return -ENOMEM;
		}
						
		if (channel == -1)
		{
			rv = xr_usb_serial_get_reg(xr_usb_serial,reg, data);
		}
		else
		{
			rv = xr_usb_serial_get_reg_ext(xr_usb_serial,channel,reg, data);
		}
		if (rv < 0)
		{
			dev_err(&xr_usb_serial->control->dev, "Cannot get register (%d)\n", rv);
			kfree(data);
			return -EFAULT;
		}
		if (put_user(le16_to_cpu(*data), (int __user *)(arg + 2 * sizeof(int))))
		{
			dev_err(&xr_usb_serial->control->dev, "Cannot put user result\n");
			kfree(data);
			return -EFAULT;
		}
		rv = 0;
		kfree(data);
		break;
	case XR_USB_SERIAL_SET_REG:
		if (get_user(channel, (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 (channel == -1)
		{
			rv = xr_usb_serial_set_reg(xr_usb_serial,reg, val);
		}
		else
		{
			rv = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,reg, val);				
		}
		if (rv < 0)
			return -EFAULT;
		rv = 0;
		break;
	case XR_USB_SERIAL_LOOPBACK:
		if (get_user(channel, (int __user *)arg))
			return -EFAULT;
		if (channel == -1)
			channel = xr_usb_serial->channel;
		rv = xr_usb_serial_set_loopback(xr_usb_serial,channel);
		if (rv < 0)
			return -EFAULT;
		rv = 0;
		break;
	case XR_USB_SERIAL_SET_GPIO_MODE_REG:
		xr_usb_serial_disable(xr_usb_serial);
		if (get_user(channel, (int __user *)arg))
			return -EFAULT;
		if (get_user(val, (int __user *)(arg + sizeof(int))))
			return -EFAULT;
		if (channel == -1)
		{
			//block = portdata->block;
			rv = xr_usb_serial_set_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_mode_addr, val);
		}
		else
		{
			rv = xr_usb_serial_set_reg_ext(xr_usb_serial,channel,xr_usb_serial->reg_map.uart_gpio_mode_addr, val);
		}
	
		dev_dbg(&xr_usb_serial->control->dev, "XR_USB_SERIAL_SET_GPIO_MODE_REG 0x%x val:0x%x \n", xr_usb_serial->reg_map.uart_gpio_mode_addr,val);
		xr_usb_serial_enable(xr_usb_serial);
		if (rv < 0)
			return -EFAULT;
		break;
	case XR_USB_SERIAL_GET_GPIO_MODE_REG:
		xr_usb_serial_disable(xr_usb_serial);
		if (get_user(channel, (int __user *)arg))
			return -EFAULT;
		 
		data = kmalloc(2, GFP_KERNEL);
		if (data == NULL) {
			dev_err(&xr_usb_serial->control->dev, "%s - Cannot allocate USB buffer.\n", __func__);
			return -ENOMEM;
		}

		if (channel == -1)
		{
			rv = xr_usb_serial_get_reg(xr_usb_serial,xr_usb_serial->reg_map.uart_gpio_mode_addr, data);
		}
		else
		{
			rv = xr_usb_serial_get_reg_ext(xr_usb_serial,channel,xr_usb_serial->reg_map.uart_gpio_mode_addr,data);
		}
		
		xr_usb_serial_enable(xr_usb_serial);
		
		dev_dbg(&xr_usb_serial->control->dev, "XR_USB_SERIAL_GET_GPIO_MODE_REG 0x%x val:0x%x \n", xr_usb_serial->reg_map.uart_gpio_mode_addr,*data);
		
		if (rv < 0 ) {
			dev_err(&xr_usb_serial->control->dev, "Cannot get register (%d) channel=%d \n", rv,channel);
			kfree(data);
			return -EFAULT;
		}
		
		if (put_user(data[0], (int __user *)(arg + sizeof(int)))) {
			dev_err(&xr_usb_serial->control->dev, "Cannot put user result\n");
			kfree(data);
			return -EFAULT;
		}

		kfree(data);
		break;
	case XRIOC_SET_ANY_BAUD_RATE:		
		if (get_user(baud_rate, (int __user *)arg)) {
			dev_dbg(&xr_usb_serial->control->dev, "get_user errot \n");
			return -EFAULT;
		}
		xr_usb_serial->line.dwDTERate = baud_rate; 
		memcpy(&newline,&(xr_usb_serial->line),sizeof(struct usb_cdc_line_coding));
		xr_usb_serial_disable(xr_usb_serial);
		rv = xr_usb_serial_set_line(xr_usb_serial,&newline);
		xr_usb_serial_enable(xr_usb_serial);
		dev_dbg(&xr_usb_serial->control->dev, "XRIOC_SET_ANY_BAUD_RATE set baud_rate:%d ret=%d\n", baud_rate,rv);
		break;	
	case XRIOC_SET_PRECISE_FLAGS:
		preciseflags = arg;
		dev_dbg(&xr_usb_serial->control->dev, "%s VIOC_SET_PRECISE_FLAGS %d\n", __func__, preciseflags);
		xr_usb_serial_disable(xr_usb_serial);
		if (preciseflags) 
		{
			xr_usb_serial->preciseflags = 1;
		} 
		else 
		{
			xr_usb_serial->preciseflags = 0;
		}
		xr_usb_serial_set_wide_mode(xr_usb_serial,xr_usb_serial->preciseflags);
		xr_usb_serial_enable(xr_usb_serial);
		break;
	}

	return rv;
}