Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10077d4a authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds
Browse files

tty: cdc_acm add krefs



Now we have a port structure begin using the fields and kref counts

Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b39933fb
Loading
Loading
Loading
Loading
+98 −66
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
#include <asm/byteorder.h>
@@ -87,7 +87,7 @@ static struct acm *acm_table[ACM_TTY_MINORS];

static DEFINE_MUTEX(open_mutex);

#define ACM_READY(acm)	(acm && acm->dev && acm->used)
#define ACM_READY(acm)	(acm && acm->dev && acm->port.count)

static const struct tty_port_operations acm_port_ops = {
};
@@ -265,6 +265,7 @@ static void acm_ctrl_irq(struct urb *urb)
{
	struct acm *acm = urb->context;
	struct usb_cdc_notification *dr = urb->transfer_buffer;
	struct tty_struct *tty;
	unsigned char *data;
	int newctrl;
	int retval;
@@ -297,12 +298,16 @@ static void acm_ctrl_irq(struct urb *urb)
			break;

		case USB_CDC_NOTIFY_SERIAL_STATE:

			tty = tty_port_tty_get(&acm->port);
			newctrl = get_unaligned_le16(data);

			if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
			if (tty) {
				if (!acm->clocal &&
				    (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
					dbg("calling hangup");
				tty_hangup(acm->tty);
					tty_hangup(tty);
				}
				tty_kref_put(tty);
			}

			acm->ctrlin = newctrl;
@@ -374,15 +379,14 @@ static void acm_rx_tasklet(unsigned long _acm)
{
	struct acm *acm = (void *)_acm;
	struct acm_rb *buf;
	struct tty_struct *tty = acm->tty;
	struct tty_struct *tty;
	struct acm_ru *rcv;
	unsigned long flags;
	unsigned char throttled;

	dbg("Entering acm_rx_tasklet");

	if (!ACM_READY(acm))
	{
	if (!ACM_READY(acm)) {
		dbg("acm_rx_tasklet: ACM not ready");
		return;
	}
@@ -390,12 +394,13 @@ static void acm_rx_tasklet(unsigned long _acm)
	spin_lock_irqsave(&acm->throttle_lock, flags);
	throttled = acm->throttle;
	spin_unlock_irqrestore(&acm->throttle_lock, flags);
	if (throttled)
	{
	if (throttled) {
		dbg("acm_rx_tasklet: throttled");
		return;
	}

	tty = tty_port_tty_get(&acm->port);

next_buffer:
	spin_lock_irqsave(&acm->read_lock, flags);
	if (list_empty(&acm->filled_read_bufs)) {
@@ -409,21 +414,23 @@ static void acm_rx_tasklet(unsigned long _acm)

	dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);

	tty_buffer_request_room(tty, buf->size);
	if (tty) {
		spin_lock_irqsave(&acm->throttle_lock, flags);
		throttled = acm->throttle;
		spin_unlock_irqrestore(&acm->throttle_lock, flags);
	if (!throttled)
		if (!throttled) {
			tty_buffer_request_room(tty, buf->size);
			tty_insert_flip_string(tty, buf->base, buf->size);
			tty_flip_buffer_push(tty);

	if (throttled) {
		} else {
			tty_kref_put(tty);
			dbg("Throttling noticed");
			spin_lock_irqsave(&acm->read_lock, flags);
			list_add(&buf->list, &acm->filled_read_bufs);
			spin_unlock_irqrestore(&acm->read_lock, flags);
			return;
		}
	}

	spin_lock_irqsave(&acm->read_lock, flags);
	list_add(&buf->list, &acm->spare_read_bufs);
@@ -431,6 +438,8 @@ static void acm_rx_tasklet(unsigned long _acm)
	goto next_buffer;

urbs:
	tty_kref_put(tty);

	while (!list_empty(&acm->spare_read_bufs)) {
		spin_lock_irqsave(&acm->read_lock, flags);
		if (list_empty(&acm->spare_read_urbs)) {
@@ -502,11 +511,14 @@ static void acm_write_bulk(struct urb *urb)
static void acm_softint(struct work_struct *work)
{
	struct acm *acm = container_of(work, struct acm, work);
	struct tty_struct *tty;

	dev_vdbg(&acm->data->dev, "tx work\n");
	if (!ACM_READY(acm))
		return;
	tty_wakeup(acm->tty);
	tty = tty_port_tty_get(&acm->port);
	tty_wakeup(tty);
	tty_kref_put(tty);
}

static void acm_waker(struct work_struct *waker)
@@ -546,8 +558,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
		rv = 0;

	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);

	tty->driver_data = acm;
	acm->tty = tty;
	tty_port_tty_set(&acm->port, tty);

	if (usb_autopm_get_interface(acm->control) < 0)
		goto early_bail;
@@ -555,12 +568,11 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
		acm->control->needs_remote_wakeup = 1;

	mutex_lock(&acm->mutex);
	if (acm->used++) {
	if (acm->port.count++) {
		usb_autopm_put_interface(acm->control);
		goto done;
	}


	acm->ctrlurb->dev = acm->dev;
	if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
		dbg("usb_submit_urb(ctrl irq) failed");
@@ -570,6 +582,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
	if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
	    (acm->ctrl_caps & USB_CDC_CAP_LINE))
		goto full_bailout;

	usb_autopm_put_interface(acm->control);

	INIT_LIST_HEAD(&acm->spare_read_urbs);
@@ -585,7 +598,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
	acm->throttle = 0;

	tasklet_schedule(&acm->urb_task);

	rv = tty_port_block_til_ready(&acm->port, tty, filp);
done:
	mutex_unlock(&acm->mutex);
err_out:
@@ -596,10 +609,11 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
	usb_kill_urb(acm->ctrlurb);
bail_out:
	usb_autopm_put_interface(acm->control);
	acm->used--;
	acm->port.count--;
	mutex_unlock(&acm->mutex);
early_bail:
	mutex_unlock(&open_mutex);
	tty_port_tty_set(&acm->port, NULL);
	return -EIO;
}

@@ -622,27 +636,19 @@ static void acm_tty_unregister(struct acm *acm)

static int acm_tty_chars_in_buffer(struct tty_struct *tty);

static void acm_tty_close(struct tty_struct *tty, struct file *filp)
static void acm_port_down(struct acm *acm, int drain)
{
	struct acm *acm = tty->driver_data;
	int i,nr;

	if (!acm || !acm->used)
		return;

	nr = acm->rx_buflimit;
	int i, nr = acm->rx_buflimit;
	mutex_lock(&open_mutex);
	if (!--acm->used) {
	if (acm->dev) {
		usb_autopm_get_interface(acm->control);
		acm_set_control(acm, acm->ctrlout = 0);

		/* try letting the last writes drain naturally */
		if (drain) {
			wait_event_interruptible_timeout(acm->drain_wait,
					(ACM_NW == acm_wb_is_avail(acm))
						|| !acm->dev,
				(ACM_NW == acm_wb_is_avail(acm)) || !acm->dev,
					ACM_CLOSE_TIMEOUT * HZ);

		}
		usb_kill_urb(acm->ctrlurb);
		for (i = 0; i < ACM_NW; i++)
			usb_kill_urb(acm->wb[i].urb);
@@ -650,12 +656,34 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
			usb_kill_urb(acm->ru[i].urb);
		acm->control->needs_remote_wakeup = 0;
		usb_autopm_put_interface(acm->control);
		} else
			acm_tty_unregister(acm);
	}
	mutex_unlock(&open_mutex);
}

static void acm_tty_hangup(struct tty_struct *tty)
{
	struct acm *acm = tty->driver_data;
	tty_port_hangup(&acm->port);
	acm_port_down(acm, 0);
}

static void acm_tty_close(struct tty_struct *tty, struct file *filp)
{
	struct acm *acm = tty->driver_data;

	/* Perform the closing process and see if we need to do the hardware
	   shutdown */
	if (tty_port_close_start(&acm->port, tty, filp) == 0)
		return;
	acm_port_down(acm, 0);
	tty_port_close_end(&acm->port, tty);
	mutex_lock(&open_mutex);
	tty_port_tty_set(&acm->port, NULL);
	if (!acm->dev)
		acm_tty_unregister(acm);
	mutex_unlock(&open_mutex);
}

static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
	struct acm *acm = tty->driver_data;
@@ -1232,6 +1260,7 @@ static void acm_disconnect(struct usb_interface *intf)
{
	struct acm *acm = usb_get_intfdata(intf);
	struct usb_device *usb_dev = interface_to_usbdev(intf);
	struct tty_struct *tty;

	/* sibling interface is already cleaning up */
	if (!acm)
@@ -1258,16 +1287,18 @@ static void acm_disconnect(struct usb_interface *intf)
	usb_driver_release_interface(&acm_driver, intf == acm->control ?
					acm->data : acm->control);

	if (!acm->used) {
	if (acm->port.count == 0) {
		acm_tty_unregister(acm);
		mutex_unlock(&open_mutex);
		return;
	}

	mutex_unlock(&open_mutex);

	if (acm->tty)
		tty_hangup(acm->tty);
	tty = tty_port_tty_get(&acm->port);
	if (tty) {
		tty_hangup(tty);
		tty_kref_put(tty);
	}
}

#ifdef CONFIG_PM
@@ -1302,7 +1333,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
	*/
	mutex_lock(&acm->mutex);

	if (acm->used)
	if (acm->port.count)
		stop_data_traffic(acm);

	mutex_unlock(&acm->mutex);
@@ -1324,7 +1355,7 @@ static int acm_resume(struct usb_interface *intf)
		return 0;

	mutex_lock(&acm->mutex);
	if (acm->used) {
	if (acm->port.count) {
		rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
		if (rv < 0)
			goto err_out;
@@ -1434,6 +1465,7 @@ static struct usb_driver acm_driver = {
static const struct tty_operations acm_ops = {
	.open =			acm_tty_open,
	.close =		acm_tty_close,
	.hangup =		acm_tty_hangup,
	.write =		acm_tty_write,
	.write_room =		acm_tty_write_room,
	.ioctl =		acm_tty_ioctl,
+0 −2
Original line number Diff line number Diff line
@@ -89,7 +89,6 @@ struct acm {
	struct usb_device *dev;				/* the corresponding usb device */
	struct usb_interface *control;			/* control interface */
	struct usb_interface *data;			/* data interface */
	struct tty_struct *tty;				/* the corresponding tty */
	struct tty_port port;			 	/* our tty port data */
	struct urb *ctrlurb;				/* urbs */
	u8 *ctrl_buffer;				/* buffers of urbs */
@@ -121,7 +120,6 @@ struct acm {
	unsigned int ctrlout;				/* output control lines (DTR, RTS) */
	unsigned int writesize;				/* max packet size for the output bulk endpoint */
	unsigned int readsize,ctrlsize;			/* buffer sizes for freeing */
	unsigned int used;				/* someone has this acm's device open */
	unsigned int minor;				/* acm minor number */
	unsigned char throttle;				/* throttled by tty layer */
	unsigned char clocal;				/* termios CLOCAL */