Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/leds/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 4 kB image not shown  

Quelle  uleds.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Userspace driver for the LED subsystem
 *
 * Copyright (C) 2016 David Lechner <david@lechnology.com>
 *
 * Based on uinput.c: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
 */

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/leds.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>

#include <uapi/linux/uleds.h>

#define ULEDS_NAME "uleds"

enum uleds_state {
 ULEDS_STATE_UNKNOWN,
 ULEDS_STATE_REGISTERED,
};

struct uleds_device {
 struct uleds_user_dev user_dev;
 struct led_classdev led_cdev;
 struct mutex  mutex;
 enum uleds_state state;
 wait_queue_head_t waitq;
 int   brightness;
 bool   new_data;
};

static struct miscdevice uleds_misc;

static void uleds_brightness_set(struct led_classdev *led_cdev,
     enum led_brightness brightness)
{
 struct uleds_device *udev = container_of(led_cdev, struct uleds_device,
       led_cdev);

 if (udev->brightness != brightness) {
  udev->brightness = brightness;
  udev->new_data = true;
  wake_up_interruptible(&udev->waitq);
 }
}

static int uleds_open(struct inode *inode, struct file *file)
{
 struct uleds_device *udev;

 udev = kzalloc(sizeof(*udev), GFP_KERNEL);
 if (!udev)
  return -ENOMEM;

 udev->led_cdev.name = udev->user_dev.name;
 udev->led_cdev.brightness_set = uleds_brightness_set;

 mutex_init(&udev->mutex);
 init_waitqueue_head(&udev->waitq);
 udev->state = ULEDS_STATE_UNKNOWN;

 file->private_data = udev;
 stream_open(inode, file);

 return 0;
}

static ssize_t uleds_write(struct file *file, const char __user *buffer,
      size_t count, loff_t *ppos)
{
 struct uleds_device *udev = file->private_data;
 const char *name;
 int ret;

 if (count == 0)
  return 0;

 ret = mutex_lock_interruptible(&udev->mutex);
 if (ret)
  return ret;

 if (udev->state == ULEDS_STATE_REGISTERED) {
  ret = -EBUSY;
  goto out;
 }

 if (count != sizeof(struct uleds_user_dev)) {
  ret = -EINVAL;
  goto out;
 }

 if (copy_from_user(&udev->user_dev, buffer,
      sizeof(struct uleds_user_dev))) {
  ret = -EFAULT;
  goto out;
 }

 name = udev->user_dev.name;
 if (!name[0] || !strcmp(name, ".") || !strcmp(name, "..") ||
     strchr(name, '/')) {
  ret = -EINVAL;
  goto out;
 }

 if (udev->user_dev.max_brightness <= 0) {
  ret = -EINVAL;
  goto out;
 }
 udev->led_cdev.max_brightness = udev->user_dev.max_brightness;

 ret = devm_led_classdev_register(uleds_misc.this_device,
      &udev->led_cdev);
 if (ret < 0)
  goto out;

 udev->new_data = true;
 udev->state = ULEDS_STATE_REGISTERED;
 ret = count;

out:
 mutex_unlock(&udev->mutex);

 return ret;
}

static ssize_t uleds_read(struct file *file, char __user *buffer, size_t count,
     loff_t *ppos)
{
 struct uleds_device *udev = file->private_data;
 ssize_t retval;

 if (count < sizeof(udev->brightness))
  return 0;

 do {
  retval = mutex_lock_interruptible(&udev->mutex);
  if (retval)
   return retval;

  if (udev->state != ULEDS_STATE_REGISTERED) {
   retval = -ENODEV;
  } else if (!udev->new_data && (file->f_flags & O_NONBLOCK)) {
   retval = -EAGAIN;
  } else if (udev->new_data) {
   retval = copy_to_user(buffer, &udev->brightness,
           sizeof(udev->brightness));
   udev->new_data = false;
   retval = sizeof(udev->brightness);
  }

  mutex_unlock(&udev->mutex);

  if (retval)
   break;

  if (!(file->f_flags & O_NONBLOCK))
   retval = wait_event_interruptible(udev->waitq,
     udev->new_data ||
     udev->state != ULEDS_STATE_REGISTERED);
 } while (retval == 0);

 return retval;
}

static __poll_t uleds_poll(struct file *file, poll_table *wait)
{
 struct uleds_device *udev = file->private_data;

 poll_wait(file, &udev->waitq, wait);

 if (udev->new_data)
  return EPOLLIN | EPOLLRDNORM;

 return 0;
}

static int uleds_release(struct inode *inode, struct file *file)
{
 struct uleds_device *udev = file->private_data;

 if (udev->state == ULEDS_STATE_REGISTERED) {
  udev->state = ULEDS_STATE_UNKNOWN;
  devm_led_classdev_unregister(uleds_misc.this_device,
          &udev->led_cdev);
 }
 kfree(udev);

 return 0;
}

static const struct file_operations uleds_fops = {
 .owner  = THIS_MODULE,
 .open  = uleds_open,
 .release = uleds_release,
 .read  = uleds_read,
 .write  = uleds_write,
 .poll  = uleds_poll,
};

static struct miscdevice uleds_misc = {
 .fops  = &uleds_fops,
 .minor  = MISC_DYNAMIC_MINOR,
 .name  = ULEDS_NAME,
};

module_misc_device(uleds_misc);

MODULE_AUTHOR("David Lechner ");
MODULE_DESCRIPTION("Userspace driver for the LED subsystem");
MODULE_LICENSE("GPL");

Messung V0.5
C=95 H=92 G=93

¤ Dauer der Verarbeitung: 0.2 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.