Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2
  3    bt8xx GPIO abuser
  4
  5    Copyright (C) 2008 Michael Buesch <m@bues.ch>
  6
  7    Please do _only_ contact the people listed _above_ with issues related to this driver.
  8    All the other people listed below are not related to this driver. Their names
  9    are only here, because this driver is derived from the bt848 driver.
 10
 11
 12    Derived from the bt848 driver:
 13
 14    Copyright (C) 1996,97,98 Ralph  Metzler
 15			   & Marcus Metzler
 16    (c) 1999-2002 Gerd Knorr
 17
 18    some v4l2 code lines are taken from Justin's bttv2 driver which is
 19    (c) 2000 Justin Schoeman
 20
 21    V4L1 removal from:
 22    (c) 2005-2006 Nickolay V. Shmyrev
 23
 24    Fixes to be fully V4L2 compliant by
 25    (c) 2006 Mauro Carvalho Chehab
 26
 27    Cropping and overscan support
 28    Copyright (C) 2005, 2006 Michael H. Schimek
 29    Sponsored by OPQ Systems AB
 30
 31    This program is free software; you can redistribute it and/or modify
 32    it under the terms of the GNU General Public License as published by
 33    the Free Software Foundation; either version 2 of the License, or
 34    (at your option) any later version.
 35
 36    This program is distributed in the hope that it will be useful,
 37    but WITHOUT ANY WARRANTY; without even the implied warranty of
 38    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 39    GNU General Public License for more details.
 40
 41    You should have received a copy of the GNU General Public License
 42    along with this program; if not, write to the Free Software
 43    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 44*/
 45
 46#include <linux/module.h>
 47#include <linux/pci.h>
 48#include <linux/spinlock.h>
 49#include <linux/gpio.h>
 50#include <linux/slab.h>
 51
 52/* Steal the hardware definitions from the bttv driver. */
 53#include "../media/video/bt8xx/bt848.h"
 54
 55
 56#define BT8XXGPIO_NR_GPIOS		24 /* We have 24 GPIO pins */
 57
 58
 59struct bt8xxgpio {
 60	spinlock_t lock;
 61
 62	void __iomem *mmio;
 63	struct pci_dev *pdev;
 64	struct gpio_chip gpio;
 65
 66#ifdef CONFIG_PM
 67	u32 saved_outen;
 68	u32 saved_data;
 69#endif
 70};
 71
 72#define bgwrite(dat, adr)	writel((dat), bg->mmio+(adr))
 73#define bgread(adr)		readl(bg->mmio+(adr))
 74
 75
 76static int modparam_gpiobase = -1/* dynamic */;
 77module_param_named(gpiobase, modparam_gpiobase, int, 0444);
 78MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
 79
 80
 81static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 82{
 83	struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
 84	unsigned long flags;
 85	u32 outen, data;
 86
 87	spin_lock_irqsave(&bg->lock, flags);
 88
 89	data = bgread(BT848_GPIO_DATA);
 90	data &= ~(1 << nr);
 91	bgwrite(data, BT848_GPIO_DATA);
 92
 93	outen = bgread(BT848_GPIO_OUT_EN);
 94	outen &= ~(1 << nr);
 95	bgwrite(outen, BT848_GPIO_OUT_EN);
 96
 97	spin_unlock_irqrestore(&bg->lock, flags);
 98
 99	return 0;
100}
101
102static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
103{
104	struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
105	unsigned long flags;
106	u32 val;
107
108	spin_lock_irqsave(&bg->lock, flags);
109	val = bgread(BT848_GPIO_DATA);
110	spin_unlock_irqrestore(&bg->lock, flags);
111
112	return !!(val & (1 << nr));
113}
114
115static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio,
116					unsigned nr, int val)
117{
118	struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
119	unsigned long flags;
120	u32 outen, data;
121
122	spin_lock_irqsave(&bg->lock, flags);
123
124	outen = bgread(BT848_GPIO_OUT_EN);
125	outen |= (1 << nr);
126	bgwrite(outen, BT848_GPIO_OUT_EN);
127
128	data = bgread(BT848_GPIO_DATA);
129	if (val)
130		data |= (1 << nr);
131	else
132		data &= ~(1 << nr);
133	bgwrite(data, BT848_GPIO_DATA);
134
135	spin_unlock_irqrestore(&bg->lock, flags);
136
137	return 0;
138}
139
140static void bt8xxgpio_gpio_set(struct gpio_chip *gpio,
141			    unsigned nr, int val)
142{
143	struct bt8xxgpio *bg = container_of(gpio, struct bt8xxgpio, gpio);
144	unsigned long flags;
145	u32 data;
146
147	spin_lock_irqsave(&bg->lock, flags);
148
149	data = bgread(BT848_GPIO_DATA);
150	if (val)
151		data |= (1 << nr);
152	else
153		data &= ~(1 << nr);
154	bgwrite(data, BT848_GPIO_DATA);
155
156	spin_unlock_irqrestore(&bg->lock, flags);
157}
158
159static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg)
160{
161	struct gpio_chip *c = &bg->gpio;
162
163	c->label = dev_name(&bg->pdev->dev);
164	c->owner = THIS_MODULE;
165	c->direction_input = bt8xxgpio_gpio_direction_input;
166	c->get = bt8xxgpio_gpio_get;
167	c->direction_output = bt8xxgpio_gpio_direction_output;
168	c->set = bt8xxgpio_gpio_set;
169	c->dbg_show = NULL;
170	c->base = modparam_gpiobase;
171	c->ngpio = BT8XXGPIO_NR_GPIOS;
172	c->can_sleep = 0;
173}
174
175static int bt8xxgpio_probe(struct pci_dev *dev,
176			const struct pci_device_id *pci_id)
177{
178	struct bt8xxgpio *bg;
179	int err;
180
181	bg = kzalloc(sizeof(*bg), GFP_KERNEL);
182	if (!bg)
183		return -ENOMEM;
184
185	bg->pdev = dev;
186	spin_lock_init(&bg->lock);
187
188	err = pci_enable_device(dev);
189	if (err) {
190		printk(KERN_ERR "bt8xxgpio: Can't enable device.\n");
191		goto err_freebg;
192	}
193	if (!request_mem_region(pci_resource_start(dev, 0),
194				pci_resource_len(dev, 0),
195				"bt8xxgpio")) {
196		printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n",
197		       (unsigned long long)pci_resource_start(dev, 0));
198		err = -EBUSY;
199		goto err_disable;
200	}
201	pci_set_master(dev);
202	pci_set_drvdata(dev, bg);
203
204	bg->mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
205	if (!bg->mmio) {
206		printk(KERN_ERR "bt8xxgpio: ioremap() failed\n");
207		err = -EIO;
208		goto err_release_mem;
209	}
210
211	/* Disable interrupts */
212	bgwrite(0, BT848_INT_MASK);
213
214	/* gpio init */
215	bgwrite(0, BT848_GPIO_DMA_CTL);
216	bgwrite(0, BT848_GPIO_REG_INP);
217	bgwrite(0, BT848_GPIO_OUT_EN);
218
219	bt8xxgpio_gpio_setup(bg);
220	err = gpiochip_add(&bg->gpio);
221	if (err) {
222		printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
223		goto err_release_mem;
224	}
225
226	printk(KERN_INFO "bt8xxgpio: Abusing BT8xx card for GPIOs %d to %d\n",
227	       bg->gpio.base, bg->gpio.base + BT8XXGPIO_NR_GPIOS - 1);
228
229	return 0;
230
231err_release_mem:
232	release_mem_region(pci_resource_start(dev, 0),
233			   pci_resource_len(dev, 0));
234	pci_set_drvdata(dev, NULL);
235err_disable:
236	pci_disable_device(dev);
237err_freebg:
238	kfree(bg);
239
240	return err;
241}
242
243static void bt8xxgpio_remove(struct pci_dev *pdev)
244{
245	struct bt8xxgpio *bg = pci_get_drvdata(pdev);
246
247	gpiochip_remove(&bg->gpio);
248
249	bgwrite(0, BT848_INT_MASK);
250	bgwrite(~0x0, BT848_INT_STAT);
251	bgwrite(0x0, BT848_GPIO_OUT_EN);
252
253	iounmap(bg->mmio);
254	release_mem_region(pci_resource_start(pdev, 0),
255			   pci_resource_len(pdev, 0));
256	pci_disable_device(pdev);
257
258	pci_set_drvdata(pdev, NULL);
259	kfree(bg);
260}
261
262#ifdef CONFIG_PM
263static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state)
264{
265	struct bt8xxgpio *bg = pci_get_drvdata(pdev);
266	unsigned long flags;
267
268	spin_lock_irqsave(&bg->lock, flags);
269
270	bg->saved_outen = bgread(BT848_GPIO_OUT_EN);
271	bg->saved_data = bgread(BT848_GPIO_DATA);
272
273	bgwrite(0, BT848_INT_MASK);
274	bgwrite(~0x0, BT848_INT_STAT);
275	bgwrite(0x0, BT848_GPIO_OUT_EN);
276
277	spin_unlock_irqrestore(&bg->lock, flags);
278
279	pci_save_state(pdev);
280	pci_disable_device(pdev);
281	pci_set_power_state(pdev, pci_choose_state(pdev, state));
282
283	return 0;
284}
285
286static int bt8xxgpio_resume(struct pci_dev *pdev)
287{
288	struct bt8xxgpio *bg = pci_get_drvdata(pdev);
289	unsigned long flags;
290	int err;
291
292	pci_set_power_state(pdev, 0);
293	err = pci_enable_device(pdev);
294	if (err)
295		return err;
296	pci_restore_state(pdev);
297
298	spin_lock_irqsave(&bg->lock, flags);
299
300	bgwrite(0, BT848_INT_MASK);
301	bgwrite(0, BT848_GPIO_DMA_CTL);
302	bgwrite(0, BT848_GPIO_REG_INP);
303	bgwrite(bg->saved_outen, BT848_GPIO_OUT_EN);
304	bgwrite(bg->saved_data & bg->saved_outen,
305		BT848_GPIO_DATA);
306
307	spin_unlock_irqrestore(&bg->lock, flags);
308
309	return 0;
310}
311#else
312#define bt8xxgpio_suspend NULL
313#define bt8xxgpio_resume NULL
314#endif /* CONFIG_PM */
315
316static struct pci_device_id bt8xxgpio_pci_tbl[] = {
317	{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) },
318	{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) },
319	{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) },
320	{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879) },
321	{ 0, },
322};
323MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl);
324
325static struct pci_driver bt8xxgpio_pci_driver = {
326	.name		= "bt8xxgpio",
327	.id_table	= bt8xxgpio_pci_tbl,
328	.probe		= bt8xxgpio_probe,
329	.remove		= bt8xxgpio_remove,
330	.suspend	= bt8xxgpio_suspend,
331	.resume		= bt8xxgpio_resume,
332};
333
334static int __init bt8xxgpio_init(void)
335{
336	return pci_register_driver(&bt8xxgpio_pci_driver);
337}
338module_init(bt8xxgpio_init)
339
340static void __exit bt8xxgpio_exit(void)
341{
342	pci_unregister_driver(&bt8xxgpio_pci_driver);
343}
344module_exit(bt8xxgpio_exit)
345
346MODULE_LICENSE("GPL");
347MODULE_AUTHOR("Michael Buesch");
348MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");
v4.10.11
  1/*
  2
  3    bt8xx GPIO abuser
  4
  5    Copyright (C) 2008 Michael Buesch <m@bues.ch>
  6
  7    Please do _only_ contact the people listed _above_ with issues related to this driver.
  8    All the other people listed below are not related to this driver. Their names
  9    are only here, because this driver is derived from the bt848 driver.
 10
 11
 12    Derived from the bt848 driver:
 13
 14    Copyright (C) 1996,97,98 Ralph  Metzler
 15			   & Marcus Metzler
 16    (c) 1999-2002 Gerd Knorr
 17
 18    some v4l2 code lines are taken from Justin's bttv2 driver which is
 19    (c) 2000 Justin Schoeman
 20
 21    V4L1 removal from:
 22    (c) 2005-2006 Nickolay V. Shmyrev
 23
 24    Fixes to be fully V4L2 compliant by
 25    (c) 2006 Mauro Carvalho Chehab
 26
 27    Cropping and overscan support
 28    Copyright (C) 2005, 2006 Michael H. Schimek
 29    Sponsored by OPQ Systems AB
 30
 31    This program is free software; you can redistribute it and/or modify
 32    it under the terms of the GNU General Public License as published by
 33    the Free Software Foundation; either version 2 of the License, or
 34    (at your option) any later version.
 35
 36    This program is distributed in the hope that it will be useful,
 37    but WITHOUT ANY WARRANTY; without even the implied warranty of
 38    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 39    GNU General Public License for more details.
 40
 41    You should have received a copy of the GNU General Public License
 42    along with this program; if not, write to the Free Software
 43    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 44*/
 45
 46#include <linux/module.h>
 47#include <linux/pci.h>
 48#include <linux/spinlock.h>
 49#include <linux/gpio.h>
 50#include <linux/slab.h>
 51
 52/* Steal the hardware definitions from the bttv driver. */
 53#include "../media/pci/bt8xx/bt848.h"
 54
 55
 56#define BT8XXGPIO_NR_GPIOS		24 /* We have 24 GPIO pins */
 57
 58
 59struct bt8xxgpio {
 60	spinlock_t lock;
 61
 62	void __iomem *mmio;
 63	struct pci_dev *pdev;
 64	struct gpio_chip gpio;
 65
 66#ifdef CONFIG_PM
 67	u32 saved_outen;
 68	u32 saved_data;
 69#endif
 70};
 71
 72#define bgwrite(dat, adr)	writel((dat), bg->mmio+(adr))
 73#define bgread(adr)		readl(bg->mmio+(adr))
 74
 75
 76static int modparam_gpiobase = -1/* dynamic */;
 77module_param_named(gpiobase, modparam_gpiobase, int, 0444);
 78MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");
 79
 80
 81static int bt8xxgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 82{
 83	struct bt8xxgpio *bg = gpiochip_get_data(gpio);
 84	unsigned long flags;
 85	u32 outen, data;
 86
 87	spin_lock_irqsave(&bg->lock, flags);
 88
 89	data = bgread(BT848_GPIO_DATA);
 90	data &= ~(1 << nr);
 91	bgwrite(data, BT848_GPIO_DATA);
 92
 93	outen = bgread(BT848_GPIO_OUT_EN);
 94	outen &= ~(1 << nr);
 95	bgwrite(outen, BT848_GPIO_OUT_EN);
 96
 97	spin_unlock_irqrestore(&bg->lock, flags);
 98
 99	return 0;
100}
101
102static int bt8xxgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
103{
104	struct bt8xxgpio *bg = gpiochip_get_data(gpio);
105	unsigned long flags;
106	u32 val;
107
108	spin_lock_irqsave(&bg->lock, flags);
109	val = bgread(BT848_GPIO_DATA);
110	spin_unlock_irqrestore(&bg->lock, flags);
111
112	return !!(val & (1 << nr));
113}
114
115static int bt8xxgpio_gpio_direction_output(struct gpio_chip *gpio,
116					unsigned nr, int val)
117{
118	struct bt8xxgpio *bg = gpiochip_get_data(gpio);
119	unsigned long flags;
120	u32 outen, data;
121
122	spin_lock_irqsave(&bg->lock, flags);
123
124	outen = bgread(BT848_GPIO_OUT_EN);
125	outen |= (1 << nr);
126	bgwrite(outen, BT848_GPIO_OUT_EN);
127
128	data = bgread(BT848_GPIO_DATA);
129	if (val)
130		data |= (1 << nr);
131	else
132		data &= ~(1 << nr);
133	bgwrite(data, BT848_GPIO_DATA);
134
135	spin_unlock_irqrestore(&bg->lock, flags);
136
137	return 0;
138}
139
140static void bt8xxgpio_gpio_set(struct gpio_chip *gpio,
141			    unsigned nr, int val)
142{
143	struct bt8xxgpio *bg = gpiochip_get_data(gpio);
144	unsigned long flags;
145	u32 data;
146
147	spin_lock_irqsave(&bg->lock, flags);
148
149	data = bgread(BT848_GPIO_DATA);
150	if (val)
151		data |= (1 << nr);
152	else
153		data &= ~(1 << nr);
154	bgwrite(data, BT848_GPIO_DATA);
155
156	spin_unlock_irqrestore(&bg->lock, flags);
157}
158
159static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg)
160{
161	struct gpio_chip *c = &bg->gpio;
162
163	c->label = dev_name(&bg->pdev->dev);
164	c->owner = THIS_MODULE;
165	c->direction_input = bt8xxgpio_gpio_direction_input;
166	c->get = bt8xxgpio_gpio_get;
167	c->direction_output = bt8xxgpio_gpio_direction_output;
168	c->set = bt8xxgpio_gpio_set;
169	c->dbg_show = NULL;
170	c->base = modparam_gpiobase;
171	c->ngpio = BT8XXGPIO_NR_GPIOS;
172	c->can_sleep = false;
173}
174
175static int bt8xxgpio_probe(struct pci_dev *dev,
176			const struct pci_device_id *pci_id)
177{
178	struct bt8xxgpio *bg;
179	int err;
180
181	bg = devm_kzalloc(&dev->dev, sizeof(struct bt8xxgpio), GFP_KERNEL);
182	if (!bg)
183		return -ENOMEM;
184
185	bg->pdev = dev;
186	spin_lock_init(&bg->lock);
187
188	err = pci_enable_device(dev);
189	if (err) {
190		printk(KERN_ERR "bt8xxgpio: Can't enable device.\n");
191		return err;
192	}
193	if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0),
194				pci_resource_len(dev, 0),
195				"bt8xxgpio")) {
196		printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n",
197		       (unsigned long long)pci_resource_start(dev, 0));
198		err = -EBUSY;
199		goto err_disable;
200	}
201	pci_set_master(dev);
202	pci_set_drvdata(dev, bg);
203
204	bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000);
205	if (!bg->mmio) {
206		printk(KERN_ERR "bt8xxgpio: ioremap() failed\n");
207		err = -EIO;
208		goto err_disable;
209	}
210
211	/* Disable interrupts */
212	bgwrite(0, BT848_INT_MASK);
213
214	/* gpio init */
215	bgwrite(0, BT848_GPIO_DMA_CTL);
216	bgwrite(0, BT848_GPIO_REG_INP);
217	bgwrite(0, BT848_GPIO_OUT_EN);
218
219	bt8xxgpio_gpio_setup(bg);
220	err = gpiochip_add_data(&bg->gpio, bg);
221	if (err) {
222		printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
223		goto err_disable;
224	}
225
 
 
 
226	return 0;
227
 
 
 
 
228err_disable:
229	pci_disable_device(dev);
 
 
230
231	return err;
232}
233
234static void bt8xxgpio_remove(struct pci_dev *pdev)
235{
236	struct bt8xxgpio *bg = pci_get_drvdata(pdev);
237
238	gpiochip_remove(&bg->gpio);
239
240	bgwrite(0, BT848_INT_MASK);
241	bgwrite(~0x0, BT848_INT_STAT);
242	bgwrite(0x0, BT848_GPIO_OUT_EN);
243
 
 
 
244	pci_disable_device(pdev);
 
 
 
245}
246
247#ifdef CONFIG_PM
248static int bt8xxgpio_suspend(struct pci_dev *pdev, pm_message_t state)
249{
250	struct bt8xxgpio *bg = pci_get_drvdata(pdev);
251	unsigned long flags;
252
253	spin_lock_irqsave(&bg->lock, flags);
254
255	bg->saved_outen = bgread(BT848_GPIO_OUT_EN);
256	bg->saved_data = bgread(BT848_GPIO_DATA);
257
258	bgwrite(0, BT848_INT_MASK);
259	bgwrite(~0x0, BT848_INT_STAT);
260	bgwrite(0x0, BT848_GPIO_OUT_EN);
261
262	spin_unlock_irqrestore(&bg->lock, flags);
263
264	pci_save_state(pdev);
265	pci_disable_device(pdev);
266	pci_set_power_state(pdev, pci_choose_state(pdev, state));
267
268	return 0;
269}
270
271static int bt8xxgpio_resume(struct pci_dev *pdev)
272{
273	struct bt8xxgpio *bg = pci_get_drvdata(pdev);
274	unsigned long flags;
275	int err;
276
277	pci_set_power_state(pdev, PCI_D0);
278	err = pci_enable_device(pdev);
279	if (err)
280		return err;
281	pci_restore_state(pdev);
282
283	spin_lock_irqsave(&bg->lock, flags);
284
285	bgwrite(0, BT848_INT_MASK);
286	bgwrite(0, BT848_GPIO_DMA_CTL);
287	bgwrite(0, BT848_GPIO_REG_INP);
288	bgwrite(bg->saved_outen, BT848_GPIO_OUT_EN);
289	bgwrite(bg->saved_data & bg->saved_outen,
290		BT848_GPIO_DATA);
291
292	spin_unlock_irqrestore(&bg->lock, flags);
293
294	return 0;
295}
296#else
297#define bt8xxgpio_suspend NULL
298#define bt8xxgpio_resume NULL
299#endif /* CONFIG_PM */
300
301static const struct pci_device_id bt8xxgpio_pci_tbl[] = {
302	{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) },
303	{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) },
304	{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) },
305	{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879) },
306	{ 0, },
307};
308MODULE_DEVICE_TABLE(pci, bt8xxgpio_pci_tbl);
309
310static struct pci_driver bt8xxgpio_pci_driver = {
311	.name		= "bt8xxgpio",
312	.id_table	= bt8xxgpio_pci_tbl,
313	.probe		= bt8xxgpio_probe,
314	.remove		= bt8xxgpio_remove,
315	.suspend	= bt8xxgpio_suspend,
316	.resume		= bt8xxgpio_resume,
317};
318
319module_pci_driver(bt8xxgpio_pci_driver);
 
 
 
 
 
 
 
 
 
 
320
321MODULE_LICENSE("GPL");
322MODULE_AUTHOR("Michael Buesch");
323MODULE_DESCRIPTION("Abuse a BT8xx framegrabber card as generic GPIO card");