cregit-Linux how code gets into the kernel

Release 4.11 drivers/staging/greybus/light.c

/*
 * Greybus Lights protocol driver.
 *
 * Copyright 2015 Google Inc.
 * Copyright 2015 Linaro Ltd.
 *
 * Released under the GPLv2 only.
 */

#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/led-class-flash.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <media/v4l2-flash-led-class.h>

#include "greybus.h"
#include "greybus_protocols.h"


#define NAMES_MAX	32


struct gb_channel {
	
u8				id;
	
u32				flags;
	
u32				color;
	
char				*color_name;
	
u8				fade_in;
	
u8				fade_out;
	
u32				mode;
	
char				*mode_name;
	
struct attribute		**attrs;
	
struct attribute_group		*attr_group;
	
const struct attribute_group	**attr_groups;
	
struct led_classdev		*led;
#if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH)
	
struct led_classdev_flash	fled;
	
struct led_flash_setting	intensity_uA;
	
struct led_flash_setting	timeout_us;
#else
	
struct led_classdev		cled;
#endif
	
struct gb_light			*light;
	
bool				is_registered;
	
bool				releasing;
	
bool				strobe_state;
	
bool				active;
	
struct mutex			lock;
};


struct gb_light {
	
u8			id;
	
char			*name;
	
struct gb_lights	*glights;
	
u32			flags;
	
u8			channels_count;
	
struct gb_channel	*channels;
	
bool			has_flash;
	
bool			ready;
#if IS_REACHABLE(CONFIG_V4L2_FLASH_LED_CLASS)
	
struct v4l2_flash	*v4l2_flash;
#endif
};


struct gb_lights {
	
struct gb_connection	*connection;
	
u8			lights_count;
	
struct gb_light		*lights;
	
struct mutex		lights_lock;
};

static void gb_lights_channel_free(struct gb_channel *channel);


static struct gb_connection *get_conn_from_channel(struct gb_channel *channel) { return channel->light->glights->connection; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva22100.00%1100.00%
Total22100.00%1100.00%


static struct gb_connection *get_conn_from_light(struct gb_light *light) { return light->glights->connection; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva20100.00%1100.00%
Total20100.00%1100.00%


static bool is_channel_flash(struct gb_channel *channel) { return !!(channel->mode & (GB_CHANNEL_MODE_FLASH | GB_CHANNEL_MODE_TORCH | GB_CHANNEL_MODE_INDICATOR)); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva28100.00%1100.00%
Total28100.00%1100.00%

#if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH)
static struct gb_channel *get_channel_from_cdev(struct led_classdev *cdev) { struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(cdev); return container_of(fled_cdev, struct gb_channel, fled); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva34100.00%1100.00%
Total34100.00%1100.00%


static struct led_classdev *get_channel_cdev(struct gb_channel *channel) { return &channel->fled.led_cdev; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva21100.00%1100.00%
Total21100.00%1100.00%


static struct gb_channel *get_channel_from_mode(struct gb_light *light, u32 mode) { struct gb_channel *channel = NULL; int i; for (i = 0; i < light->channels_count; i++) { channel = &light->channels[i]; if (channel && channel->mode == mode) break; } return channel; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva67100.00%1100.00%
Total67100.00%1100.00%


static int __gb_lights_flash_intensity_set(struct gb_channel *channel, u32 intensity) { struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_flash_intensity_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.intensity_uA = cpu_to_le32(intensity); ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_INTENSITY, &req, sizeof(req), NULL, 0); gb_pm_runtime_put_autosuspend(bundle); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva8468.85%150.00%
Kris Huang3831.15%150.00%
Total122100.00%2100.00%


static int __gb_lights_flash_brightness_set(struct gb_channel *channel) { u32 intensity; /* If the channel is flash we need to get the attached torch channel */ if (channel->mode & GB_CHANNEL_MODE_FLASH) channel = get_channel_from_mode(channel->light, GB_CHANNEL_MODE_TORCH); /* For not flash we need to convert brightness to intensity */ intensity = channel->intensity_uA.min + (channel->intensity_uA.step * channel->led->brightness); return __gb_lights_flash_intensity_set(channel, intensity); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva65100.00%1100.00%
Total65100.00%1100.00%

#else
static struct gb_channel *get_channel_from_cdev(struct led_classdev *cdev) { return container_of(cdev, struct gb_channel, cled); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva24100.00%1100.00%
Total24100.00%1100.00%


static struct led_classdev *get_channel_cdev(struct gb_channel *channel) { return &channel->cled; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva19100.00%1100.00%
Total19100.00%1100.00%


static int __gb_lights_flash_brightness_set(struct gb_channel *channel) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva14100.00%1100.00%
Total14100.00%1100.00%

#endif static int gb_lights_color_set(struct gb_channel *channel, u32 color); static int gb_lights_fade_set(struct gb_channel *channel);
static void led_lock(struct led_classdev *cdev) { mutex_lock(&cdev->led_access); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva19100.00%1100.00%
Total19100.00%1100.00%


static void led_unlock(struct led_classdev *cdev) { mutex_unlock(&cdev->led_access); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva19100.00%1100.00%
Total19100.00%1100.00%

#define gb_lights_fade_attr(__dir) \ static ssize_t fade_##__dir##_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ struct led_classdev *cdev = dev_get_drvdata(dev); \ struct gb_channel *channel = get_channel_from_cdev(cdev); \ \ return sprintf(buf, "%u\n", channel->fade_##__dir); \ } \ \ static ssize_t fade_##__dir##_store(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t size) \ { \ struct led_classdev *cdev = dev_get_drvdata(dev); \ struct gb_channel *channel = get_channel_from_cdev(cdev); \ u8 fade; \ int ret; \ \ led_lock(cdev); \ if (led_sysfs_is_disabled(cdev)) { \ ret = -EBUSY; \ goto unlock; \ } \ \ ret = kstrtou8(buf, 0, &fade); \ if (ret < 0) { \ dev_err(dev, "could not parse fade value %d\n", ret); \ goto unlock; \ } \ if (channel->fade_##__dir == fade) \ goto unlock; \ channel->fade_##__dir = fade; \ \ ret = gb_lights_fade_set(channel); \ if (ret < 0) \ goto unlock; \ \ ret = size; \ unlock: \ led_unlock(cdev); \ return ret; \ } \ static DEVICE_ATTR_RW(fade_##__dir) gb_lights_fade_attr(in); gb_lights_fade_attr(out);
static ssize_t color_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *cdev = dev_get_drvdata(dev); struct gb_channel *channel = get_channel_from_cdev(cdev); return sprintf(buf, "0x%08x\n", channel->color); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva52100.00%1100.00%
Total52100.00%1100.00%


static ssize_t color_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct led_classdev *cdev = dev_get_drvdata(dev); struct gb_channel *channel = get_channel_from_cdev(cdev); u32 color; int ret; led_lock(cdev); if (led_sysfs_is_disabled(cdev)) { ret = -EBUSY; goto unlock; } ret = kstrtou32(buf, 0, &color); if (ret < 0) { dev_err(dev, "could not parse color value %d\n", ret); goto unlock; } ret = gb_lights_color_set(channel, color); if (ret < 0) goto unlock; channel->color = color; ret = size; unlock: led_unlock(cdev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva142100.00%1100.00%
Total142100.00%1100.00%

static DEVICE_ATTR_RW(color);
static int channel_attr_groups_set(struct gb_channel *channel, struct led_classdev *cdev) { int attr = 0; int size = 0; if (channel->flags & GB_LIGHT_CHANNEL_MULTICOLOR) size++; if (channel->flags & GB_LIGHT_CHANNEL_FADER) size += 2; if (!size) return 0; /* Set attributes based in the channel flags */ channel->attrs = kcalloc(size + 1, sizeof(*channel->attrs), GFP_KERNEL); if (!channel->attrs) return -ENOMEM; channel->attr_group = kcalloc(1, sizeof(*channel->attr_group), GFP_KERNEL); if (!channel->attr_group) return -ENOMEM; channel->attr_groups = kcalloc(2, sizeof(*channel->attr_groups), GFP_KERNEL); if (!channel->attr_groups) return -ENOMEM; if (channel->flags & GB_LIGHT_CHANNEL_MULTICOLOR) channel->attrs[attr++] = &dev_attr_color.attr; if (channel->flags & GB_LIGHT_CHANNEL_FADER) { channel->attrs[attr++] = &dev_attr_fade_in.attr; channel->attrs[attr++] = &dev_attr_fade_out.attr; } channel->attr_group->attrs = channel->attrs; channel->attr_groups[0] = channel->attr_group; cdev->groups = channel->attr_groups; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva23598.33%150.00%
David Lin41.67%150.00%
Total239100.00%2100.00%


static int gb_lights_fade_set(struct gb_channel *channel) { struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_fade_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.fade_in = channel->fade_in; req.fade_out = channel->fade_out; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FADE, &req, sizeof(req), NULL, 0); gb_pm_runtime_put_autosuspend(bundle); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva8869.84%150.00%
Kris Huang3830.16%150.00%
Total126100.00%2100.00%


static int gb_lights_color_set(struct gb_channel *channel, u32 color) { struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_color_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.color = cpu_to_le32(color); ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_COLOR, &req, sizeof(req), NULL, 0); gb_pm_runtime_put_autosuspend(bundle); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva8468.85%150.00%
Kris Huang3831.15%150.00%
Total122100.00%2100.00%


static int __gb_lights_led_brightness_set(struct gb_channel *channel) { struct gb_lights_set_brightness_request req; struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; bool old_active; int ret; mutex_lock(&channel->lock); ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) goto out_unlock; old_active = channel->active; req.light_id = channel->light->id; req.channel_id = channel->id; req.brightness = (u8)channel->led->brightness; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_BRIGHTNESS, &req, sizeof(req), NULL, 0); if (ret < 0) goto out_pm_put; if (channel->led->brightness) channel->active = true; else channel->active = false; /* we need to keep module alive when turning to active state */ if (!old_active && channel->active) goto out_unlock; /* * on the other hand if going to inactive we still hold a reference and * need to put it, so we could go to suspend. */ if (old_active && !channel->active) gb_pm_runtime_put_autosuspend(bundle); out_pm_put: gb_pm_runtime_put_autosuspend(bundle); out_unlock: mutex_unlock(&channel->lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kris Huang12562.50%266.67%
Rui Miguel Silva7537.50%133.33%
Total200100.00%3100.00%


static int __gb_lights_brightness_set(struct gb_channel *channel) { int ret; if (channel->releasing) return 0; if (is_channel_flash(channel)) ret = __gb_lights_flash_brightness_set(channel); else ret = __gb_lights_led_brightness_set(channel); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva48100.00%1100.00%
Total48100.00%1100.00%


static int gb_brightness_set(struct led_classdev *cdev, enum led_brightness value) { struct gb_channel *channel = get_channel_from_cdev(cdev); channel->led->brightness = value; return __gb_lights_brightness_set(channel); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva39100.00%1100.00%
Total39100.00%1100.00%


static enum led_brightness gb_brightness_get(struct led_classdev *cdev) { struct gb_channel *channel = get_channel_from_cdev(cdev); return channel->led->brightness; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva29100.00%1100.00%
Total29100.00%1100.00%


static int gb_blink_set(struct led_classdev *cdev, unsigned long *delay_on, unsigned long *delay_off) { struct gb_channel *channel = get_channel_from_cdev(cdev); struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_blink_request req; bool old_active; int ret; if (channel->releasing) return -ESHUTDOWN; if (!delay_on || !delay_off) return -EINVAL; mutex_lock(&channel->lock); ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) goto out_unlock; old_active = channel->active; req.light_id = channel->light->id; req.channel_id = channel->id; req.time_on_ms = cpu_to_le16(*delay_on); req.time_off_ms = cpu_to_le16(*delay_off); ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_BLINK, &req, sizeof(req), NULL, 0); if (ret < 0) goto out_pm_put; if (*delay_on) channel->active = true; else channel->active = false; /* we need to keep module alive when turning to active state */ if (!old_active && channel->active) goto out_unlock; /* * on the other hand if going to inactive we still hold a reference and * need to put it, so we could go to suspend. */ if (old_active && !channel->active) gb_pm_runtime_put_autosuspend(bundle); out_pm_put: gb_pm_runtime_put_autosuspend(bundle); out_unlock: mutex_unlock(&channel->lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva12550.81%360.00%
Kris Huang12149.19%240.00%
Total246100.00%5100.00%


static void gb_lights_led_operations_set(struct gb_channel *channel, struct led_classdev *cdev) { cdev->brightness_get = gb_brightness_get; cdev->brightness_set_blocking = gb_brightness_set; if (channel->flags & GB_LIGHT_CHANNEL_BLINK) cdev->blink_set = gb_blink_set; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva42100.00%2100.00%
Total42100.00%2100.00%

#if IS_REACHABLE(CONFIG_V4L2_FLASH_LED_CLASS) /* V4L2 specific helpers */ static const struct v4l2_flash_ops v4l2_flash_ops;
static void __gb_lights_channel_v4l2_config(struct led_flash_setting *channel_s, struct led_flash_setting *v4l2_s) { v4l2_s->min = channel_s->min; v4l2_s->max = channel_s->max; v4l2_s->step = channel_s->step; /* For v4l2 val is the default value */ v4l2_s->val = channel_s->max; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva49100.00%1100.00%
Total49100.00%1100.00%


static int gb_lights_light_v4l2_register(struct gb_light *light) { struct gb_connection *connection = get_conn_from_light(light); struct device *dev = &connection->bundle->dev; struct v4l2_flash_config *sd_cfg; struct led_classdev_flash *fled; struct led_classdev_flash *iled = NULL; struct gb_channel *channel_torch, *channel_ind, *channel_flash; int ret = 0; sd_cfg = kcalloc(1, sizeof(*sd_cfg), GFP_KERNEL); if (!sd_cfg) return -ENOMEM; channel_torch = get_channel_from_mode(light, GB_CHANNEL_MODE_TORCH); if (channel_torch) __gb_lights_channel_v4l2_config(&channel_torch->intensity_uA, &sd_cfg->torch_intensity); channel_ind = get_channel_from_mode(light, GB_CHANNEL_MODE_INDICATOR); if (channel_ind) { __gb_lights_channel_v4l2_config(&channel_ind->intensity_uA, &sd_cfg->indicator_intensity); iled = &channel_ind->fled; } channel_flash = get_channel_from_mode(light, GB_CHANNEL_MODE_FLASH); WARN_ON(!channel_flash); fled = &channel_flash->fled; snprintf(sd_cfg->dev_name, sizeof(sd_cfg->dev_name), "%s", light->name); /* Set the possible values to faults, in our case all faults */ sd_cfg->flash_faults = LED_FAULT_OVER_VOLTAGE | LED_FAULT_TIMEOUT | LED_FAULT_OVER_TEMPERATURE | LED_FAULT_SHORT_CIRCUIT | LED_FAULT_OVER_CURRENT | LED_FAULT_INDICATOR | LED_FAULT_UNDER_VOLTAGE | LED_FAULT_INPUT_VOLTAGE | LED_FAULT_LED_OVER_TEMPERATURE; light->v4l2_flash = v4l2_flash_init(dev, NULL, fled, iled, &v4l2_flash_ops, sd_cfg); if (IS_ERR_OR_NULL(light->v4l2_flash)) { ret = PTR_ERR(light->v4l2_flash); goto out_free; } return ret; out_free: kfree(sd_cfg); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva27099.26%266.67%
Greg Kroah-Hartman20.74%133.33%
Total272100.00%3100.00%


static void gb_lights_light_v4l2_unregister(struct gb_light *light) { v4l2_flash_release(light->v4l2_flash); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva18100.00%1100.00%
Total18100.00%1100.00%

#else
static int gb_lights_light_v4l2_register(struct gb_light *light) { struct gb_connection *connection = get_conn_from_light(light); dev_err(&connection->bundle->dev, "no support for v4l2 subdevices\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva3494.44%150.00%
Greg Kroah-Hartman25.56%150.00%
Total36100.00%2100.00%


static void gb_lights_light_v4l2_unregister(struct gb_light *light) { }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva10100.00%1100.00%
Total10100.00%1100.00%

#endif #if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH) /* Flash specific operations */
static int gb_lights_flash_intensity_set(struct led_classdev_flash *fcdev, u32 brightness) { struct gb_channel *channel = container_of(fcdev, struct gb_channel, fled); int ret; ret = __gb_lights_flash_intensity_set(channel, brightness); if (ret < 0) return ret; fcdev->brightness.val = brightness; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva61100.00%1100.00%
Total61100.00%1100.00%


static int gb_lights_flash_intensity_get(struct led_classdev_flash *fcdev, u32 *brightness) { *brightness = fcdev->brightness.val; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva27100.00%1100.00%
Total27100.00%1100.00%


static int gb_lights_flash_strobe_set(struct led_classdev_flash *fcdev, bool state) { struct gb_channel *channel = container_of(fcdev, struct gb_channel, fled); struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_flash_strobe_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.state = state ? 1 : 0; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_STROBE, &req, sizeof(req), NULL, 0); if (!ret) channel->strobe_state = state; gb_pm_runtime_put_autosuspend(bundle); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva11778.52%150.00%
Kris Huang3221.48%150.00%
Total149100.00%2100.00%


static int gb_lights_flash_strobe_get(struct led_classdev_flash *fcdev, bool *state) { struct gb_channel *channel = container_of(fcdev, struct gb_channel, fled); *state = channel->strobe_state; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva40100.00%1100.00%
Total40100.00%1100.00%


static int gb_lights_flash_timeout_set(struct led_classdev_flash *fcdev, u32 timeout) { struct gb_channel *channel = container_of(fcdev, struct gb_channel, fled); struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_flash_timeout_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.timeout_us = cpu_to_le32(timeout); ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_TIMEOUT, &req, sizeof(req), NULL, 0); if (!ret) fcdev->timeout.val = timeout; gb_pm_runtime_put_autosuspend(bundle); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva11878.67%150.00%
Kris Huang3221.33%150.00%
Total150100.00%2100.00%


static int gb_lights_flash_fault_get(struct led_classdev_flash *fcdev, u32 *fault) { struct gb_channel *channel = container_of(fcdev, struct gb_channel, fled); struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_get_flash_fault_request req; struct gb_lights_get_flash_fault_response resp; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_GET_FLASH_FAULT, &req, sizeof(req), &resp, sizeof(resp)); if (!ret) *fault = le32_to_cpu(resp.fault); gb_pm_runtime_put_autosuspend(bundle); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva12078.95%150.00%
Kris Huang3221.05%150.00%
Total152100.00%2100.00%

static const struct led_flash_ops gb_lights_flash_ops = { .flash_brightness_set = gb_lights_flash_intensity_set, .flash_brightness_get = gb_lights_flash_intensity_get, .strobe_set = gb_lights_flash_strobe_set, .strobe_get = gb_lights_flash_strobe_get, .timeout_set = gb_lights_flash_timeout_set, .fault_get = gb_lights_flash_fault_get, };
static int __gb_lights_channel_torch_attach(struct gb_channel *channel, struct gb_channel *channel_torch) { char *name; /* we can only attach torch to a flash channel */ if (!(channel->mode & GB_CHANNEL_MODE_FLASH)) return 0; /* Move torch brightness to the destination */ channel->led->max_brightness = channel_torch->led->max_brightness; /* append mode name to flash name */ name = kasprintf(GFP_KERNEL, "%s_%s", channel->led->name, channel_torch->mode_name); if (!name) return -ENOMEM; kfree(channel->led->name); channel->led->name = name; channel_torch->led = channel->led; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva105100.00%1100.00%
Total105100.00%1100.00%


static int __gb_lights_flash_led_register(struct gb_channel *channel) { struct gb_connection *connection = get_conn_from_channel(channel); struct led_classdev_flash *fled = &channel->fled; struct led_flash_setting *fset; struct gb_channel *channel_torch; int ret; fled->ops = &gb_lights_flash_ops; fled->led_cdev.flags |= LED_DEV_CAP_FLASH; fset = &fled->brightness; fset->min = channel->intensity_uA.min; fset->max = channel->intensity_uA.max; fset->step = channel->intensity_uA.step; fset->val = channel->intensity_uA.max; /* Only the flash mode have the timeout constraints settings */ if (channel->mode & GB_CHANNEL_MODE_FLASH) { fset = &fled->timeout; fset->min = channel->timeout_us.min; fset->max = channel->timeout_us.max; fset->step = channel->timeout_us.step; fset->val = channel->timeout_us.max; } /* * If light have torch mode channel, this channel will be the led * classdev of the registered above flash classdev */ channel_torch = get_channel_from_mode(channel->light, GB_CHANNEL_MODE_TORCH); if (channel_torch) { ret = __gb_lights_channel_torch_attach(channel, channel_torch); if (ret < 0) goto fail; } ret = led_classdev_flash_register(&connection->bundle->dev, fled); if (ret < 0) goto fail; channel->is_registered = true; return 0; fail: channel->led = NULL; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva243100.00%2100.00%
Total243100.00%2100.00%


static void __gb_lights_flash_led_unregister(struct gb_channel *channel) { if (!channel->is_registered) return; led_classdev_flash_unregister(&channel->fled); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva27100.00%1100.00%
Total27100.00%1100.00%


static int gb_lights_channel_flash_config(struct gb_channel *channel) { struct gb_connection *connection = get_conn_from_channel(channel); struct gb_lights_get_channel_flash_config_request req; struct gb_lights_get_channel_flash_config_response conf; struct led_flash_setting *fset; int ret; req.light_id = channel->light->id; req.channel_id = channel->id; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_GET_CHANNEL_FLASH_CONFIG, &req, sizeof(req), &conf, sizeof(conf)); if (ret < 0) return ret; /* * Intensity constraints for flash related modes: flash, torch, * indicator. They will be needed for v4l2 registration. */ fset = &channel->intensity_uA; fset->min = le32_to_cpu(conf.intensity_min_uA); fset->max = le32_to_cpu(conf.intensity_max_uA); fset->step = le32_to_cpu(conf.intensity_step_uA); /* * On flash type, max brightness is set as the number of intensity steps * available. */ channel->led->max_brightness = (fset->max - fset->min) / fset->step; /* Only the flash mode have the timeout constraints settings */ if (channel->mode & GB_CHANNEL_MODE_FLASH) { fset = &channel->timeout_us; fset->min = le32_to_cpu(conf.timeout_min_us); fset->max = le32_to_cpu(conf.timeout_max_us); fset->step = le32_to_cpu(conf.timeout_step_us); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva205100.00%1100.00%
Total205100.00%1100.00%

#else
static int gb_lights_channel_flash_config(struct gb_channel *channel) { struct gb_connection *connection = get_conn_from_channel(channel); dev_err(&connection->bundle->dev, "no support for flash devices\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva3494.44%150.00%
Greg Kroah-Hartman25.56%150.00%
Total36100.00%2100.00%


static int __gb_lights_flash_led_register(struct gb_channel *channel) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva14100.00%1100.00%
Total14100.00%1100.00%


static void __gb_lights_flash_led_unregister(struct gb_channel *channel) { }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva10100.00%1100.00%
Total10100.00%1100.00%

#endif
static int __gb_lights_led_register(struct gb_channel *channel) { struct gb_connection *connection = get_conn_from_channel(channel); struct led_classdev *cdev = get_channel_cdev(channel); int ret; ret = led_classdev_register(&connection->bundle->dev, cdev); if (ret < 0) channel->led = NULL; else channel->is_registered = true; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva70100.00%1100.00%
Total70100.00%1100.00%


static int gb_lights_channel_register(struct gb_channel *channel) { /* Normal LED channel, just register in led classdev and we are done */ if (!is_channel_flash(channel)) return __gb_lights_led_register(channel); /* * Flash Type need more work, register flash classdev, indicator as * flash classdev, torch will be led classdev of the flash classdev. */ if (!(channel->mode & GB_CHANNEL_MODE_TORCH)) return __gb_lights_flash_led_register(channel); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva47100.00%1100.00%
Total47100.00%1100.00%


static void __gb_lights_led_unregister(struct gb_channel *channel) { struct led_classdev *cdev = get_channel_cdev(channel); if (!channel->is_registered) return; led_classdev_unregister(cdev); channel->led = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva40100.00%1100.00%
Total40100.00%1100.00%


static void gb_lights_channel_unregister(struct gb_channel *channel) { /* The same as register, handle channels differently */ if (!is_channel_flash(channel)) { __gb_lights_led_unregister(channel); return; } if (channel->mode & GB_CHANNEL_MODE_TORCH) __gb_lights_led_unregister(channel); else __gb_lights_flash_led_unregister(channel); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva47100.00%1100.00%
Total47100.00%1100.00%


static int gb_lights_channel_config(struct gb_light *light, struct gb_channel *channel) { struct gb_lights_get_channel_config_response conf; struct gb_lights_get_channel_config_request req; struct gb_connection *connection = get_conn_from_light(light); struct led_classdev *cdev = get_channel_cdev(channel); char *name; int ret; req.light_id = light->id; req.channel_id = channel->id; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_GET_CHANNEL_CONFIG, &req, sizeof(req), &conf, sizeof(conf)); if (ret < 0) return ret; channel->light = light; channel->mode = le32_to_cpu(conf.mode); channel->flags = le32_to_cpu(conf.flags); channel->color = le32_to_cpu(conf.color); channel->color_name = kstrndup(conf.color_name, NAMES_MAX, GFP_KERNEL); if (!channel->color_name) return -ENOMEM; channel->mode_name = kstrndup(conf.mode_name, NAMES_MAX, GFP_KERNEL); if (!channel->mode_name) return -ENOMEM; channel->led = cdev; name = kasprintf(GFP_KERNEL, "%s:%s:%s", light->name, channel->color_name, channel->mode_name); if (!name) return -ENOMEM; cdev->name = name; cdev->max_brightness = conf.max_brightness; ret = channel_attr_groups_set(channel, cdev); if (ret < 0) return ret; gb_lights_led_operations_set(channel, cdev); /* * If it is not a flash related channel (flash, torch or indicator) we * are done here. If not, continue and fetch flash related * configurations. */ if (!is_channel_flash(channel)) return ret; light->has_flash = true; ret = gb_lights_channel_flash_config(channel); if (ret < 0) return ret; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva304100.00%1100.00%
Total304100.00%1100.00%


static int gb_lights_light_config(struct gb_lights *glights, u8 id) { struct gb_light *light = &glights->lights[id]; struct gb_lights_get_light_config_request req; struct gb_lights_get_light_config_response conf; int ret; int i; light->glights = glights; light->id = id; req.id = id; ret = gb_operation_sync(glights->connection, GB_LIGHTS_TYPE_GET_LIGHT_CONFIG, &req, sizeof(req), &conf, sizeof(conf)); if (ret < 0) return ret; if (!conf.channel_count) return -EINVAL; if (!strlen(conf.name)) return -EINVAL; light->channels_count = conf.channel_count; light->name = kstrndup(conf.name, NAMES_MAX, GFP_KERNEL); light->channels = kzalloc(light->channels_count * sizeof(struct gb_channel), GFP_KERNEL); if (!light->channels) return -ENOMEM; /* First we collect all the configurations for all channels */ for (i = 0; i < light->channels_count; i++) { light->channels[i].id = i; ret = gb_lights_channel_config(light, &light->channels[i]); if (ret < 0) return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva22598.25%150.00%
Viresh Kumar41.75%150.00%
Total229100.00%2100.00%


static int gb_lights_light_register(struct gb_light *light) { int ret; int i; /* * Then, if everything went ok in getting configurations, we register * the classdev, flash classdev and v4l2 subsystem, if a flash device is * found. */ for (i = 0; i < light->channels_count; i++) { ret = gb_lights_channel_register(&light->channels[i]); if (ret < 0) return ret; mutex_init(&light->channels[i].lock); } light->ready = true; if (light->has_flash) { ret = gb_lights_light_v4l2_register(light); if (ret < 0) { light->has_flash = false; return ret; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva8273.87%360.00%
Viresh Kumar1614.41%120.00%
Kris Huang1311.71%120.00%
Total111100.00%5100.00%


static void gb_lights_channel_free(struct gb_channel *channel) { kfree(channel->attrs); kfree(channel->attr_group); kfree(channel->attr_groups); kfree(channel->color_name); kfree(channel->mode_name); mutex_destroy(&channel->lock); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva4685.19%150.00%
Kris Huang814.81%150.00%
Total54100.00%2100.00%


static void gb_lights_channel_release(struct gb_channel *channel) { channel->releasing = true; gb_lights_channel_unregister(channel); gb_lights_channel_free(channel); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva27100.00%1100.00%
Total27100.00%1100.00%


static void gb_lights_light_release(struct gb_light *light) { int i; int count; light->ready = false; count = light->channels_count; if (light->has_flash) gb_lights_light_v4l2_unregister(light); for (i = 0; i < count; i++) { gb_lights_channel_release(&light->channels[i]); light->channels_count--; } kfree(light->channels); kfree(light->name); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva85100.00%2100.00%
Total85100.00%2100.00%


static void gb_lights_release(struct gb_lights *glights) { int i; if (!glights) return; mutex_lock(&glights->lights_lock); if (!glights->lights) goto free_glights; for (i = 0; i < glights->lights_count; i++) gb_lights_light_release(&glights->lights[i]); kfree(glights->lights); free_glights: mutex_unlock(&glights->lights_lock); mutex_destroy(&glights->lights_lock); kfree(glights); }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva94100.00%1100.00%
Total94100.00%1100.00%


static int gb_lights_get_count(struct gb_lights *glights) { struct gb_lights_get_lights_response resp; int ret; ret = gb_operation_sync(glights->connection, GB_LIGHTS_TYPE_GET_LIGHTS, NULL, 0, &resp, sizeof(resp)); if (ret < 0) return ret; if (!resp.lights_count) return -EINVAL; glights->lights_count = resp.lights_count; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva72100.00%1100.00%
Total72100.00%1100.00%


static int gb_lights_create_all(struct gb_lights *glights) { struct gb_connection *connection = glights->connection; int ret; int i; mutex_lock(&glights->lights_lock); ret = gb_lights_get_count(glights); if (ret < 0) goto out; glights->lights = kzalloc(glights->lights_count * sizeof(struct gb_light), GFP_KERNEL); if (!glights->lights) { ret = -ENOMEM; goto out; } for (i = 0; i < glights->lights_count; i++) { ret = gb_lights_light_config(glights, i); if (ret < 0) { dev_err(&connection->bundle->dev, "Fail to configure lights device\n"); goto out; } } out: mutex_unlock(&glights->lights_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva14597.97%133.33%
Greg Kroah-Hartman21.35%133.33%
Viresh Kumar10.68%133.33%
Total148100.00%3100.00%


static int gb_lights_register_all(struct gb_lights *glights) { struct gb_connection *connection = glights->connection; int ret = 0; int i; mutex_lock(&glights->lights_lock); for (i = 0; i < glights->lights_count; i++) { ret = gb_lights_light_register(&glights->lights[i]); if (ret < 0) { dev_err(&connection->bundle->dev, "Fail to enable lights device\n"); break; } } mutex_unlock(&glights->lights_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar98100.00%1100.00%
Total98100.00%1100.00%


static int gb_lights_request_handler(struct gb_operation *op) { struct gb_connection *connection = op->connection; struct device *dev = &connection->bundle->dev; struct gb_lights *glights = gb_connection_get_data(connection); struct gb_light *light; struct gb_message *request; struct gb_lights_event_request *payload; int ret = 0; u8 light_id; u8 event; if (op->type != GB_LIGHTS_TYPE_EVENT) { dev_err(dev, "Unsupported unsolicited event: %u\n", op->type); return -EINVAL; } request = op->request; if (request->payload_size < sizeof(*payload)) { dev_err(dev, "Wrong event size received (%zu < %zu)\n", request->payload_size, sizeof(*payload)); return -EINVAL; } payload = request->payload; light_id = payload->light_id; if (light_id >= glights->lights_count || !glights->lights[light_id].ready) { dev_err(dev, "Event received for unconfigured light id: %d\n", light_id); return -EINVAL; } event = payload->event; if (event & GB_LIGHTS_LIGHT_CONFIG) { light = &glights->lights[light_id]; mutex_lock(&glights->lights_lock); gb_lights_light_release(light); ret = gb_lights_light_config(glights, light_id); if (!ret) ret = gb_lights_light_register(light); if (ret < 0) gb_lights_light_release(light); mutex_unlock(&glights->lights_lock); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva21081.08%233.33%
Viresh Kumar3413.13%233.33%
Greg Kroah-Hartman155.79%233.33%
Total259100.00%6100.00%


static int gb_lights_probe(struct gb_bundle *bundle, const struct greybus_bundle_id *id) { struct greybus_descriptor_cport *cport_desc; struct gb_connection *connection; struct gb_lights *glights; int ret; if (bundle->num_cports != 1) return -ENODEV; cport_desc = &bundle->cport_desc[0]; if (cport_desc->protocol_id != GREYBUS_PROTOCOL_LIGHTS) return -ENODEV; glights = kzalloc(sizeof(*glights), GFP_KERNEL); if (!glights) return -ENOMEM; mutex_init(&glights->lights_lock); connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), gb_lights_request_handler); if (IS_ERR(connection)) { ret = PTR_ERR(connection); goto out; } glights->connection = connection; gb_connection_set_data(connection, glights); greybus_set_drvdata(bundle, glights); /* We aren't ready to receive an incoming request yet */ ret = gb_connection_enable_tx(connection); if (ret) goto error_connection_destroy; /* * Setup all the lights devices over this connection, if anything goes * wrong tear down all lights */ ret = gb_lights_create_all(glights); if (ret < 0) goto error_connection_disable; /* We are ready to receive an incoming request now, enable RX as well */ ret = gb_connection_enable(connection); if (ret) goto error_connection_disable; /* Enable & register lights */ ret = gb_lights_register_all(glights); if (ret < 0) goto error_connection_disable; gb_pm_runtime_put_autosuspend(bundle); return 0; error_connection_disable: gb_connection_disable(connection); error_connection_destroy: gb_connection_destroy(connection); out: gb_lights_release(glights); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar16666.40%350.00%
Rui Miguel Silva7530.00%116.67%
Kris Huang52.00%116.67%
Greg Kroah-Hartman41.60%116.67%
Total250100.00%6100.00%


static void gb_lights_disconnect(struct gb_bundle *bundle) { struct gb_lights *glights = greybus_get_drvdata(bundle); if (gb_pm_runtime_get_sync(bundle)) gb_pm_runtime_get_noresume(bundle); gb_connection_disable(glights->connection); gb_connection_destroy(glights->connection); gb_lights_release(glights); }

Contributors

PersonTokensPropCommitsCommitProp
Viresh Kumar2038.46%133.33%
Rui Miguel Silva2038.46%133.33%
Kris Huang1223.08%133.33%
Total52100.00%3100.00%

static const struct greybus_bundle_id gb_lights_id_table[] = { { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_LIGHTS) }, { } }; MODULE_DEVICE_TABLE(greybus, gb_lights_id_table); static struct greybus_driver gb_lights_driver = { .name = "lights", .probe = gb_lights_probe, .disconnect = gb_lights_disconnect, .id_table = gb_lights_id_table, }; module_greybus_driver(gb_lights_driver); MODULE_LICENSE("GPL v2");

Overall Contributors

PersonTokensPropCommitsCommitProp
Rui Miguel Silva484184.24%952.94%
Kris Huang5018.72%211.76%
Viresh Kumar3746.51%317.65%
Greg Kroah-Hartman270.47%211.76%
David Lin40.07%15.88%
Total5747100.00%17100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.