Linux Audio

Check our new training course

Loading...
v3.1
 
  1/*
  2 *  cb710/core.c
  3 *
  4 *  Copyright by Michał Mirosław, 2008-2009
  5 *
  6 * This program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License version 2 as
  8 * published by the Free Software Foundation.
  9 */
 10#include <linux/kernel.h>
 11#include <linux/module.h>
 12#include <linux/pci.h>
 13#include <linux/spinlock.h>
 14#include <linux/idr.h>
 15#include <linux/cb710.h>
 16#include <linux/gfp.h>
 17
 18static DEFINE_IDA(cb710_ida);
 19static DEFINE_SPINLOCK(cb710_ida_lock);
 20
 21void cb710_pci_update_config_reg(struct pci_dev *pdev,
 22	int reg, uint32_t mask, uint32_t xor)
 23{
 24	u32 rval;
 25
 26	pci_read_config_dword(pdev, reg, &rval);
 27	rval = (rval & mask) ^ xor;
 28	pci_write_config_dword(pdev, reg, rval);
 29}
 30EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg);
 31
 32/* Some magic writes based on Windows driver init code */
 33static int __devinit cb710_pci_configure(struct pci_dev *pdev)
 34{
 35	unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
 36	struct pci_dev *pdev0;
 37	u32 val;
 38
 39	cb710_pci_update_config_reg(pdev, 0x48,
 40		~0x000000FF, 0x0000003F);
 41
 42	pci_read_config_dword(pdev, 0x48, &val);
 43	if (val & 0x80000000)
 44		return 0;
 45
 46	pdev0 = pci_get_slot(pdev->bus, devfn);
 47	if (!pdev0)
 48		return -ENODEV;
 49
 50	if (pdev0->vendor == PCI_VENDOR_ID_ENE
 51	    && pdev0->device == PCI_DEVICE_ID_ENE_720) {
 52		cb710_pci_update_config_reg(pdev0, 0x8C,
 53			~0x00F00000, 0x00100000);
 54		cb710_pci_update_config_reg(pdev0, 0xB0,
 55			~0x08000000, 0x08000000);
 56	}
 57
 58	cb710_pci_update_config_reg(pdev0, 0x8C,
 59		~0x00000F00, 0x00000200);
 60	cb710_pci_update_config_reg(pdev0, 0x90,
 61		~0x00060000, 0x00040000);
 62
 63	pci_dev_put(pdev0);
 64
 65	return 0;
 66}
 67
 68static irqreturn_t cb710_irq_handler(int irq, void *data)
 69{
 70	struct cb710_chip *chip = data;
 71	struct cb710_slot *slot = &chip->slot[0];
 72	irqreturn_t handled = IRQ_NONE;
 73	unsigned nr;
 74
 75	spin_lock(&chip->irq_lock); /* incl. smp_rmb() */
 76
 77	for (nr = chip->slots; nr; ++slot, --nr) {
 78		cb710_irq_handler_t handler_func = slot->irq_handler;
 79		if (handler_func && handler_func(slot))
 80			handled = IRQ_HANDLED;
 81	}
 82
 83	spin_unlock(&chip->irq_lock);
 84
 85	return handled;
 86}
 87
 88static void cb710_release_slot(struct device *dev)
 89{
 90#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
 91	struct cb710_slot *slot = cb710_pdev_to_slot(to_platform_device(dev));
 92	struct cb710_chip *chip = cb710_slot_to_chip(slot);
 93
 94	/* slot struct can be freed now */
 95	atomic_dec(&chip->slot_refs_count);
 96#endif
 97}
 98
 99static int __devinit cb710_register_slot(struct cb710_chip *chip,
100	unsigned slot_mask, unsigned io_offset, const char *name)
101{
102	int nr = chip->slots;
103	struct cb710_slot *slot = &chip->slot[nr];
104	int err;
105
106	dev_dbg(cb710_chip_dev(chip),
107		"register: %s.%d; slot %d; mask %d; IO offset: 0x%02X\n",
108		name, chip->platform_id, nr, slot_mask, io_offset);
109
110	/* slot->irq_handler == NULL here; this needs to be
111	 * seen before platform_device_register() */
112	++chip->slots;
113	smp_wmb();
114
115	slot->iobase = chip->iobase + io_offset;
116	slot->pdev.name = name;
117	slot->pdev.id = chip->platform_id;
118	slot->pdev.dev.parent = &chip->pdev->dev;
119	slot->pdev.dev.release = cb710_release_slot;
120
121	err = platform_device_register(&slot->pdev);
122
123#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
124	atomic_inc(&chip->slot_refs_count);
125#endif
126
127	if (err) {
128		/* device_initialize() called from platform_device_register()
129		 * wants this on error path */
130		platform_device_put(&slot->pdev);
131
132		/* slot->irq_handler == NULL here anyway, so no lock needed */
133		--chip->slots;
134		return err;
135	}
136
137	chip->slot_mask |= slot_mask;
138
139	return 0;
140}
141
142static void cb710_unregister_slot(struct cb710_chip *chip,
143	unsigned slot_mask)
144{
145	int nr = chip->slots - 1;
146
147	if (!(chip->slot_mask & slot_mask))
148		return;
149
150	platform_device_unregister(&chip->slot[nr].pdev);
151
152	/* complementary to spin_unlock() in cb710_set_irq_handler() */
153	smp_rmb();
154	BUG_ON(chip->slot[nr].irq_handler != NULL);
155
156	/* slot->irq_handler == NULL here, so no lock needed */
157	--chip->slots;
158	chip->slot_mask &= ~slot_mask;
159}
160
161void cb710_set_irq_handler(struct cb710_slot *slot,
162	cb710_irq_handler_t handler)
163{
164	struct cb710_chip *chip = cb710_slot_to_chip(slot);
165	unsigned long flags;
166
167	spin_lock_irqsave(&chip->irq_lock, flags);
168	slot->irq_handler = handler;
169	spin_unlock_irqrestore(&chip->irq_lock, flags);
170}
171EXPORT_SYMBOL_GPL(cb710_set_irq_handler);
172
173#ifdef CONFIG_PM
174
175static int cb710_suspend(struct pci_dev *pdev, pm_message_t state)
176{
 
177	struct cb710_chip *chip = pci_get_drvdata(pdev);
178
179	free_irq(pdev->irq, chip);
180	pci_save_state(pdev);
181	pci_disable_device(pdev);
182	if (state.event & PM_EVENT_SLEEP)
183		pci_set_power_state(pdev, PCI_D3cold);
184	return 0;
185}
186
187static int cb710_resume(struct pci_dev *pdev)
188{
 
189	struct cb710_chip *chip = pci_get_drvdata(pdev);
190	int err;
191
192	pci_set_power_state(pdev, PCI_D0);
193	pci_restore_state(pdev);
194	err = pcim_enable_device(pdev);
195	if (err)
196		return err;
197
198	return devm_request_irq(&pdev->dev, pdev->irq,
199		cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
200}
201
202#endif /* CONFIG_PM */
203
204static int __devinit cb710_probe(struct pci_dev *pdev,
205	const struct pci_device_id *ent)
206{
207	struct cb710_chip *chip;
208	unsigned long flags;
209	u32 val;
210	int err;
211	int n = 0;
212
213	err = cb710_pci_configure(pdev);
214	if (err)
215		return err;
216
217	/* this is actually magic... */
218	pci_read_config_dword(pdev, 0x48, &val);
219	if (!(val & 0x80000000)) {
220		pci_write_config_dword(pdev, 0x48, val|0x71000000);
221		pci_read_config_dword(pdev, 0x48, &val);
222	}
223
224	dev_dbg(&pdev->dev, "PCI config[0x48] = 0x%08X\n", val);
225	if (!(val & 0x70000000))
226		return -ENODEV;
227	val = (val >> 28) & 7;
228	if (val & CB710_SLOT_MMC)
229		++n;
230	if (val & CB710_SLOT_MS)
231		++n;
232	if (val & CB710_SLOT_SM)
233		++n;
234
235	chip = devm_kzalloc(&pdev->dev,
236		sizeof(*chip) + n * sizeof(*chip->slot), GFP_KERNEL);
237	if (!chip)
238		return -ENOMEM;
239
240	err = pcim_enable_device(pdev);
241	if (err)
242		return err;
243
244	err = pcim_iomap_regions(pdev, 0x0001, KBUILD_MODNAME);
245	if (err)
246		return err;
247
 
248	chip->pdev = pdev;
249	chip->iobase = pcim_iomap_table(pdev)[0];
250
251	pci_set_drvdata(pdev, chip);
252
253	err = devm_request_irq(&pdev->dev, pdev->irq,
254		cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
255	if (err)
256		return err;
257
258	do {
259		if (!ida_pre_get(&cb710_ida, GFP_KERNEL))
260			return -ENOMEM;
261
262		spin_lock_irqsave(&cb710_ida_lock, flags);
263		err = ida_get_new(&cb710_ida, &chip->platform_id);
264		spin_unlock_irqrestore(&cb710_ida_lock, flags);
265
266		if (err && err != -EAGAIN)
267			return err;
268	} while (err);
269
270
271	dev_info(&pdev->dev, "id %d, IO 0x%p, IRQ %d\n",
272		chip->platform_id, chip->iobase, pdev->irq);
273
274	if (val & CB710_SLOT_MMC) {	/* MMC/SD slot */
275		err = cb710_register_slot(chip,
276			CB710_SLOT_MMC, 0x00, "cb710-mmc");
277		if (err)
278			return err;
279	}
280
281	if (val & CB710_SLOT_MS) {	/* MemoryStick slot */
282		err = cb710_register_slot(chip,
283			CB710_SLOT_MS, 0x40, "cb710-ms");
284		if (err)
285			goto unreg_mmc;
286	}
287
288	if (val & CB710_SLOT_SM) {	/* SmartMedia slot */
289		err = cb710_register_slot(chip,
290			CB710_SLOT_SM, 0x60, "cb710-sm");
291		if (err)
292			goto unreg_ms;
293	}
294
295	return 0;
296unreg_ms:
297	cb710_unregister_slot(chip, CB710_SLOT_MS);
298unreg_mmc:
299	cb710_unregister_slot(chip, CB710_SLOT_MMC);
300
301#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
302	BUG_ON(atomic_read(&chip->slot_refs_count) != 0);
303#endif
304	return err;
305}
306
307static void __devexit cb710_remove_one(struct pci_dev *pdev)
308{
309	struct cb710_chip *chip = pci_get_drvdata(pdev);
310	unsigned long flags;
311
312	cb710_unregister_slot(chip, CB710_SLOT_SM);
313	cb710_unregister_slot(chip, CB710_SLOT_MS);
314	cb710_unregister_slot(chip, CB710_SLOT_MMC);
315#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
316	BUG_ON(atomic_read(&chip->slot_refs_count) != 0);
317#endif
318
319	spin_lock_irqsave(&cb710_ida_lock, flags);
320	ida_remove(&cb710_ida, chip->platform_id);
321	spin_unlock_irqrestore(&cb710_ida_lock, flags);
322}
323
324static const struct pci_device_id cb710_pci_tbl[] = {
325	{ PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_CB710_FLASH,
326		PCI_ANY_ID, PCI_ANY_ID, },
327	{ 0, }
328};
329
 
 
330static struct pci_driver cb710_driver = {
331	.name = KBUILD_MODNAME,
332	.id_table = cb710_pci_tbl,
333	.probe = cb710_probe,
334	.remove = __devexit_p(cb710_remove_one),
335#ifdef CONFIG_PM
336	.suspend = cb710_suspend,
337	.resume = cb710_resume,
338#endif
339};
340
341static int __init cb710_init_module(void)
342{
343	return pci_register_driver(&cb710_driver);
344}
345
346static void __exit cb710_cleanup_module(void)
347{
348	pci_unregister_driver(&cb710_driver);
349	ida_destroy(&cb710_ida);
350}
351
352module_init(cb710_init_module);
353module_exit(cb710_cleanup_module);
354
355MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
356MODULE_DESCRIPTION("ENE CB710 memory card reader driver");
357MODULE_LICENSE("GPL");
358MODULE_DEVICE_TABLE(pci, cb710_pci_tbl);
v6.8
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *  cb710/core.c
  4 *
  5 *  Copyright by Michał Mirosław, 2008-2009
 
 
 
 
  6 */
  7#include <linux/kernel.h>
  8#include <linux/module.h>
  9#include <linux/pci.h>
 10#include <linux/spinlock.h>
 11#include <linux/idr.h>
 12#include <linux/cb710.h>
 13#include <linux/gfp.h>
 14
 15static DEFINE_IDA(cb710_ida);
 
 16
 17void cb710_pci_update_config_reg(struct pci_dev *pdev,
 18	int reg, uint32_t mask, uint32_t xor)
 19{
 20	u32 rval;
 21
 22	pci_read_config_dword(pdev, reg, &rval);
 23	rval = (rval & mask) ^ xor;
 24	pci_write_config_dword(pdev, reg, rval);
 25}
 26EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg);
 27
 28/* Some magic writes based on Windows driver init code */
 29static int cb710_pci_configure(struct pci_dev *pdev)
 30{
 31	unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
 32	struct pci_dev *pdev0;
 33	u32 val;
 34
 35	cb710_pci_update_config_reg(pdev, 0x48,
 36		~0x000000FF, 0x0000003F);
 37
 38	pci_read_config_dword(pdev, 0x48, &val);
 39	if (val & 0x80000000)
 40		return 0;
 41
 42	pdev0 = pci_get_slot(pdev->bus, devfn);
 43	if (!pdev0)
 44		return -ENODEV;
 45
 46	if (pdev0->vendor == PCI_VENDOR_ID_ENE
 47	    && pdev0->device == PCI_DEVICE_ID_ENE_720) {
 48		cb710_pci_update_config_reg(pdev0, 0x8C,
 49			~0x00F00000, 0x00100000);
 50		cb710_pci_update_config_reg(pdev0, 0xB0,
 51			~0x08000000, 0x08000000);
 52	}
 53
 54	cb710_pci_update_config_reg(pdev0, 0x8C,
 55		~0x00000F00, 0x00000200);
 56	cb710_pci_update_config_reg(pdev0, 0x90,
 57		~0x00060000, 0x00040000);
 58
 59	pci_dev_put(pdev0);
 60
 61	return 0;
 62}
 63
 64static irqreturn_t cb710_irq_handler(int irq, void *data)
 65{
 66	struct cb710_chip *chip = data;
 67	struct cb710_slot *slot = &chip->slot[0];
 68	irqreturn_t handled = IRQ_NONE;
 69	unsigned nr;
 70
 71	spin_lock(&chip->irq_lock); /* incl. smp_rmb() */
 72
 73	for (nr = chip->slots; nr; ++slot, --nr) {
 74		cb710_irq_handler_t handler_func = slot->irq_handler;
 75		if (handler_func && handler_func(slot))
 76			handled = IRQ_HANDLED;
 77	}
 78
 79	spin_unlock(&chip->irq_lock);
 80
 81	return handled;
 82}
 83
 84static void cb710_release_slot(struct device *dev)
 85{
 86#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
 87	struct cb710_slot *slot = cb710_pdev_to_slot(to_platform_device(dev));
 88	struct cb710_chip *chip = cb710_slot_to_chip(slot);
 89
 90	/* slot struct can be freed now */
 91	atomic_dec(&chip->slot_refs_count);
 92#endif
 93}
 94
 95static int cb710_register_slot(struct cb710_chip *chip,
 96	unsigned slot_mask, unsigned io_offset, const char *name)
 97{
 98	int nr = chip->slots;
 99	struct cb710_slot *slot = &chip->slot[nr];
100	int err;
101
102	dev_dbg(cb710_chip_dev(chip),
103		"register: %s.%d; slot %d; mask %d; IO offset: 0x%02X\n",
104		name, chip->platform_id, nr, slot_mask, io_offset);
105
106	/* slot->irq_handler == NULL here; this needs to be
107	 * seen before platform_device_register() */
108	++chip->slots;
109	smp_wmb();
110
111	slot->iobase = chip->iobase + io_offset;
112	slot->pdev.name = name;
113	slot->pdev.id = chip->platform_id;
114	slot->pdev.dev.parent = &chip->pdev->dev;
115	slot->pdev.dev.release = cb710_release_slot;
116
117	err = platform_device_register(&slot->pdev);
118
119#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
120	atomic_inc(&chip->slot_refs_count);
121#endif
122
123	if (err) {
124		/* device_initialize() called from platform_device_register()
125		 * wants this on error path */
126		platform_device_put(&slot->pdev);
127
128		/* slot->irq_handler == NULL here anyway, so no lock needed */
129		--chip->slots;
130		return err;
131	}
132
133	chip->slot_mask |= slot_mask;
134
135	return 0;
136}
137
138static void cb710_unregister_slot(struct cb710_chip *chip,
139	unsigned slot_mask)
140{
141	int nr = chip->slots - 1;
142
143	if (!(chip->slot_mask & slot_mask))
144		return;
145
146	platform_device_unregister(&chip->slot[nr].pdev);
147
148	/* complementary to spin_unlock() in cb710_set_irq_handler() */
149	smp_rmb();
150	BUG_ON(chip->slot[nr].irq_handler != NULL);
151
152	/* slot->irq_handler == NULL here, so no lock needed */
153	--chip->slots;
154	chip->slot_mask &= ~slot_mask;
155}
156
157void cb710_set_irq_handler(struct cb710_slot *slot,
158	cb710_irq_handler_t handler)
159{
160	struct cb710_chip *chip = cb710_slot_to_chip(slot);
161	unsigned long flags;
162
163	spin_lock_irqsave(&chip->irq_lock, flags);
164	slot->irq_handler = handler;
165	spin_unlock_irqrestore(&chip->irq_lock, flags);
166}
167EXPORT_SYMBOL_GPL(cb710_set_irq_handler);
168
169static int __maybe_unused cb710_suspend(struct device *dev_d)
 
 
170{
171	struct pci_dev *pdev = to_pci_dev(dev_d);
172	struct cb710_chip *chip = pci_get_drvdata(pdev);
173
174	devm_free_irq(&pdev->dev, pdev->irq, chip);
 
 
 
 
175	return 0;
176}
177
178static int __maybe_unused cb710_resume(struct device *dev_d)
179{
180	struct pci_dev *pdev = to_pci_dev(dev_d);
181	struct cb710_chip *chip = pci_get_drvdata(pdev);
 
 
 
 
 
 
 
182
183	return devm_request_irq(&pdev->dev, pdev->irq,
184		cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
185}
186
187static int cb710_probe(struct pci_dev *pdev,
 
 
188	const struct pci_device_id *ent)
189{
190	struct cb710_chip *chip;
 
191	u32 val;
192	int err;
193	int n = 0;
194
195	err = cb710_pci_configure(pdev);
196	if (err)
197		return err;
198
199	/* this is actually magic... */
200	pci_read_config_dword(pdev, 0x48, &val);
201	if (!(val & 0x80000000)) {
202		pci_write_config_dword(pdev, 0x48, val|0x71000000);
203		pci_read_config_dword(pdev, 0x48, &val);
204	}
205
206	dev_dbg(&pdev->dev, "PCI config[0x48] = 0x%08X\n", val);
207	if (!(val & 0x70000000))
208		return -ENODEV;
209	val = (val >> 28) & 7;
210	if (val & CB710_SLOT_MMC)
211		++n;
212	if (val & CB710_SLOT_MS)
213		++n;
214	if (val & CB710_SLOT_SM)
215		++n;
216
217	chip = devm_kzalloc(&pdev->dev, struct_size(chip, slot, n),
218			    GFP_KERNEL);
219	if (!chip)
220		return -ENOMEM;
221
222	err = pcim_enable_device(pdev);
223	if (err)
224		return err;
225
226	err = pcim_iomap_regions(pdev, 0x0001, KBUILD_MODNAME);
227	if (err)
228		return err;
229
230	spin_lock_init(&chip->irq_lock);
231	chip->pdev = pdev;
232	chip->iobase = pcim_iomap_table(pdev)[0];
233
234	pci_set_drvdata(pdev, chip);
235
236	err = devm_request_irq(&pdev->dev, pdev->irq,
237		cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
238	if (err)
239		return err;
240
241	err = ida_alloc(&cb710_ida, GFP_KERNEL);
242	if (err < 0)
243		return err;
244	chip->platform_id = err;
 
 
 
 
 
 
 
 
245
246	dev_info(&pdev->dev, "id %d, IO 0x%p, IRQ %d\n",
247		chip->platform_id, chip->iobase, pdev->irq);
248
249	if (val & CB710_SLOT_MMC) {	/* MMC/SD slot */
250		err = cb710_register_slot(chip,
251			CB710_SLOT_MMC, 0x00, "cb710-mmc");
252		if (err)
253			return err;
254	}
255
256	if (val & CB710_SLOT_MS) {	/* MemoryStick slot */
257		err = cb710_register_slot(chip,
258			CB710_SLOT_MS, 0x40, "cb710-ms");
259		if (err)
260			goto unreg_mmc;
261	}
262
263	if (val & CB710_SLOT_SM) {	/* SmartMedia slot */
264		err = cb710_register_slot(chip,
265			CB710_SLOT_SM, 0x60, "cb710-sm");
266		if (err)
267			goto unreg_ms;
268	}
269
270	return 0;
271unreg_ms:
272	cb710_unregister_slot(chip, CB710_SLOT_MS);
273unreg_mmc:
274	cb710_unregister_slot(chip, CB710_SLOT_MMC);
275
276#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
277	BUG_ON(atomic_read(&chip->slot_refs_count) != 0);
278#endif
279	return err;
280}
281
282static void cb710_remove_one(struct pci_dev *pdev)
283{
284	struct cb710_chip *chip = pci_get_drvdata(pdev);
 
285
286	cb710_unregister_slot(chip, CB710_SLOT_SM);
287	cb710_unregister_slot(chip, CB710_SLOT_MS);
288	cb710_unregister_slot(chip, CB710_SLOT_MMC);
289#ifdef CONFIG_CB710_DEBUG_ASSUMPTIONS
290	BUG_ON(atomic_read(&chip->slot_refs_count) != 0);
291#endif
292
293	ida_free(&cb710_ida, chip->platform_id);
 
 
294}
295
296static const struct pci_device_id cb710_pci_tbl[] = {
297	{ PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_CB710_FLASH,
298		PCI_ANY_ID, PCI_ANY_ID, },
299	{ 0, }
300};
301
302static SIMPLE_DEV_PM_OPS(cb710_pm_ops, cb710_suspend, cb710_resume);
303
304static struct pci_driver cb710_driver = {
305	.name = KBUILD_MODNAME,
306	.id_table = cb710_pci_tbl,
307	.probe = cb710_probe,
308	.remove = cb710_remove_one,
309	.driver.pm = &cb710_pm_ops,
 
 
 
310};
311
312static int __init cb710_init_module(void)
313{
314	return pci_register_driver(&cb710_driver);
315}
316
317static void __exit cb710_cleanup_module(void)
318{
319	pci_unregister_driver(&cb710_driver);
320	ida_destroy(&cb710_ida);
321}
322
323module_init(cb710_init_module);
324module_exit(cb710_cleanup_module);
325
326MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
327MODULE_DESCRIPTION("ENE CB710 memory card reader driver");
328MODULE_LICENSE("GPL");
329MODULE_DEVICE_TABLE(pci, cb710_pci_tbl);