コード例 #1
0
ファイル: serqt_usb2.c プロジェクト: AiWinters/linux
static void qt_close(struct usb_serial_port *port)
{
	struct usb_serial *serial = port->serial;
	struct quatech_port *qt_port;
	struct quatech_port *port0;
	struct tty_struct *tty;
	int status;
	unsigned int index;
	status = 0;

	tty = tty_port_tty_get(&port->port);
	index = tty->index - serial->minor;

	qt_port = qt_get_port_private(port);
	port0 = qt_get_port_private(serial->port[0]);

	/* shutdown any bulk reads that might be going on */
	if (serial->num_bulk_out)
		usb_unlink_urb(port->write_urb);
	if (serial->num_bulk_in)
		usb_unlink_urb(port->read_urb);

	/* wait up to for transmitter to empty */
	if (serial->dev)
		qt_block_until_empty(tty, qt_port);
	tty_kref_put(tty);

	/* Close uart channel */
	status = qt_close_channel(serial, index);
	if (status < 0)
		dev_dbg(&port->dev,
			"%s - port %d qt_close_channel failed.\n",
			__func__, port->number);

	port0->open_ports--;

	dev_dbg(&port->dev, "qt_num_open_ports in close%d:in port%d\n",
		port0->open_ports, port->number);

	if (port0->open_ports == 0) {
		if (serial->port[0]->interrupt_in_urb) {
			dev_dbg(&port->dev, "Shutdown interrupt_in_urb\n");
			usb_kill_urb(serial->port[0]->interrupt_in_urb);
		}

	}

	if (qt_port->write_urb) {
		/* if this urb had a transfer buffer already (old tx) free it */
		kfree(qt_port->write_urb->transfer_buffer);
		usb_free_urb(qt_port->write_urb);
	}

}
コード例 #2
0
ファイル: serqt_usb2.c プロジェクト: AiWinters/linux
static void qt_unthrottle(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct usb_serial *serial = get_usb_serial(port, __func__);
	struct quatech_port *qt_port;

	if (!serial)
		return;

	qt_port = qt_get_port_private(port);

	mutex_lock(&qt_port->lock);

	if (qt_port->RxHolding == 1) {
		dev_dbg(&port->dev, "%s -qt_port->RxHolding == 1\n", __func__);

		qt_port->RxHolding = 0;
		dev_dbg(&port->dev, "%s - qt_port->RxHolding = 0\n", __func__);

		/* if we have a bulk endpoint, start it up */
		if ((serial->num_bulk_in) && (qt_port->ReadBulkStopped == 1))
			qt_submit_urb_from_unthrottle(port, serial);
	}
	mutex_unlock(&qt_port->lock);
}
コード例 #3
0
ファイル: serqt_usb2.c プロジェクト: AiWinters/linux
static void qt_break(struct tty_struct *tty, int break_state)
{
	struct usb_serial_port *port = tty->driver_data;
	struct usb_serial *serial = get_usb_serial(port, __func__);
	struct quatech_port *qt_port;
	u16 index, onoff;
	unsigned int result;

	index = tty->index - serial->minor;

	qt_port = qt_get_port_private(port);

	if (break_state == -1)
		onoff = 1;
	else
		onoff = 0;

	mutex_lock(&qt_port->lock);

	result =
	    usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
			    QT_BREAK_CONTROL, 0x40, onoff, index, NULL, 0, 300);

	mutex_unlock(&qt_port->lock);
}
コード例 #4
0
ファイル: serqt_usb2.c プロジェクト: AiWinters/linux
static int qt_write_room(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct usb_serial *serial;
	struct quatech_port *qt_port;

	int retval = -EINVAL;

	if (port_paranoia_check(port, __func__))
		return -1;

	serial = get_usb_serial(port, __func__);

	if (!serial)
		return -ENODEV;

	qt_port = qt_get_port_private(port);

	mutex_lock(&qt_port->lock);

	if (serial->num_bulk_out) {
		if (port->write_urb->status != -EINPROGRESS)
			retval = port->bulk_out_size;
	}

	mutex_unlock(&qt_port->lock);
	return retval;

}
コード例 #5
0
ファイル: serqt_usb2.c プロジェクト: AiWinters/linux
static int qt_tiocmget(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct usb_serial *serial = get_usb_serial(port, __func__);
	struct quatech_port *qt_port = qt_get_port_private(port);
	int retval;

	if (!serial)
		return -ENODEV;

	mutex_lock(&qt_port->lock);
	retval = qt_real_tiocmget(tty, port, serial);
	mutex_unlock(&qt_port->lock);
	return retval;
}
コード例 #6
0
ファイル: serqt_usb2.c プロジェクト: MaxChina/linux
static int qt_ioctl(struct tty_struct *tty,
		    unsigned int cmd, unsigned long arg)
{
	struct usb_serial_port *port = tty->driver_data;
	struct quatech_port *qt_port = qt_get_port_private(port);
	unsigned int index;

	dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);

	index = port->port_number;

	if (cmd == TIOCMIWAIT) {
		while (qt_port != NULL) {
#if 0
			/* this never wakes up */
			interruptible_sleep_on(&qt_port->msr_wait);
#endif
			if (signal_pending(current))
				return -ERESTARTSYS;
			else {
				char diff = qt_port->diff_status;

				if (diff == 0)
					return -EIO;	/* no change => error */

				/* Consume all events */
				qt_port->diff_status = 0;

				if (((arg & TIOCM_RNG)
				     && (diff & SERIAL_MSR_RI))
				    || ((arg & TIOCM_DSR)
					&& (diff & SERIAL_MSR_DSR))
				    || ((arg & TIOCM_CD)
					&& (diff & SERIAL_MSR_CD))
				    || ((arg & TIOCM_CTS)
					&& (diff & SERIAL_MSR_CTS))) {
					return 0;
				}
			}
		}
		return 0;
	}

	dev_dbg(&port->dev, "%s -No ioctl for that one.\n", __func__);
	return -ENOIOCTLCMD;
}
コード例 #7
0
ファイル: serqt_usb2.c プロジェクト: AiWinters/linux
static void qt_throttle(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct usb_serial *serial = get_usb_serial(port, __func__);
	struct quatech_port *qt_port;

	if (!serial)
		return;

	qt_port = qt_get_port_private(port);

	mutex_lock(&qt_port->lock);

	/* pass on to the driver specific version of this function */
	qt_port->RxHolding = 1;

	mutex_unlock(&qt_port->lock);
}
コード例 #8
0
ファイル: serqt_usb2.c プロジェクト: AiWinters/linux
static int qt_open(struct tty_struct *tty,
		   struct usb_serial_port *port)
{
	struct usb_serial *serial;
	struct quatech_port *quatech_port;
	struct quatech_port *port0;
	struct qt_open_channel_data ChannelData;

	int result;

	if (port_paranoia_check(port, __func__))
		return -ENODEV;

	serial = port->serial;

	if (serial_paranoia_check(serial, __func__))
		return -ENODEV;

	quatech_port = qt_get_port_private(port);
	port0 = qt_get_port_private(serial->port[0]);

	if (quatech_port == NULL || port0 == NULL)
		return -ENODEV;

	usb_clear_halt(serial->dev, port->write_urb->pipe);
	usb_clear_halt(serial->dev, port->read_urb->pipe);
	port0->open_ports++;

	result = qt_get_device(serial, &port0->DeviceData);

	/* Port specific setups */
	result = qt_open_channel(serial, port->number, &ChannelData);
	if (result < 0) {
		dev_dbg(&port->dev, "qt_open_channel failed\n");
		return result;
	}
	dev_dbg(&port->dev, "qt_open_channel completed.\n");

/* FIXME: are these needed?  Does it even do anything useful? */
	quatech_port->shadowLSR = ChannelData.line_status &
	    (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | SERIAL_LSR_BI);

	quatech_port->shadowMSR = ChannelData.modem_status &
	    (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD);

	/* Set Baud rate to default and turn off (default)flow control here */
	result = qt_setuart(serial, port->number, DEFAULT_DIVISOR, DEFAULT_LCR);
	if (result < 0) {
		dev_dbg(&port->dev, "qt_setuart failed\n");
		return result;
	}
	dev_dbg(&port->dev, "qt_setuart completed.\n");

	/*
	 * Put this here to make it responsive to stty and defaults set by
	 * the tty layer
	 */

	/*  Check to see if we've set up our endpoint info yet */
	if (port0->open_ports == 1) {
		if (serial->port[0]->interrupt_in_buffer == NULL)
			qt_submit_urb_from_open(serial, port);
	}

	dev_dbg(&port->dev, "port number is %d\n", port->number);
	dev_dbg(&port->dev, "serial number is %d\n", port->serial->minor);
	dev_dbg(&port->dev,
		"Bulkin endpoint is %d\n", port->bulk_in_endpointAddress);
	dev_dbg(&port->dev,
		"BulkOut endpoint is %d\n", port->bulk_out_endpointAddress);
	dev_dbg(&port->dev, "Interrupt endpoint is %d\n",
		port->interrupt_in_endpointAddress);
	dev_dbg(&port->dev, "port's number in the device is %d\n",
		quatech_port->port_num);
	quatech_port->read_urb = port->read_urb;

	/* set up our bulk in urb */

	usb_fill_bulk_urb(quatech_port->read_urb,
			  serial->dev,
			  usb_rcvbulkpipe(serial->dev,
					  port->bulk_in_endpointAddress),
			  port->bulk_in_buffer,
			  quatech_port->read_urb->transfer_buffer_length,
			  qt_read_bulk_callback, quatech_port);

	dev_dbg(&port->dev, "qt_open: bulkin endpoint is %d\n",
		port->bulk_in_endpointAddress);
	quatech_port->read_urb_busy = true;
	result = usb_submit_urb(quatech_port->read_urb, GFP_KERNEL);
	if (result) {
		dev_err(&port->dev,
			"%s - Error %d submitting control urb\n",
			__func__, result);
		quatech_port->read_urb_busy = false;
	}

	/* initialize our wait queues */
	init_waitqueue_head(&quatech_port->wait);
	init_waitqueue_head(&quatech_port->msr_wait);

	/* initialize our icount structure */
	memset(&(quatech_port->icount), 0x00, sizeof(quatech_port->icount));

	return 0;

}
コード例 #9
0
ファイル: serqt_usb2.c プロジェクト: AiWinters/linux
static int qt_startup(struct usb_serial *serial)
{
	struct device *dev = &serial->dev->dev;
	struct usb_serial_port *port;
	struct quatech_port *qt_port;
	struct qt_get_device_data DeviceData;
	int i;
	int status;

	/* Now setup per port private data */
	for (i = 0; i < serial->num_ports; i++) {
		port = serial->port[i];
		qt_port = kzalloc(sizeof(*qt_port), GFP_KERNEL);
		if (!qt_port) {
			for (--i; i >= 0; i--) {
				port = serial->port[i];
				kfree(usb_get_serial_port_data(port));
				usb_set_serial_port_data(port, NULL);
			}
			return -ENOMEM;
		}
		mutex_init(&qt_port->lock);

		usb_set_serial_port_data(port, qt_port);

	}

	status = qt_get_device(serial, &DeviceData);
	if (status < 0)
		goto startup_error;

	dev_dbg(dev, "DeviceData.portb = 0x%x\n", DeviceData.portb);

	DeviceData.portb &= ~FULLPWRBIT;
	dev_dbg(dev, "Changing DeviceData.portb to 0x%x\n", DeviceData.portb);

	status = qt_set_device(serial, &DeviceData);
	if (status < 0) {
		dev_dbg(dev, "qt_set_device failed\n");
		goto startup_error;
	}

	status = qt_get_device(serial, &DeviceData);
	if (status < 0) {
		dev_dbg(dev, "qt_get_device failed\n");
		goto startup_error;
	}

	switch (serial->dev->descriptor.idProduct) {
	case QUATECH_DSU100:
	case QUATECH_QSU100:
	case QUATECH_ESU100A:
	case QUATECH_ESU100B:
	case QUATECH_HSU100A:
	case QUATECH_HSU100B:
	case QUATECH_HSU100C:
	case QUATECH_HSU100D:
		DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS);
		DeviceData.porta |= CLKS_X4;
		DeviceData.portb &= ~(LOOPMODE_BITS);
		DeviceData.portb |= RS232_MODE;
		break;

	case QUATECH_SSU200:
	case QUATECH_DSU200:
	case QUATECH_QSU200:
	case QUATECH_ESU200A:
	case QUATECH_ESU200B:
	case QUATECH_HSU200A:
	case QUATECH_HSU200B:
	case QUATECH_HSU200C:
	case QUATECH_HSU200D:
		DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS);
		DeviceData.porta |= CLKS_X4;
		DeviceData.portb &= ~(LOOPMODE_BITS);
		DeviceData.portb |= ALL_LOOPBACK;
		break;
	default:
		DeviceData.porta &= ~(RR_BITS | DUPMODE_BITS);
		DeviceData.porta |= CLKS_X4;
		DeviceData.portb &= ~(LOOPMODE_BITS);
		DeviceData.portb |= RS232_MODE;
		break;

	}

	status = BoxSetPrebufferLevel(serial);	/* sets to default value */
	if (status < 0) {
		dev_dbg(dev, "BoxSetPrebufferLevel failed\n");
		goto startup_error;
	}

	status = BoxSetATC(serial, ATC_DISABLED);
	if (status < 0) {
		dev_dbg(dev, "BoxSetATC failed\n");
		goto startup_error;
	}

	dev_dbg(dev, "DeviceData.portb = 0x%x\n", DeviceData.portb);

	DeviceData.portb |= NEXT_BOARD_POWER_BIT;
	dev_dbg(dev, "Changing DeviceData.portb to 0x%x\n", DeviceData.portb);

	status = qt_set_device(serial, &DeviceData);
	if (status < 0) {
		dev_dbg(dev, "qt_set_device failed\n");
		goto startup_error;
	}

	return 0;

startup_error:
	for (i = 0; i < serial->num_ports; i++) {
		port = serial->port[i];
		qt_port = qt_get_port_private(port);
		kfree(qt_port);
		usb_set_serial_port_data(port, NULL);
	}

	return -EIO;
}
コード例 #10
0
ファイル: serqt_usb2.c プロジェクト: AiWinters/linux
static void qt_read_bulk_callback(struct urb *urb)
{

	struct usb_serial_port *port = urb->context;
	struct usb_serial *serial = get_usb_serial(port, __func__);
	struct quatech_port *qt_port = qt_get_port_private(port);
	int result;

	if (urb->status) {
		qt_port->ReadBulkStopped = 1;
		dev_dbg(&urb->dev->dev,
			"%s - nonzero write bulk status received: %d\n",
			__func__, urb->status);
		return;
	}

	dev_dbg(&port->dev,
		"%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);

	if (port_paranoia_check(port, __func__) != 0) {
		qt_port->ReadBulkStopped = 1;
		return;
	}

	if (!serial)
		return;

	if (qt_port->closePending == 1) {
		/* Were closing , stop reading */
		dev_dbg(&port->dev,
			"%s - (qt_port->closepending == 1\n", __func__);
		qt_port->ReadBulkStopped = 1;
		return;
	}

	/*
	 * RxHolding is asserted by throttle, if we assert it, we're not
	 * receiving any more characters and let the box handle the flow
	 * control
	 */
	if (qt_port->RxHolding == 1) {
		qt_port->ReadBulkStopped = 1;
		return;
	}

	if (urb->status) {
		qt_port->ReadBulkStopped = 1;

		dev_dbg(&port->dev,
			"%s - nonzero read bulk status received: %d\n",
			__func__, urb->status);
		return;
	}

	if (urb->actual_length)
		qt_status_change_check(urb, qt_port, port);

	/* Continue trying to always read  */
	usb_fill_bulk_urb(port->read_urb, serial->dev,
			  usb_rcvbulkpipe(serial->dev,
					  port->bulk_in_endpointAddress),
			  port->read_urb->transfer_buffer,
			  port->read_urb->transfer_buffer_length,
			  qt_read_bulk_callback, port);
	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
	if (result)
		dev_dbg(&port->dev,
			"%s - failed resubmitting read urb, error %d",
			__func__, result);
	else {
		if (urb->actual_length) {
			tty_flip_buffer_push(&port->port);
			tty_schedule_flip(&port->port);
		}
	}

	schedule_work(&port->work);
}