Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 346930
b: refs/heads/master
c: 2be975c
h: refs/heads/master
v: v3
  • Loading branch information
Dmitry Torokhov committed Nov 8, 2012
1 parent 6dc9389 commit 4cf5ef1
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 29 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: fa8e2458ecfc959cd627e25ba86d8eddcb63c887
refs/heads/master: 2be975c6d920de989ff5e4bc09ffe87e59d94662
176 changes: 149 additions & 27 deletions trunk/drivers/input/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -1726,7 +1726,7 @@ EXPORT_SYMBOL_GPL(input_class);
/**
* input_allocate_device - allocate memory for new input device
*
* Returns prepared struct input_dev or NULL.
* Returns prepared struct input_dev or %NULL.
*
* NOTE: Use input_free_device() to free devices that have not been
* registered; input_unregister_device() should be used for already
Expand All @@ -1753,6 +1753,70 @@ struct input_dev *input_allocate_device(void)
}
EXPORT_SYMBOL(input_allocate_device);

struct input_devres {
struct input_dev *input;
};

static int devm_input_device_match(struct device *dev, void *res, void *data)
{
struct input_devres *devres = res;

return devres->input == data;
}

static void devm_input_device_release(struct device *dev, void *res)
{
struct input_devres *devres = res;
struct input_dev *input = devres->input;

dev_dbg(dev, "%s: dropping reference to %s\n",
__func__, dev_name(&input->dev));
input_put_device(input);
}

/**
* devm_input_allocate_device - allocate managed input device
* @dev: device owning the input device being created
*
* Returns prepared struct input_dev or %NULL.
*
* Managed input devices do not need to be explicitly unregistered or
* freed as it will be done automatically when owner device unbinds from
* its driver (or binding fails). Once managed input device is allocated,
* it is ready to be set up and registered in the same fashion as regular
* input device. There are no special devm_input_device_[un]register()
* variants, regular ones work with both managed and unmanaged devices.
*
* NOTE: the owner device is set up as parent of input device and users
* should not override it.
*/

struct input_dev *devm_input_allocate_device(struct device *dev)
{
struct input_dev *input;
struct input_devres *devres;

devres = devres_alloc(devm_input_device_release,
sizeof(struct input_devres), GFP_KERNEL);
if (!devres)
return NULL;

input = input_allocate_device();
if (!input) {
devres_free(devres);
return NULL;
}

input->dev.parent = dev;
input->devres_managed = true;

devres->input = input;
devres_add(dev, devres);

return input;
}
EXPORT_SYMBOL(devm_input_allocate_device);

/**
* input_free_device - free memory occupied by input_dev structure
* @dev: input device to free
Expand All @@ -1769,8 +1833,14 @@ EXPORT_SYMBOL(input_allocate_device);
*/
void input_free_device(struct input_dev *dev)
{
if (dev)
if (dev) {
if (dev->devres_managed)
WARN_ON(devres_destroy(dev->dev.parent,
devm_input_device_release,
devm_input_device_match,
dev));
input_put_device(dev);
}
}
EXPORT_SYMBOL(input_free_device);

Expand Down Expand Up @@ -1891,6 +1961,38 @@ static void input_cleanse_bitmasks(struct input_dev *dev)
INPUT_CLEANSE_BITMASK(dev, SW, sw);
}

static void __input_unregister_device(struct input_dev *dev)
{
struct input_handle *handle, *next;

input_disconnect_device(dev);

mutex_lock(&input_mutex);

list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
handle->handler->disconnect(handle);
WARN_ON(!list_empty(&dev->h_list));

del_timer_sync(&dev->timer);
list_del_init(&dev->node);

input_wakeup_procfs_readers();

mutex_unlock(&input_mutex);

device_del(&dev->dev);
}

static void devm_input_device_unregister(struct device *dev, void *res)
{
struct input_devres *devres = res;
struct input_dev *input = devres->input;

dev_dbg(dev, "%s: unregistering device %s\n",
__func__, dev_name(&input->dev));
__input_unregister_device(input);
}

/**
* input_register_device - register device with input core
* @dev: device to be registered
Expand All @@ -1906,11 +2008,21 @@ static void input_cleanse_bitmasks(struct input_dev *dev)
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
struct input_devres *devres = NULL;
struct input_handler *handler;
unsigned int packet_size;
const char *path;
int error;

if (dev->devres_managed) {
devres = devres_alloc(devm_input_device_unregister,
sizeof(struct input_devres), GFP_KERNEL);
if (!devres)
return -ENOMEM;

devres->input = dev;
}

/* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit);

Expand All @@ -1926,8 +2038,10 @@ int input_register_device(struct input_dev *dev)

dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
if (!dev->vals)
return -ENOMEM;
if (!dev->vals) {
error = -ENOMEM;
goto err_devres_free;
}

/*
* If delay and period are pre-set by the driver, then autorepeating
Expand All @@ -1952,7 +2066,7 @@ int input_register_device(struct input_dev *dev)

error = device_add(&dev->dev);
if (error)
return error;
goto err_free_vals;

path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
pr_info("%s as %s\n",
Expand All @@ -1961,10 +2075,8 @@ int input_register_device(struct input_dev *dev)
kfree(path);

error = mutex_lock_interruptible(&input_mutex);
if (error) {
device_del(&dev->dev);
return error;
}
if (error)
goto err_device_del;

list_add_tail(&dev->node, &input_dev_list);

Expand All @@ -1975,7 +2087,21 @@ int input_register_device(struct input_dev *dev)

mutex_unlock(&input_mutex);

if (dev->devres_managed) {
dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
__func__, dev_name(&dev->dev));
devres_add(dev->dev.parent, devres);
}
return 0;

err_device_del:
device_del(&dev->dev);
err_free_vals:
kfree(dev->vals);
dev->vals = NULL;
err_devres_free:
devres_free(devres);
return error;
}
EXPORT_SYMBOL(input_register_device);

Expand All @@ -1988,24 +2114,20 @@ EXPORT_SYMBOL(input_register_device);
*/
void input_unregister_device(struct input_dev *dev)
{
struct input_handle *handle, *next;

input_disconnect_device(dev);

mutex_lock(&input_mutex);

list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
handle->handler->disconnect(handle);
WARN_ON(!list_empty(&dev->h_list));

del_timer_sync(&dev->timer);
list_del_init(&dev->node);

input_wakeup_procfs_readers();

mutex_unlock(&input_mutex);

device_unregister(&dev->dev);
if (dev->devres_managed) {
WARN_ON(devres_destroy(dev->dev.parent,
devm_input_device_unregister,
devm_input_device_match,
dev));
__input_unregister_device(dev);
/*
* We do not do input_put_device() here because it will be done
* when 2nd devres fires up.
*/
} else {
__input_unregister_device(dev);
input_put_device(dev);
}
}
EXPORT_SYMBOL(input_unregister_device);

Expand Down
7 changes: 6 additions & 1 deletion trunk/include/linux/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ struct input_value {
* @h_list: list of input handles associated with the device. When
* accessing the list dev->mutex must be held
* @node: used to place the device onto input_dev_list
* @devres_managed: indicates that devices is managed with devres framework
* and needs not be explicitly unregistered or freed.
*/
struct input_dev {
const char *name;
Expand Down Expand Up @@ -180,6 +182,8 @@ struct input_dev {
unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;

bool devres_managed;
};
#define to_input_dev(d) container_of(d, struct input_dev, dev)

Expand Down Expand Up @@ -323,7 +327,8 @@ struct input_handle {
struct list_head h_node;
};

struct input_dev *input_allocate_device(void);
struct input_dev __must_check *input_allocate_device(void);
struct input_dev __must_check *devm_input_allocate_device(struct device *);
void input_free_device(struct input_dev *dev);

static inline struct input_dev *input_get_device(struct input_dev *dev)
Expand Down

0 comments on commit 4cf5ef1

Please sign in to comment.