Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 289656
b: refs/heads/master
c: 3cc3615
h: refs/heads/master
v: v3
  • Loading branch information
Bjørn Mork authored and Greg Kroah-Hartman committed Mar 8, 2012
1 parent 7ac3a97 commit cd9a2db
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b0c13860808a528cd580fdca61aef9f73352a331
refs/heads/master: 3cc3615749dbd1b891512d5c9a5bf4559cfa9741
63 changes: 59 additions & 4 deletions trunk/drivers/usb/class/cdc-wdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <linux/usb/cdc.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <linux/usb/cdc-wdm.h>

/*
* Version Information
Expand Down Expand Up @@ -116,6 +117,7 @@ struct wdm_device {
int rerr;

struct list_head device_list;
int (*manage_power)(struct usb_interface *, int);
};

static struct usb_driver wdm_driver;
Expand Down Expand Up @@ -580,7 +582,6 @@ static int wdm_open(struct inode *inode, struct file *file)
dev_err(&desc->intf->dev, "Error autopm - %d\n", rv);
goto out;
}
intf->needs_remote_wakeup = 1;

/* using write lock to protect desc->count */
mutex_lock(&desc->wlock);
Expand All @@ -597,6 +598,8 @@ static int wdm_open(struct inode *inode, struct file *file)
rv = 0;
}
mutex_unlock(&desc->wlock);
if (desc->count == 1)
desc->manage_power(intf, 1);
usb_autopm_put_interface(desc->intf);
out:
mutex_unlock(&wdm_mutex);
Expand All @@ -618,7 +621,7 @@ static int wdm_release(struct inode *inode, struct file *file)
dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
kill_urbs(desc);
if (!test_bit(WDM_DISCONNECTING, &desc->flags))
desc->intf->needs_remote_wakeup = 0;
desc->manage_power(desc->intf, 0);
}
mutex_unlock(&wdm_mutex);
return 0;
Expand Down Expand Up @@ -665,7 +668,8 @@ static void wdm_rxwork(struct work_struct *work)

/* --- hotplug --- */

static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep, u16 bufsize)
static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
u16 bufsize, int (*manage_power)(struct usb_interface *, int))
{
int rv = -ENOMEM;
struct wdm_device *desc;
Expand Down Expand Up @@ -750,6 +754,8 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
desc
);

desc->manage_power = manage_power;

spin_lock(&wdm_device_list_lock);
list_add(&desc->device_list, &wdm_device_list);
spin_unlock(&wdm_device_list_lock);
Expand All @@ -766,6 +772,19 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
return rv;
}

static int wdm_manage_power(struct usb_interface *intf, int on)
{
/* need autopm_get/put here to ensure the usbcore sees the new value */
int rv = usb_autopm_get_interface(intf);
if (rv < 0)
goto err;

intf->needs_remote_wakeup = on;
usb_autopm_put_interface(intf);
err:
return rv;
}

static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
int rv = -EINVAL;
Expand Down Expand Up @@ -809,12 +828,48 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto err;
ep = &iface->endpoint[0].desc;

rv = wdm_create(intf, ep, maxcom);
rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);

err:
return rv;
}

/**
* usb_cdc_wdm_register - register a WDM subdriver
* @intf: usb interface the subdriver will associate with
* @ep: interrupt endpoint to monitor for notifications
* @bufsize: maximum message size to support for read/write
*
* Create WDM usb class character device and associate it with intf
* without binding, allowing another driver to manage the interface.
*
* The subdriver will manage the given interrupt endpoint exclusively
* and will issue control requests referring to the given intf. It
* will otherwise avoid interferring, and in particular not do
* usb_set_intfdata/usb_get_intfdata on intf.
*
* The return value is a pointer to the subdriver's struct usb_driver.
* The registering driver is responsible for calling this subdriver's
* disconnect, suspend, resume, pre_reset and post_reset methods from
* its own.
*/
struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep,
int bufsize,
int (*manage_power)(struct usb_interface *, int))
{
int rv = -EINVAL;

rv = wdm_create(intf, ep, bufsize, manage_power);
if (rv < 0)
goto err;

return &wdm_driver;
err:
return ERR_PTR(rv);
}
EXPORT_SYMBOL(usb_cdc_wdm_register);

static void wdm_disconnect(struct usb_interface *intf)
{
struct wdm_device *desc;
Expand Down
19 changes: 19 additions & 0 deletions trunk/include/linux/usb/cdc-wdm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* USB CDC Device Management subdriver
*
* Copyright (c) 2012 Bjørn Mork <bjorn@mork.no>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/

#ifndef __LINUX_USB_CDC_WDM_H
#define __LINUX_USB_CDC_WDM_H

extern struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep,
int bufsize,
int (*manage_power)(struct usb_interface *, int));

#endif /* __LINUX_USB_CDC_WDM_H */

0 comments on commit cd9a2db

Please sign in to comment.