Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 208478
b: refs/heads/master
c: 5ba1821
h: refs/heads/master
v: v3
  • Loading branch information
Daniel Gl?ckner authored and Linus Torvalds committed Aug 11, 2010
1 parent 39e3896 commit 434a68a
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 54 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: 9c4ba9466117b16a2b85034bb87db528aaeb3f07
refs/heads/master: 5ba1821d1b4a506f8c9be93d962f22b24b6140a5
80 changes: 27 additions & 53 deletions trunk/drivers/gpio/gpiolib.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ struct gpio_desc {
#define FLAG_TRIG_RISE 6 /* trigger on rising edge */
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */

#define PDESC_ID_SHIFT 16 /* add new flags before this one */
#define ID_SHIFT 16 /* add new flags before this one */

#define GPIO_FLAGS_MASK ((1 << PDESC_ID_SHIFT) - 1)
#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))

#ifdef CONFIG_DEBUG_FS
Expand All @@ -69,12 +69,7 @@ struct gpio_desc {
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];

#ifdef CONFIG_GPIO_SYSFS
struct poll_desc {
struct work_struct work;
struct sysfs_dirent *value_sd;
};

static struct idr pdesc_idr;
static DEFINE_IDR(dirent_idr);
#endif

static inline void desc_set_label(struct gpio_desc *d, const char *label)
Expand Down Expand Up @@ -325,24 +320,16 @@ static const DEVICE_ATTR(value, 0644,

static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
{
struct work_struct *work = priv;
struct sysfs_dirent *value_sd = priv;

schedule_work(work);
sysfs_notify_dirent(value_sd);
return IRQ_HANDLED;
}

static void gpio_notify_sysfs(struct work_struct *work)
{
struct poll_desc *pdesc;

pdesc = container_of(work, struct poll_desc, work);
sysfs_notify_dirent(pdesc->value_sd);
}

static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
unsigned long gpio_flags)
{
struct poll_desc *pdesc;
struct sysfs_dirent *value_sd;
unsigned long irq_flags;
int ret, irq, id;

Expand All @@ -353,18 +340,16 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
if (irq < 0)
return -EIO;

id = desc->flags >> PDESC_ID_SHIFT;
pdesc = idr_find(&pdesc_idr, id);
if (pdesc) {
free_irq(irq, &pdesc->work);
cancel_work_sync(&pdesc->work);
}
id = desc->flags >> ID_SHIFT;
value_sd = idr_find(&dirent_idr, id);
if (value_sd)
free_irq(irq, value_sd);

desc->flags &= ~GPIO_TRIGGER_MASK;

if (!gpio_flags) {
ret = 0;
goto free_sd;
goto free_id;
}

irq_flags = IRQF_SHARED;
Expand All @@ -375,55 +360,46 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;

if (!pdesc) {
pdesc = kmalloc(sizeof(*pdesc), GFP_KERNEL);
if (!pdesc) {
ret = -ENOMEM;
if (!value_sd) {
value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value");
if (!value_sd) {
ret = -ENODEV;
goto err_out;
}

do {
ret = -ENOMEM;
if (idr_pre_get(&pdesc_idr, GFP_KERNEL))
ret = idr_get_new_above(&pdesc_idr,
pdesc, 1, &id);
if (idr_pre_get(&dirent_idr, GFP_KERNEL))
ret = idr_get_new_above(&dirent_idr, value_sd,
1, &id);
} while (ret == -EAGAIN);

if (ret)
goto free_mem;
goto free_sd;

desc->flags &= GPIO_FLAGS_MASK;
desc->flags |= (unsigned long)id << PDESC_ID_SHIFT;
desc->flags |= (unsigned long)id << ID_SHIFT;

if (desc->flags >> PDESC_ID_SHIFT != id) {
if (desc->flags >> ID_SHIFT != id) {
ret = -ERANGE;
goto free_id;
}

pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value");
if (!pdesc->value_sd) {
ret = -ENODEV;
goto free_id;
}
INIT_WORK(&pdesc->work, gpio_notify_sysfs);
}

ret = request_irq(irq, gpio_sysfs_irq, irq_flags,
"gpiolib", &pdesc->work);
"gpiolib", value_sd);
if (ret)
goto free_sd;
goto free_id;

desc->flags |= gpio_flags;
return 0;

free_sd:
if (pdesc)
sysfs_put(pdesc->value_sd);
free_id:
idr_remove(&pdesc_idr, id);
idr_remove(&dirent_idr, id);
desc->flags &= GPIO_FLAGS_MASK;
free_mem:
kfree(pdesc);
free_sd:
if (value_sd)
sysfs_put(value_sd);
err_out:
return ret;
}
Expand Down Expand Up @@ -994,8 +970,6 @@ static int __init gpiolib_sysfs_init(void)
unsigned long flags;
unsigned gpio;

idr_init(&pdesc_idr);

status = class_register(&gpio_class);
if (status < 0)
return status;
Expand Down

0 comments on commit 434a68a

Please sign in to comment.