From patchwork Tue Mar 2 23:42:23 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?TsOpbWV0aCBNw6FydG9u?= X-Patchwork-Id: 2872 Return-path: Envelope-to: mchehab@infradead.org Delivery-date: Tue, 02 Mar 2010 23:42:39 +0000 Received: from bombadil.infradead.org [18.85.46.34] by pedra with IMAP (fetchmail-6.3.6) for (single-drop); Tue, 02 Mar 2010 20:51:33 -0300 (BRT) Received: from vger.kernel.org ([209.132.180.67]) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1Nmbja-0003Ey-C9; Tue, 02 Mar 2010 23:42:39 +0000 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757919Ab0CBXmb (ORCPT + 1 other); Tue, 2 Mar 2010 18:42:31 -0500 Received: from relay01.digicable.hu ([92.249.128.189]:37113 "EHLO relay01.digicable.hu" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757915Ab0CBXm3 (ORCPT ); Tue, 2 Mar 2010 18:42:29 -0500 Received: from [94.21.49.222] by relay01.digicable.hu with esmtpa id 1NmbjO-0000nX-5T ; Wed, 03 Mar 2010 00:42:26 +0100 Message-ID: <4B8DA25F.10602@freemail.hu> Date: Wed, 03 Mar 2010 00:42:23 +0100 From: =?UTF-8?B?TsOpbWV0aCBNw6FydG9u?= User-Agent: Mozilla/5.0 (X11; U; Linux i686; hu-HU; rv:1.8.1.21) Gecko/20090402 SeaMonkey/1.1.16 MIME-Version: 1.0 To: Jean-Francois Moine CC: Hans de Goede , Laurent Pinchart , Richard Purdie , V4L Mailing List Subject: [RFC, PATCH 1/3] gspca: add LEDs subsystem connection References: <4B8A2158.6020701@freemail.hu> <20100228202801.6986cb19@tele> <4B8AC618.80200@freemail.hu> <20100301101806.7c7986be@tele> In-Reply-To: <20100301101806.7c7986be@tele> X-Original: 94.21.49.222 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org From: Márton Németh On some webcams one or more LEDs can be found. One type of these LEDs are feedback LEDs: they usually shows the state of streaming mode. The LED can be programmed to constantly switched off state (e.g. for power saving reasons, preview mode) or on state (e.g. the application shows motion detection or "on-air"). The second type of LEDs are used to create enough light for the sensor for example visible or in infra-red light. Both type of these LEDs can be handled using the LEDs subsystem. This patch add support to connect a gspca based driver to the LEDs subsystem. Signed-off-by: Márton Németh --- -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff -r d8fafa7d88dc linux/drivers/media/video/gspca/gspca.h --- a/linux/drivers/media/video/gspca/gspca.h Thu Feb 18 19:02:51 2010 +0100 +++ b/linux/drivers/media/video/gspca/gspca.h Wed Mar 03 00:10:19 2010 +0100 @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "compat.h" /* compilation option */ @@ -53,14 +55,41 @@ int nrates; }; +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +/** + * struct gspca_led - data structure for one LED on a camera + * @led_cdev: the class device for the LED + * @name: place for the LED name which will appear under /sys/class/leds/ + * @led_trigger: the trigger structure for the same LED + * @trigger_name: place for the trigger name which will appear in the file + * /sys/class/leds/{led name}/trigger + * @parent: pointer to the parent gspca_dev + */ +struct gspca_led { + struct led_classdev led_cdev; + char name[32]; +#ifdef CONFIG_LEDS_TRIGGERS + struct led_trigger led_trigger; + char trigger_name[32]; +#endif + struct gspca_dev *parent; +}; +#endif + /* device information - set at probe time */ struct cam { const struct v4l2_pix_format *cam_mode; /* size nmodes */ const struct framerates *mode_framerates; /* must have size nmode, * just like cam_mode */ +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) + struct gspca_led *leds; +#endif u32 bulk_size; /* buffer size when image transfer by bulk */ u32 input_flags; /* value for ENUM_INPUT status flags */ u8 nmodes; /* size of cam_mode */ +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) + u8 nleds; /* number of LEDs */ +#endif u8 no_urb_create; /* don't create transfer URBs */ u8 bulk_nurbs; /* number of URBs in bulk mode * - cannot be > MAX_NURBS diff -r d8fafa7d88dc linux/drivers/media/video/gspca/gspca.c --- a/linux/drivers/media/video/gspca/gspca.c Thu Feb 18 19:02:51 2010 +0100 +++ b/linux/drivers/media/video/gspca/gspca.c Wed Mar 03 00:10:19 2010 +0100 @@ -4,6 +4,7 @@ * Copyright (C) 2008-2009 Jean-Francois Moine (http://moinejf.free.fr) * * Camera button input handling by Márton Németh + * LED subsystem connection by Márton Németh * Copyright (C) 2009-2010 Márton Németh * * This program is free software; you can redistribute it and/or modify it @@ -2256,6 +2257,76 @@ .release = gspca_release, }; +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +/** + * gspca_create_name() - Create a name using format string and a number + * @name: format string on input, e.g. "video%d::feedback". The format string + * may contain one and only one %d format specifier. The created name + * will be put on the same location and the original format string will + * be overwritten. + * @length: the length of the buffer in bytes pointed by the name parameter + * @num: the number to use when creating the name + * + * Returns zero on success. + */ +static int gspca_create_name(char *name, unsigned int length, int num) +{ + char buffer[32]; + unsigned int l; + + /* TODO: check format string: it shall contain one and only one %d */ + + l = min(length, sizeof(buffer)); + snprintf(buffer, l, name, num); + strlcpy(name, buffer, l); + + return 0; +} + +static void gspca_leds_register(struct gspca_dev *gspca_dev) { + int i; + int ret; + + for (i = 0; i < gspca_dev->cam.nleds; i++) { +#ifdef CONFIG_LEDS_TRIGGERS + gspca_create_name(gspca_dev->cam.leds[i].trigger_name, + sizeof(gspca_dev->cam.leds[i].trigger_name), + gspca_dev->vdev.num); + gspca_dev->cam.leds[i].led_trigger.name = gspca_dev->cam.leds[i].trigger_name; + gspca_dev->cam.leds[i].led_cdev.default_trigger = gspca_dev->cam.leds[i].trigger_name; +#endif + gspca_create_name(gspca_dev->cam.leds[i].name, + sizeof(gspca_dev->cam.leds[i].name), + gspca_dev->vdev.num); + + gspca_dev->cam.leds[i].led_cdev.name = gspca_dev->cam.leds[i].name; + gspca_dev->cam.leds[i].led_cdev.blink_set = NULL; + gspca_dev->cam.leds[i].led_cdev.flags = LED_CORE_SUSPENDRESUME; + ret = led_classdev_register(&gspca_dev->dev->dev, + &gspca_dev->cam.leds[i].led_cdev); + if (!ret) { +#ifdef CONFIG_LEDS_TRIGGERS + led_trigger_register(&gspca_dev->cam.leds[i].led_trigger); +#endif + } + } +} + +static void gspca_leds_unregister(struct gspca_dev *gspca_dev) +{ + int i; + for (i = 0; i < gspca_dev->cam.nleds; i++) { +#ifdef CONFIG_LEDS_TRIGGERS + led_trigger_unregister(&gspca_dev->cam.leds[i].led_trigger); +#endif + led_classdev_unregister(&gspca_dev->cam.leds[i].led_cdev); + } +} +#else +#define gspca_leds_register(gspca_dev) +#define gspca_leds_disconnect(gspca_dev) +#endif + /* * probe and create a new gspca device * @@ -2342,6 +2413,8 @@ if (ret == 0) ret = gspca_input_create_urb(gspca_dev); + gspca_leds_register(gspca_dev); + return 0; out: kfree(gspca_dev->usb_buf); @@ -2386,6 +2459,8 @@ gspca_dev->dev = NULL; mutex_unlock(&gspca_dev->usb_lock); + gspca_leds_unregister(gspca_dev); + usb_set_intfdata(intf, NULL); /* release the device */