All of lore.kernel.org
 help / color / mirror / Atom feed
From: Domenico Andreoli <cavokz@gmail.com>
To: David Brownell <david-b@pacbell.net>
Cc: video4linux-list@redhat.com, Michael Buesch <mb@bu3sch.de>,
	Mauro Carvalho Chehab <mchehab@infradead.org>
Subject: Re: [PATCH v3] Add bt8xxgpio driver
Date: Mon, 14 Jul 2008 09:27:33 +0200	[thread overview]
Message-ID: <20080714072733.GA29908@ska.dandreoli.com> (raw)
In-Reply-To: <200807132259.54360.david-b@pacbell.net>

On Sun, Jul 13, 2008 at 10:59:54PM -0700, David Brownell wrote:
> On Sunday 13 July 2008, Domenico Andreoli wrote:
> > Say that a given card has 4 relays attached to its GPIOs. Only the
> > card's driver may know about these relays and only the driver should
> > be able to set those GPIO directions. Moreover, driver should prevent
> > direction change for them, which are intended for output only.
> > 
> > While I figure out how to prevent user direction tampering, how about
> > making gpiolib know which are the initial directions?
> 
> I don't quite follow.  If you export the GPIOs to userspace using
> the (pending, to-appear-in-2.6.27) sysfs interface, you can use

I already tried it, very nifty. I used it to show my driver is working,
I could hear the relays and see the tester.. yuk!

Anyway I was too free to play with GPIOs, I would like to be able to
set limits at driver level. i.e. relay GPIOs should be output only and
no one, being another driver or user-space, should be able to change
their direction.

While I am able to enforce direction policy, I am not able to setup the
initial direction. Indeed it is set by gpiolib basing on the presence
of chip.direction_input.

cheers,
Domenico


This patch adds the gpiolib bttv sub-driver.

Every bttv card may define a set of available gpio ports which are
registered to gpiolib and then made available through kernel's generic
gpio interface.

--

State of the patch: working. RFC.

Index: v4l-dvb.git/drivers/media/video/bt8xx/Kconfig
===================================================================
--- v4l-dvb.git.orig/drivers/media/video/bt8xx/Kconfig	2008-07-14 06:33:54.000000000 +0200
+++ v4l-dvb.git/drivers/media/video/bt8xx/Kconfig	2008-07-14 06:33:58.000000000 +0200
@@ -21,6 +21,12 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called bttv.
 
+config VIDEO_BT848_GPIO
+	tristate "GPIO support for bt848 cards"
+	depends on VIDEO_BT848 && GPIOLIB
+	---help---
+	  This enables GPIOLIB bindings on BT848 boards.
+
 config VIDEO_BT848_DVB
 	bool "DVB/ATSC Support for bt878 based TV cards"
 	depends on VIDEO_BT848 && DVB_CORE
Index: v4l-dvb.git/drivers/media/video/bt8xx/Makefile
===================================================================
--- v4l-dvb.git.orig/drivers/media/video/bt8xx/Makefile	2008-07-14 06:33:54.000000000 +0200
+++ v4l-dvb.git/drivers/media/video/bt8xx/Makefile	2008-07-14 06:33:58.000000000 +0200
@@ -7,6 +7,7 @@
 		       bttv-input.o bttv-audio-hook.o
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o
+obj-$(CONFIG_VIDEO_BT848_GPIO) += bttv-gpiolib.o
 
 EXTRA_CFLAGS += -Idrivers/media/video
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
Index: v4l-dvb.git/drivers/media/video/bt8xx/bttv-cards.c
===================================================================
--- v4l-dvb.git.orig/drivers/media/video/bt8xx/bttv-cards.c	2008-07-14 06:33:54.000000000 +0200
+++ v4l-dvb.git/drivers/media/video/bt8xx/bttv-cards.c	2008-07-14 06:33:58.000000000 +0200
@@ -2162,6 +2162,7 @@
 		.gpiomask       = 0xdf,
 		.muxsel         = { 2 },
 		.pll            = PLL_28,
+		.has_gpiolib    = 1,
 	},
 	[BTTV_BOARD_XGUARD] = {
 		.name           = "Grand X-Guard / Trust 814PCI",
Index: v4l-dvb.git/drivers/media/video/bt8xx/bttv-driver.c
===================================================================
--- v4l-dvb.git.orig/drivers/media/video/bt8xx/bttv-driver.c	2008-07-14 06:33:55.000000000 +0200
+++ v4l-dvb.git/drivers/media/video/bt8xx/bttv-driver.c	2008-07-14 06:33:58.000000000 +0200
@@ -4455,6 +4455,12 @@
 		request_modules(btv);
 	}
 
+#ifdef CONFIG_VIDEO_BT848_GPIO_MODULE
+	/* add gpiolib subdevice */
+	if (bttv_tvcards[btv->c.type].has_gpiolib)
+		bttv_sub_add_device(&btv->c, "gpiolib");
+#endif
+
 	bttv_input_init(btv);
 
 	/* everything is fine */
Index: v4l-dvb.git/drivers/media/video/bt8xx/bttv-gpiolib.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ v4l-dvb.git/drivers/media/video/bt8xx/bttv-gpiolib.c	2008-07-14 08:32:01.000000000 +0200
@@ -0,0 +1,235 @@
+/*
+ * Bt8xx based GPIOLIB driver
+ *
+ * Copyright (C) 2008 Domenico Andreoli <cavok@dandreoli.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include <asm/gpio.h>
+
+#include "bttvp.h"
+
+struct bttv_gpiolib_device {
+	struct bttv_sub_device *sub;
+	struct gpio_chip chip;
+
+	u32 in_mask;
+	u32 out_mask;
+	u32 out;
+};
+
+static u32 nr_to_mask(struct bttv_gpiolib_device *dev, unsigned nr)
+{
+	u32 io_mask = dev->in_mask | dev->out_mask;
+	int shift = 0;
+
+	while(io_mask && nr) {
+		nr -= io_mask & 1;
+		io_mask >>= 1;
+		shift++;
+	}
+
+	return 1 << shift;
+}
+
+static void bttv_gpiolib_inout(struct bttv_core *core, u32 mask, u32 outbits, u32 outvals)
+{
+	struct bttv *btv = container_of(core, struct bttv, c);
+	unsigned long flags;
+	u32 data;
+
+	spin_lock_irqsave(&btv->gpio_lock, flags);
+
+	/* set direction */
+	data = btread(BT848_GPIO_OUT_EN);
+	data &= ~mask;
+	data |= mask & outbits;
+	btwrite(data, BT848_GPIO_OUT_EN);
+
+	mask &= outbits;
+	if(mask) {
+		/* set output values */
+		data = btread(BT848_GPIO_DATA);
+		data &= ~mask;
+		data |= mask & outvals;
+		btwrite(data, BT848_GPIO_DATA);
+	}
+
+	spin_unlock_irqrestore(&btv->gpio_lock, flags);
+}
+
+static int bttv_gpiolib_direction_input(struct gpio_chip *gpio, unsigned nr)
+{
+	struct bttv_gpiolib_device *dev = container_of(gpio, struct bttv_gpiolib_device, chip);
+	u32 mask = nr_to_mask(dev, nr);
+
+	if(!(mask & dev->in_mask))
+		return -EPERM;
+
+	bttv_gpiolib_inout(dev->sub->core, mask, 0, 0);
+	return 0;
+}
+
+static int bttv_gpiolib_direction_output(struct gpio_chip *gpio, unsigned nr, int val)
+{
+	struct bttv_gpiolib_device *dev = container_of(gpio, struct bttv_gpiolib_device, chip);
+	u32 mask = nr_to_mask(dev, nr);
+
+	if(!(mask & dev->out_mask))
+		return -EPERM;
+
+	bttv_gpiolib_inout(dev->sub->core, mask, mask, val ? mask : 0);
+	return 0;
+}
+
+static int bttv_gpiolib_get(struct gpio_chip *gpio, unsigned nr)
+{
+	u32 data;
+	unsigned long flags;
+	struct bttv_gpiolib_device *dev = container_of(gpio, struct bttv_gpiolib_device, chip);
+	struct bttv *btv = container_of(dev->sub->core, struct bttv, c);
+
+	spin_lock_irqsave(&btv->gpio_lock, flags);
+	data = btread(BT848_GPIO_DATA);
+	spin_unlock_irqrestore(&btv->gpio_lock, flags);
+
+	return !!(data & nr_to_mask(dev, nr));
+}
+
+static void bttv_gpiolib_set(struct gpio_chip *gpio, unsigned nr, int val)
+{
+	u32 data;
+	unsigned long flags;
+	struct bttv_gpiolib_device *dev = container_of(gpio, struct bttv_gpiolib_device, chip);
+	struct bttv *btv = container_of(dev->sub->core, struct bttv, c);
+	u32 mask = nr_to_mask(dev, nr);
+
+	spin_lock_irqsave(&btv->gpio_lock, flags);
+	data = btread(BT848_GPIO_DATA);
+	data &= ~mask;
+	data |= val ? mask : 0;
+	btwrite(data, BT848_GPIO_DATA);
+	spin_unlock_irqrestore(&btv->gpio_lock, flags);
+}
+
+static int bttv_gpiolib_setup(unsigned int type, struct bttv_gpiolib_device *dev)
+{
+	switch(type) {
+		case BTTV_BOARD_IVC200:
+			dev->in_mask  = 0x0f;
+			dev->out_mask = 0xff;
+			break;
+
+		default:
+			printk(KERN_ERR "card type %d: missing gpiolib configuration\n", type);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __devinit bttv_gpiolib_probe(struct bttv_sub_device *sub)
+{
+	struct bttv_gpiolib_device *dev;
+	u32 io_mask;
+	int ret;
+
+	dev = kzalloc(sizeof(struct bttv_gpiolib_device), GFP_KERNEL);
+	if(!dev)
+		return -ENOMEM;
+
+	ret = bttv_gpiolib_setup(sub->core->type, dev);
+	if(ret) {
+		kfree(dev);
+		return ret;
+	}
+
+	io_mask = dev->in_mask | dev->out_mask;
+	if(!io_mask) {
+		printk(KERN_ERR "card type %d: missing GPIOs configuration\n", sub->core->type);
+		kfree(dev);
+		return -EINVAL;
+	}
+
+	/* set direction and output values */
+	bttv_gpiolib_inout(sub->core, io_mask, dev->out_mask, dev->out);
+
+	while(io_mask) {
+		dev->chip.ngpio++;
+		io_mask >>= 1;
+	}
+
+	dev->sub = sub;
+	dev->chip.label = sub->dev.bus_id;
+	dev->chip.owner = THIS_MODULE;
+
+	dev->chip.base = -1;
+	dev->chip.direction_input = bttv_gpiolib_direction_input;
+	dev->chip.direction_output = bttv_gpiolib_direction_output;
+	dev->chip.get = bttv_gpiolib_get;
+	dev->chip.set = bttv_gpiolib_set;
+
+	ret = gpiochip_add(&dev->chip);
+	if(ret) {
+		printk(KERN_ERR "error adding gpio chip %s: %d\n", dev->chip.label, ret);
+		kfree(dev);
+		return ret;
+	}
+
+	dev_set_drvdata(&sub->dev, dev);
+	return 0;
+}
+
+static void __devexit bttv_gpiolib_remove(struct bttv_sub_device *sub)
+{
+	struct bttv_gpiolib_device *dev = dev_get_drvdata(&sub->dev);
+	int ret;
+
+	ret = gpiochip_remove(&dev->chip);
+	if(ret)
+		printk(KERN_ERR "error removing gpio chip %s: %d). leaking memory...\n", dev->chip.label, ret);
+	else
+		kfree(dev);
+}
+
+static struct bttv_sub_driver driver = {
+	.drv = {
+		.name		= "bttv-gpiolib",
+	},
+	.probe		= bttv_gpiolib_probe,
+	.remove		= bttv_gpiolib_remove,
+};
+
+static int __init bttv_gpiolib_init(void)
+{
+	return bttv_sub_register(&driver, "gpiolib");
+}
+
+static void __exit bttv_gpiolib_exit(void)
+{
+	bttv_sub_unregister(&driver);
+}
+
+module_init(bttv_gpiolib_init);
+module_exit(bttv_gpiolib_exit);
+
+MODULE_DESCRIPTION("Bt8xx based GPIOLIB driver");
+MODULE_AUTHOR("Domenico Andreoli <cavok@dandreoli.com>");
+MODULE_LICENSE("GPL");
Index: v4l-dvb.git/drivers/media/video/bt8xx/bttv.h
===================================================================
--- v4l-dvb.git.orig/drivers/media/video/bt8xx/bttv.h	2008-07-14 06:33:54.000000000 +0200
+++ v4l-dvb.git/drivers/media/video/bt8xx/bttv.h	2008-07-14 06:33:58.000000000 +0200
@@ -249,6 +249,8 @@
 	void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
 
 	void (*muxsel_hook)(struct bttv *btv, unsigned int input);
+
+	bool has_gpiolib;
 };
 
 extern struct tvcard bttv_tvcards[];


-----[ Domenico Andreoli, aka cavok
 --[ http://www.dandreoli.com/gpgkey.asc
   ---[ 3A0F 2F80 F79C 678A 8936  4FEE 0677 9033 A20E BC50

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

  parent reply	other threads:[~2008-07-14  7:27 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-10 17:14 [PATCH v3] Add bt8xxgpio driver Michael Buesch
2008-07-10 18:15 ` Jiri Slaby
2008-07-10 18:44   ` Michael Buesch
2008-07-10 20:02   ` David Brownell
2008-07-11 12:53     ` Michael Buesch
2008-07-10 19:02 ` Mauro Carvalho Chehab
2008-07-10 19:12   ` Michael Buesch
2008-07-10 19:33     ` Mauro Carvalho Chehab
2008-07-11 13:00       ` Michael Buesch
2008-07-13  0:42   ` Domenico Andreoli
     [not found]     ` <200807131215.12082.mb@bu3sch.de>
2008-07-13 15:43       ` Domenico Andreoli
     [not found]         ` <200807131808.35599.mb@bu3sch.de>
2008-07-13 16:39           ` Domenico Andreoli
2008-07-15  8:46             ` Trent Piepho
     [not found]         ` <200807131300.35126.david-b@pacbell.net>
2008-07-14  5:25           ` Domenico Andreoli
     [not found]             ` <200807132259.54360.david-b@pacbell.net>
2008-07-14  7:27               ` Domenico Andreoli [this message]
     [not found]                 ` <200807141558.29582.mb@bu3sch.de>
2008-07-14 15:25                   ` Domenico Andreoli
     [not found]                     ` <200807140926.28592.david-b@pacbell.net>
2008-07-14 17:08                       ` Domenico Andreoli
     [not found]                     ` <200807141951.39810.mb@bu3sch.de>
2008-07-14 19:21                       ` Domenico Andreoli

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080714072733.GA29908@ska.dandreoli.com \
    --to=cavokz@gmail.com \
    --cc=david-b@pacbell.net \
    --cc=mb@bu3sch.de \
    --cc=mchehab@infradead.org \
    --cc=video4linux-list@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.