aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/uio')
-rw-r--r--drivers/uio/Kconfig16
-rw-r--r--drivers/uio/Makefile1
-rw-r--r--drivers/uio/uio_aec.c2
-rw-r--r--drivers/uio/uio_cif.c4
-rw-r--r--drivers/uio/uio_dmem_genirq.c359
-rw-r--r--drivers/uio/uio_netx.c2
-rw-r--r--drivers/uio/uio_pci_generic.c2
-rw-r--r--drivers/uio/uio_pdrv.c1
-rw-r--r--drivers/uio/uio_pdrv_genirq.c3
-rw-r--r--drivers/uio/uio_pruss.c6
-rw-r--r--drivers/uio/uio_sercos3.c4
11 files changed, 389 insertions, 11 deletions
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index c48b93813fc1..f56d185790ea 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -44,6 +44,22 @@ config UIO_PDRV_GENIRQ
44 44
45 If you don't know what to do here, say N. 45 If you don't know what to do here, say N.
46 46
47config UIO_DMEM_GENIRQ
48 tristate "Userspace platform driver with generic irq and dynamic memory"
49 help
50 Platform driver for Userspace I/O devices, including generic
51 interrupt handling code. Shared interrupts are not supported.
52
53 Memory regions can be specified with the same platform device
54 resources as the UIO_PDRV drivers, but dynamic regions can also
55 be specified.
56 The number and size of these regions is static,
57 but the memory allocation is not performed until
58 the associated device file is opened. The
59 memory is freed once the uio device is closed.
60
61 If you don't know what to do here, say N.
62
47config UIO_AEC 63config UIO_AEC
48 tristate "AEC video timestamp device" 64 tristate "AEC video timestamp device"
49 depends on PCI 65 depends on PCI
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index d4dd9a5552f8..b354c539507a 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_UIO) += uio.o
2obj-$(CONFIG_UIO_CIF) += uio_cif.o 2obj-$(CONFIG_UIO_CIF) += uio_cif.o
3obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o 3obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o
4obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o 4obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o
5obj-$(CONFIG_UIO_DMEM_GENIRQ) += uio_dmem_genirq.o
5obj-$(CONFIG_UIO_AEC) += uio_aec.o 6obj-$(CONFIG_UIO_AEC) += uio_aec.o
6obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o 7obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o
7obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o 8obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c
index 72b22d44e8b9..1548982db58b 100644
--- a/drivers/uio/uio_aec.c
+++ b/drivers/uio/uio_aec.c
@@ -78,7 +78,7 @@ static void print_board_data(struct pci_dev *pdev, struct uio_info *i)
78 ioread8(i->priv + 0x07)); 78 ioread8(i->priv + 0x07));
79} 79}
80 80
81static int __devinit probe(struct pci_dev *pdev, const struct pci_device_id *id) 81static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
82{ 82{
83 struct uio_info *info; 83 struct uio_info *info;
84 int ret; 84 int ret;
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c
index a84a451159ed..7dd6fc60539d 100644
--- a/drivers/uio/uio_cif.c
+++ b/drivers/uio/uio_cif.c
@@ -40,7 +40,7 @@ static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info)
40 return IRQ_HANDLED; 40 return IRQ_HANDLED;
41} 41}
42 42
43static int __devinit hilscher_pci_probe(struct pci_dev *dev, 43static int hilscher_pci_probe(struct pci_dev *dev,
44 const struct pci_device_id *id) 44 const struct pci_device_id *id)
45{ 45{
46 struct uio_info *info; 46 struct uio_info *info;
@@ -112,7 +112,7 @@ static void hilscher_pci_remove(struct pci_dev *dev)
112 kfree (info); 112 kfree (info);
113} 113}
114 114
115static struct pci_device_id hilscher_pci_ids[] __devinitdata = { 115static struct pci_device_id hilscher_pci_ids[] = {
116 { 116 {
117 .vendor = PCI_VENDOR_ID_PLX, 117 .vendor = PCI_VENDOR_ID_PLX,
118 .device = PCI_DEVICE_ID_PLX_9030, 118 .device = PCI_DEVICE_ID_PLX_9030,
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
new file mode 100644
index 000000000000..252434c9ea9d
--- /dev/null
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -0,0 +1,359 @@
1/*
2 * drivers/uio/uio_dmem_genirq.c
3 *
4 * Userspace I/O platform driver with generic IRQ handling code.
5 *
6 * Copyright (C) 2012 Damian Hobson-Garcia
7 *
8 * Based on uio_pdrv_genirq.c by Magnus Damm
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 */
14
15#include <linux/platform_device.h>
16#include <linux/uio_driver.h>
17#include <linux/spinlock.h>
18#include <linux/bitops.h>
19#include <linux/module.h>
20#include <linux/interrupt.h>
21#include <linux/platform_data/uio_dmem_genirq.h>
22#include <linux/stringify.h>
23#include <linux/pm_runtime.h>
24#include <linux/dma-mapping.h>
25#include <linux/slab.h>
26
27#include <linux/of.h>
28#include <linux/of_platform.h>
29#include <linux/of_address.h>
30
31#define DRIVER_NAME "uio_dmem_genirq"
32#define DMEM_MAP_ERROR (~0)
33
34struct uio_dmem_genirq_platdata {
35 struct uio_info *uioinfo;
36 spinlock_t lock;
37 unsigned long flags;
38 struct platform_device *pdev;
39 unsigned int dmem_region_start;
40 unsigned int num_dmem_regions;
41 void *dmem_region_vaddr[MAX_UIO_MAPS];
42 struct mutex alloc_lock;
43 unsigned int refcnt;
44};
45
46static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode)
47{
48 struct uio_dmem_genirq_platdata *priv = info->priv;
49 struct uio_mem *uiomem;
50 int ret = 0;
51 int dmem_region = priv->dmem_region_start;
52
53 uiomem = &priv->uioinfo->mem[priv->dmem_region_start];
54
55 mutex_lock(&priv->alloc_lock);
56 while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) {
57 void *addr;
58 if (!uiomem->size)
59 break;
60
61 addr = dma_alloc_coherent(&priv->pdev->dev, uiomem->size,
62 (dma_addr_t *)&uiomem->addr, GFP_KERNEL);
63 if (!addr) {
64 uiomem->addr = DMEM_MAP_ERROR;
65 }
66 priv->dmem_region_vaddr[dmem_region++] = addr;
67 ++uiomem;
68 }
69 priv->refcnt++;
70
71 mutex_unlock(&priv->alloc_lock);
72 /* Wait until the Runtime PM code has woken up the device */
73 pm_runtime_get_sync(&priv->pdev->dev);
74 return ret;
75}
76
77static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode)
78{
79 struct uio_dmem_genirq_platdata *priv = info->priv;
80 struct uio_mem *uiomem;
81 int dmem_region = priv->dmem_region_start;
82
83 /* Tell the Runtime PM code that the device has become idle */
84 pm_runtime_put_sync(&priv->pdev->dev);
85
86 uiomem = &priv->uioinfo->mem[priv->dmem_region_start];
87
88 mutex_lock(&priv->alloc_lock);
89
90 priv->refcnt--;
91 while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) {
92 if (!uiomem->size)
93 break;
94 if (priv->dmem_region_vaddr[dmem_region]) {
95 dma_free_coherent(&priv->pdev->dev, uiomem->size,
96 priv->dmem_region_vaddr[dmem_region],
97 uiomem->addr);
98 }
99 uiomem->addr = DMEM_MAP_ERROR;
100 ++dmem_region;
101 ++uiomem;
102 }
103
104 mutex_unlock(&priv->alloc_lock);
105 return 0;
106}
107
108static irqreturn_t uio_dmem_genirq_handler(int irq, struct uio_info *dev_info)
109{
110 struct uio_dmem_genirq_platdata *priv = dev_info->priv;
111
112 /* Just disable the interrupt in the interrupt controller, and
113 * remember the state so we can allow user space to enable it later.
114 */
115
116 if (!test_and_set_bit(0, &priv->flags))
117 disable_irq_nosync(irq);
118
119 return IRQ_HANDLED;
120}
121
122static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
123{
124 struct uio_dmem_genirq_platdata *priv = dev_info->priv;
125 unsigned long flags;
126
127 /* Allow user space to enable and disable the interrupt
128 * in the interrupt controller, but keep track of the
129 * state to prevent per-irq depth damage.
130 *
131 * Serialize this operation to support multiple tasks.
132 */
133
134 spin_lock_irqsave(&priv->lock, flags);
135 if (irq_on) {
136 if (test_and_clear_bit(0, &priv->flags))
137 enable_irq(dev_info->irq);
138 } else {
139 if (!test_and_set_bit(0, &priv->flags))
140 disable_irq(dev_info->irq);
141 }
142 spin_unlock_irqrestore(&priv->lock, flags);
143
144 return 0;
145}
146
147static int uio_dmem_genirq_probe(struct platform_device *pdev)
148{
149 struct uio_dmem_genirq_pdata *pdata = pdev->dev.platform_data;
150 struct uio_info *uioinfo = &pdata->uioinfo;
151 struct uio_dmem_genirq_platdata *priv;
152 struct uio_mem *uiomem;
153 int ret = -EINVAL;
154 int i;
155
156 if (pdev->dev.of_node) {
157 int irq;
158
159 /* alloc uioinfo for one device */
160 uioinfo = kzalloc(sizeof(*uioinfo), GFP_KERNEL);
161 if (!uioinfo) {
162 ret = -ENOMEM;
163 dev_err(&pdev->dev, "unable to kmalloc\n");
164 goto bad2;
165 }
166 uioinfo->name = pdev->dev.of_node->name;
167 uioinfo->version = "devicetree";
168
169 /* Multiple IRQs are not supported */
170 irq = platform_get_irq(pdev, 0);
171 if (irq == -ENXIO)
172 uioinfo->irq = UIO_IRQ_NONE;
173 else
174 uioinfo->irq = irq;
175 }
176
177 if (!uioinfo || !uioinfo->name || !uioinfo->version) {
178 dev_err(&pdev->dev, "missing platform_data\n");
179 goto bad0;
180 }
181
182 if (uioinfo->handler || uioinfo->irqcontrol ||
183 uioinfo->irq_flags & IRQF_SHARED) {
184 dev_err(&pdev->dev, "interrupt configuration error\n");
185 goto bad0;
186 }
187
188 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
189 if (!priv) {
190 ret = -ENOMEM;
191 dev_err(&pdev->dev, "unable to kmalloc\n");
192 goto bad0;
193 }
194
195 dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
196
197 priv->uioinfo = uioinfo;
198 spin_lock_init(&priv->lock);
199 priv->flags = 0; /* interrupt is enabled to begin with */
200 priv->pdev = pdev;
201 mutex_init(&priv->alloc_lock);
202
203 if (!uioinfo->irq) {
204 ret = platform_get_irq(pdev, 0);
205 if (ret < 0) {
206 dev_err(&pdev->dev, "failed to get IRQ\n");
207 goto bad0;
208 }
209 uioinfo->irq = ret;
210 }
211 uiomem = &uioinfo->mem[0];
212
213 for (i = 0; i < pdev->num_resources; ++i) {
214 struct resource *r = &pdev->resource[i];
215
216 if (r->flags != IORESOURCE_MEM)
217 continue;
218
219 if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
220 dev_warn(&pdev->dev, "device has more than "
221 __stringify(MAX_UIO_MAPS)
222 " I/O memory resources.\n");
223 break;
224 }
225
226 uiomem->memtype = UIO_MEM_PHYS;
227 uiomem->addr = r->start;
228 uiomem->size = resource_size(r);
229 ++uiomem;
230 }
231
232 priv->dmem_region_start = i;
233 priv->num_dmem_regions = pdata->num_dynamic_regions;
234
235 for (i = 0; i < pdata->num_dynamic_regions; ++i) {
236 if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
237 dev_warn(&pdev->dev, "device has more than "
238 __stringify(MAX_UIO_MAPS)
239 " dynamic and fixed memory regions.\n");
240 break;
241 }
242 uiomem->memtype = UIO_MEM_PHYS;
243 uiomem->addr = DMEM_MAP_ERROR;
244 uiomem->size = pdata->dynamic_region_sizes[i];
245 ++uiomem;
246 }
247
248 while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
249 uiomem->size = 0;
250 ++uiomem;
251 }
252
253 /* This driver requires no hardware specific kernel code to handle
254 * interrupts. Instead, the interrupt handler simply disables the
255 * interrupt in the interrupt controller. User space is responsible
256 * for performing hardware specific acknowledge and re-enabling of
257 * the interrupt in the interrupt controller.
258 *
259 * Interrupt sharing is not supported.
260 */
261
262 uioinfo->handler = uio_dmem_genirq_handler;
263 uioinfo->irqcontrol = uio_dmem_genirq_irqcontrol;
264 uioinfo->open = uio_dmem_genirq_open;
265 uioinfo->release = uio_dmem_genirq_release;
266 uioinfo->priv = priv;
267
268 /* Enable Runtime PM for this device:
269 * The device starts in suspended state to allow the hardware to be
270 * turned off by default. The Runtime PM bus code should power on the
271 * hardware and enable clocks at open().
272 */
273 pm_runtime_enable(&pdev->dev);
274
275 ret = uio_register_device(&pdev->dev, priv->uioinfo);
276 if (ret) {
277 dev_err(&pdev->dev, "unable to register uio device\n");
278 goto bad1;
279 }
280
281 platform_set_drvdata(pdev, priv);
282 return 0;
283 bad1:
284 kfree(priv);
285 pm_runtime_disable(&pdev->dev);
286 bad0:
287 /* kfree uioinfo for OF */
288 if (pdev->dev.of_node)
289 kfree(uioinfo);
290 bad2:
291 return ret;
292}
293
294static int uio_dmem_genirq_remove(struct platform_device *pdev)
295{
296 struct uio_dmem_genirq_platdata *priv = platform_get_drvdata(pdev);
297
298 uio_unregister_device(priv->uioinfo);
299 pm_runtime_disable(&pdev->dev);
300
301 priv->uioinfo->handler = NULL;
302 priv->uioinfo->irqcontrol = NULL;
303
304 /* kfree uioinfo for OF */
305 if (pdev->dev.of_node)
306 kfree(priv->uioinfo);
307
308 kfree(priv);
309 return 0;
310}
311
312static int uio_dmem_genirq_runtime_nop(struct device *dev)
313{
314 /* Runtime PM callback shared between ->runtime_suspend()
315 * and ->runtime_resume(). Simply returns success.
316 *
317 * In this driver pm_runtime_get_sync() and pm_runtime_put_sync()
318 * are used at open() and release() time. This allows the
319 * Runtime PM code to turn off power to the device while the
320 * device is unused, ie before open() and after release().
321 *
322 * This Runtime PM callback does not need to save or restore
323 * any registers since user space is responsbile for hardware
324 * register reinitialization after open().
325 */
326 return 0;
327}
328
329static const struct dev_pm_ops uio_dmem_genirq_dev_pm_ops = {
330 .runtime_suspend = uio_dmem_genirq_runtime_nop,
331 .runtime_resume = uio_dmem_genirq_runtime_nop,
332};
333
334#ifdef CONFIG_OF
335static const struct of_device_id uio_of_genirq_match[] = {
336 { /* empty for now */ },
337};
338MODULE_DEVICE_TABLE(of, uio_of_genirq_match);
339#else
340# define uio_of_genirq_match NULL
341#endif
342
343static struct platform_driver uio_dmem_genirq = {
344 .probe = uio_dmem_genirq_probe,
345 .remove = uio_dmem_genirq_remove,
346 .driver = {
347 .name = DRIVER_NAME,
348 .owner = THIS_MODULE,
349 .pm = &uio_dmem_genirq_dev_pm_ops,
350 .of_match_table = uio_of_genirq_match,
351 },
352};
353
354module_platform_driver(uio_dmem_genirq);
355
356MODULE_AUTHOR("Damian Hobson-Garcia");
357MODULE_DESCRIPTION("Userspace I/O platform driver with dynamic memory.");
358MODULE_LICENSE("GPL v2");
359MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c
index a879fd5741f8..6a4ba5e83e37 100644
--- a/drivers/uio/uio_netx.c
+++ b/drivers/uio/uio_netx.c
@@ -48,7 +48,7 @@ static irqreturn_t netx_handler(int irq, struct uio_info *dev_info)
48 return IRQ_HANDLED; 48 return IRQ_HANDLED;
49} 49}
50 50
51static int __devinit netx_pci_probe(struct pci_dev *dev, 51static int netx_pci_probe(struct pci_dev *dev,
52 const struct pci_device_id *id) 52 const struct pci_device_id *id)
53{ 53{
54 struct uio_info *info; 54 struct uio_info *info;
diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c
index 0bd08ef2b394..14aa10c1f6de 100644
--- a/drivers/uio/uio_pci_generic.c
+++ b/drivers/uio/uio_pci_generic.c
@@ -53,7 +53,7 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info)
53 return IRQ_HANDLED; 53 return IRQ_HANDLED;
54} 54}
55 55
56static int __devinit probe(struct pci_dev *pdev, 56static int probe(struct pci_dev *pdev,
57 const struct pci_device_id *id) 57 const struct pci_device_id *id)
58{ 58{
59 struct uio_pci_generic_dev *gdev; 59 struct uio_pci_generic_dev *gdev;
diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c
index 72d3646c7365..39be9e061700 100644
--- a/drivers/uio/uio_pdrv.c
+++ b/drivers/uio/uio_pdrv.c
@@ -60,6 +60,7 @@ static int uio_pdrv_probe(struct platform_device *pdev)
60 uiomem->memtype = UIO_MEM_PHYS; 60 uiomem->memtype = UIO_MEM_PHYS;
61 uiomem->addr = r->start; 61 uiomem->addr = r->start;
62 uiomem->size = resource_size(r); 62 uiomem->size = resource_size(r);
63 uiomem->name = r->name;
63 ++uiomem; 64 ++uiomem;
64 } 65 }
65 66
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 42202cd83158..c122bca669b6 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -102,7 +102,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
102 int ret = -EINVAL; 102 int ret = -EINVAL;
103 int i; 103 int i;
104 104
105 if (!uioinfo) { 105 if (pdev->dev.of_node) {
106 int irq; 106 int irq;
107 107
108 /* alloc uioinfo for one device */ 108 /* alloc uioinfo for one device */
@@ -172,6 +172,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
172 uiomem->memtype = UIO_MEM_PHYS; 172 uiomem->memtype = UIO_MEM_PHYS;
173 uiomem->addr = r->start; 173 uiomem->addr = r->start;
174 uiomem->size = resource_size(r); 174 uiomem->size = resource_size(r);
175 uiomem->name = r->name;
175 ++uiomem; 176 ++uiomem;
176 } 177 }
177 178
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c
index f8738de342be..6e2ab007fe9c 100644
--- a/drivers/uio/uio_pruss.c
+++ b/drivers/uio/uio_pruss.c
@@ -115,7 +115,7 @@ static void pruss_cleanup(struct platform_device *dev,
115 kfree(gdev); 115 kfree(gdev);
116} 116}
117 117
118static int __devinit pruss_probe(struct platform_device *dev) 118static int pruss_probe(struct platform_device *dev)
119{ 119{
120 struct uio_info *p; 120 struct uio_info *p;
121 struct uio_pruss_dev *gdev; 121 struct uio_pruss_dev *gdev;
@@ -219,7 +219,7 @@ out_free:
219 return ret; 219 return ret;
220} 220}
221 221
222static int __devexit pruss_remove(struct platform_device *dev) 222static int pruss_remove(struct platform_device *dev)
223{ 223{
224 struct uio_pruss_dev *gdev = platform_get_drvdata(dev); 224 struct uio_pruss_dev *gdev = platform_get_drvdata(dev);
225 225
@@ -230,7 +230,7 @@ static int __devexit pruss_remove(struct platform_device *dev)
230 230
231static struct platform_driver pruss_driver = { 231static struct platform_driver pruss_driver = {
232 .probe = pruss_probe, 232 .probe = pruss_probe,
233 .remove = __devexit_p(pruss_remove), 233 .remove = pruss_remove,
234 .driver = { 234 .driver = {
235 .name = DRV_NAME, 235 .name = DRV_NAME,
236 .owner = THIS_MODULE, 236 .owner = THIS_MODULE,
diff --git a/drivers/uio/uio_sercos3.c b/drivers/uio/uio_sercos3.c
index a187fa14c5c0..81a10a563120 100644
--- a/drivers/uio/uio_sercos3.c
+++ b/drivers/uio/uio_sercos3.c
@@ -116,7 +116,7 @@ static int sercos3_setup_iomem(struct pci_dev *dev, struct uio_info *info,
116 return 0; 116 return 0;
117} 117}
118 118
119static int __devinit sercos3_pci_probe(struct pci_dev *dev, 119static int sercos3_pci_probe(struct pci_dev *dev,
120 const struct pci_device_id *id) 120 const struct pci_device_id *id)
121{ 121{
122 struct uio_info *info; 122 struct uio_info *info;
@@ -197,7 +197,7 @@ static void sercos3_pci_remove(struct pci_dev *dev)
197 kfree(info); 197 kfree(info);
198} 198}
199 199
200static struct pci_device_id sercos3_pci_ids[] __devinitdata = { 200static struct pci_device_id sercos3_pci_ids[] = {
201 { 201 {
202 .vendor = PCI_VENDOR_ID_PLX, 202 .vendor = PCI_VENDOR_ID_PLX,
203 .device = PCI_DEVICE_ID_PLX_9030, 203 .device = PCI_DEVICE_ID_PLX_9030,