solo6x10-core.c (17501B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> 4 * 5 * Original author: 6 * Ben Collins <bcollins@ubuntu.com> 7 * 8 * Additional work by: 9 * John Brooks <john.brooks@bluecherry.net> 10 */ 11 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <linux/pci.h> 15#include <linux/interrupt.h> 16#include <linux/videodev2.h> 17#include <linux/delay.h> 18#include <linux/sysfs.h> 19#include <linux/ktime.h> 20#include <linux/slab.h> 21 22#include "solo6x10.h" 23#include "solo6x10-tw28.h" 24 25MODULE_DESCRIPTION("Softlogic 6x10 MPEG4/H.264/G.723 CODEC V4L2/ALSA Driver"); 26MODULE_AUTHOR("Bluecherry <maintainers@bluecherrydvr.com>"); 27MODULE_VERSION(SOLO6X10_VERSION); 28MODULE_LICENSE("GPL"); 29 30static unsigned video_nr = -1; 31module_param(video_nr, uint, 0644); 32MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)"); 33 34static int full_eeprom; /* default is only top 64B */ 35module_param(full_eeprom, uint, 0644); 36MODULE_PARM_DESC(full_eeprom, "Allow access to full 128B EEPROM (dangerous)"); 37 38 39static void solo_set_time(struct solo_dev *solo_dev) 40{ 41 struct timespec64 ts; 42 43 ktime_get_ts64(&ts); 44 45 /* no overflow because we use monotonic timestamps */ 46 solo_reg_write(solo_dev, SOLO_TIMER_SEC, (u32)ts.tv_sec); 47 solo_reg_write(solo_dev, SOLO_TIMER_USEC, (u32)ts.tv_nsec / NSEC_PER_USEC); 48} 49 50static void solo_timer_sync(struct solo_dev *solo_dev) 51{ 52 u32 sec, usec; 53 struct timespec64 ts; 54 long diff; 55 56 if (solo_dev->type != SOLO_DEV_6110) 57 return; 58 59 if (++solo_dev->time_sync < 60) 60 return; 61 62 solo_dev->time_sync = 0; 63 64 sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC); 65 usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC); 66 67 ktime_get_ts64(&ts); 68 69 diff = (s32)ts.tv_sec - (s32)sec; 70 diff = (diff * 1000000) 71 + ((s32)(ts.tv_nsec / NSEC_PER_USEC) - (s32)usec); 72 73 if (diff > 1000 || diff < -1000) { 74 solo_set_time(solo_dev); 75 } else if (diff) { 76 long usec_lsb = solo_dev->usec_lsb; 77 78 usec_lsb -= diff / 4; 79 if (usec_lsb < 0) 80 usec_lsb = 0; 81 else if (usec_lsb > 255) 82 usec_lsb = 255; 83 84 solo_dev->usec_lsb = usec_lsb; 85 solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB, 86 solo_dev->usec_lsb); 87 } 88} 89 90static irqreturn_t solo_isr(int irq, void *data) 91{ 92 struct solo_dev *solo_dev = data; 93 u32 status; 94 int i; 95 96 status = solo_reg_read(solo_dev, SOLO_IRQ_STAT); 97 if (!status) 98 return IRQ_NONE; 99 100 /* Acknowledge all interrupts immediately */ 101 solo_reg_write(solo_dev, SOLO_IRQ_STAT, status); 102 103 if (status & SOLO_IRQ_PCI_ERR) 104 solo_p2m_error_isr(solo_dev); 105 106 for (i = 0; i < SOLO_NR_P2M; i++) 107 if (status & SOLO_IRQ_P2M(i)) 108 solo_p2m_isr(solo_dev, i); 109 110 if (status & SOLO_IRQ_IIC) 111 solo_i2c_isr(solo_dev); 112 113 if (status & SOLO_IRQ_VIDEO_IN) { 114 solo_video_in_isr(solo_dev); 115 solo_timer_sync(solo_dev); 116 } 117 118 if (status & SOLO_IRQ_ENCODER) 119 solo_enc_v4l2_isr(solo_dev); 120 121 if (status & SOLO_IRQ_G723) 122 solo_g723_isr(solo_dev); 123 124 return IRQ_HANDLED; 125} 126 127static void free_solo_dev(struct solo_dev *solo_dev) 128{ 129 struct pci_dev *pdev = solo_dev->pdev; 130 131 if (solo_dev->dev.parent) 132 device_unregister(&solo_dev->dev); 133 134 if (solo_dev->reg_base) { 135 /* Bring down the sub-devices first */ 136 solo_g723_exit(solo_dev); 137 solo_enc_v4l2_exit(solo_dev); 138 solo_enc_exit(solo_dev); 139 solo_v4l2_exit(solo_dev); 140 solo_disp_exit(solo_dev); 141 solo_gpio_exit(solo_dev); 142 solo_p2m_exit(solo_dev); 143 solo_i2c_exit(solo_dev); 144 145 /* Now cleanup the PCI device */ 146 solo_irq_off(solo_dev, ~0); 147 free_irq(pdev->irq, solo_dev); 148 pci_iounmap(pdev, solo_dev->reg_base); 149 } 150 151 pci_release_regions(pdev); 152 pci_disable_device(pdev); 153 v4l2_device_unregister(&solo_dev->v4l2_dev); 154 pci_set_drvdata(pdev, NULL); 155 156 kfree(solo_dev); 157} 158 159static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr, 160 const char *buf, size_t count) 161{ 162 struct solo_dev *solo_dev = 163 container_of(dev, struct solo_dev, dev); 164 u16 *p = (u16 *)buf; 165 int i; 166 167 if (count & 0x1) 168 dev_warn(dev, "EEPROM Write not aligned (truncating)\n"); 169 170 if (!full_eeprom && count > 64) { 171 dev_warn(dev, "EEPROM Write truncated to 64 bytes\n"); 172 count = 64; 173 } else if (full_eeprom && count > 128) { 174 dev_warn(dev, "EEPROM Write truncated to 128 bytes\n"); 175 count = 128; 176 } 177 178 solo_eeprom_ewen(solo_dev, 1); 179 180 for (i = full_eeprom ? 0 : 32; i < min((int)(full_eeprom ? 64 : 32), 181 (int)(count / 2)); i++) 182 solo_eeprom_write(solo_dev, i, cpu_to_be16(p[i])); 183 184 solo_eeprom_ewen(solo_dev, 0); 185 186 return count; 187} 188 189static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr, 190 char *buf) 191{ 192 struct solo_dev *solo_dev = 193 container_of(dev, struct solo_dev, dev); 194 u16 *p = (u16 *)buf; 195 int count = (full_eeprom ? 128 : 64); 196 int i; 197 198 for (i = (full_eeprom ? 0 : 32); i < (count / 2); i++) 199 p[i] = be16_to_cpu(solo_eeprom_read(solo_dev, i)); 200 201 return count; 202} 203 204static ssize_t p2m_timeouts_show(struct device *dev, 205 struct device_attribute *attr, 206 char *buf) 207{ 208 struct solo_dev *solo_dev = 209 container_of(dev, struct solo_dev, dev); 210 211 return sprintf(buf, "%d\n", solo_dev->p2m_timeouts); 212} 213 214static ssize_t sdram_size_show(struct device *dev, 215 struct device_attribute *attr, 216 char *buf) 217{ 218 struct solo_dev *solo_dev = 219 container_of(dev, struct solo_dev, dev); 220 221 return sprintf(buf, "%dMegs\n", solo_dev->sdram_size >> 20); 222} 223 224static ssize_t tw28xx_show(struct device *dev, 225 struct device_attribute *attr, 226 char *buf) 227{ 228 struct solo_dev *solo_dev = 229 container_of(dev, struct solo_dev, dev); 230 231 return sprintf(buf, "tw2815[%d] tw2864[%d] tw2865[%d]\n", 232 hweight32(solo_dev->tw2815), 233 hweight32(solo_dev->tw2864), 234 hweight32(solo_dev->tw2865)); 235} 236 237static ssize_t input_map_show(struct device *dev, 238 struct device_attribute *attr, 239 char *buf) 240{ 241 struct solo_dev *solo_dev = 242 container_of(dev, struct solo_dev, dev); 243 unsigned int val; 244 char *out = buf; 245 246 val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_0); 247 out += sprintf(out, "Channel 0 => Input %d\n", val & 0x1f); 248 out += sprintf(out, "Channel 1 => Input %d\n", (val >> 5) & 0x1f); 249 out += sprintf(out, "Channel 2 => Input %d\n", (val >> 10) & 0x1f); 250 out += sprintf(out, "Channel 3 => Input %d\n", (val >> 15) & 0x1f); 251 out += sprintf(out, "Channel 4 => Input %d\n", (val >> 20) & 0x1f); 252 out += sprintf(out, "Channel 5 => Input %d\n", (val >> 25) & 0x1f); 253 254 val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_1); 255 out += sprintf(out, "Channel 6 => Input %d\n", val & 0x1f); 256 out += sprintf(out, "Channel 7 => Input %d\n", (val >> 5) & 0x1f); 257 out += sprintf(out, "Channel 8 => Input %d\n", (val >> 10) & 0x1f); 258 out += sprintf(out, "Channel 9 => Input %d\n", (val >> 15) & 0x1f); 259 out += sprintf(out, "Channel 10 => Input %d\n", (val >> 20) & 0x1f); 260 out += sprintf(out, "Channel 11 => Input %d\n", (val >> 25) & 0x1f); 261 262 val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_2); 263 out += sprintf(out, "Channel 12 => Input %d\n", val & 0x1f); 264 out += sprintf(out, "Channel 13 => Input %d\n", (val >> 5) & 0x1f); 265 out += sprintf(out, "Channel 14 => Input %d\n", (val >> 10) & 0x1f); 266 out += sprintf(out, "Channel 15 => Input %d\n", (val >> 15) & 0x1f); 267 out += sprintf(out, "Spot Output => Input %d\n", (val >> 20) & 0x1f); 268 269 return out - buf; 270} 271 272static ssize_t p2m_timeout_store(struct device *dev, 273 struct device_attribute *attr, 274 const char *buf, size_t count) 275{ 276 struct solo_dev *solo_dev = 277 container_of(dev, struct solo_dev, dev); 278 unsigned long ms; 279 int ret = kstrtoul(buf, 10, &ms); 280 281 if (ret < 0 || ms > 200) 282 return -EINVAL; 283 solo_dev->p2m_jiffies = msecs_to_jiffies(ms); 284 285 return count; 286} 287 288static ssize_t p2m_timeout_show(struct device *dev, 289 struct device_attribute *attr, 290 char *buf) 291{ 292 struct solo_dev *solo_dev = 293 container_of(dev, struct solo_dev, dev); 294 295 return sprintf(buf, "%ums\n", jiffies_to_msecs(solo_dev->p2m_jiffies)); 296} 297 298static ssize_t intervals_show(struct device *dev, 299 struct device_attribute *attr, 300 char *buf) 301{ 302 struct solo_dev *solo_dev = 303 container_of(dev, struct solo_dev, dev); 304 char *out = buf; 305 int fps = solo_dev->fps; 306 int i; 307 308 for (i = 0; i < solo_dev->nr_chans; i++) { 309 out += sprintf(out, "Channel %d: %d/%d (0x%08x)\n", 310 i, solo_dev->v4l2_enc[i]->interval, fps, 311 solo_reg_read(solo_dev, SOLO_CAP_CH_INTV(i))); 312 } 313 314 return out - buf; 315} 316 317static ssize_t sdram_offsets_show(struct device *dev, 318 struct device_attribute *attr, 319 char *buf) 320{ 321 struct solo_dev *solo_dev = 322 container_of(dev, struct solo_dev, dev); 323 char *out = buf; 324 325 out += sprintf(out, "DISP: 0x%08x @ 0x%08x\n", 326 SOLO_DISP_EXT_ADDR, 327 SOLO_DISP_EXT_SIZE); 328 329 out += sprintf(out, "EOSD: 0x%08x @ 0x%08x (0x%08x * %d)\n", 330 SOLO_EOSD_EXT_ADDR, 331 SOLO_EOSD_EXT_AREA(solo_dev), 332 SOLO_EOSD_EXT_SIZE(solo_dev), 333 SOLO_EOSD_EXT_AREA(solo_dev) / 334 SOLO_EOSD_EXT_SIZE(solo_dev)); 335 336 out += sprintf(out, "MOTI: 0x%08x @ 0x%08x\n", 337 SOLO_MOTION_EXT_ADDR(solo_dev), 338 SOLO_MOTION_EXT_SIZE); 339 340 out += sprintf(out, "G723: 0x%08x @ 0x%08x\n", 341 SOLO_G723_EXT_ADDR(solo_dev), 342 SOLO_G723_EXT_SIZE); 343 344 out += sprintf(out, "CAPT: 0x%08x @ 0x%08x (0x%08x * %d)\n", 345 SOLO_CAP_EXT_ADDR(solo_dev), 346 SOLO_CAP_EXT_SIZE(solo_dev), 347 SOLO_CAP_PAGE_SIZE, 348 SOLO_CAP_EXT_SIZE(solo_dev) / SOLO_CAP_PAGE_SIZE); 349 350 out += sprintf(out, "EREF: 0x%08x @ 0x%08x (0x%08x * %d)\n", 351 SOLO_EREF_EXT_ADDR(solo_dev), 352 SOLO_EREF_EXT_AREA(solo_dev), 353 SOLO_EREF_EXT_SIZE, 354 SOLO_EREF_EXT_AREA(solo_dev) / SOLO_EREF_EXT_SIZE); 355 356 out += sprintf(out, "MPEG: 0x%08x @ 0x%08x\n", 357 SOLO_MP4E_EXT_ADDR(solo_dev), 358 SOLO_MP4E_EXT_SIZE(solo_dev)); 359 360 out += sprintf(out, "JPEG: 0x%08x @ 0x%08x\n", 361 SOLO_JPEG_EXT_ADDR(solo_dev), 362 SOLO_JPEG_EXT_SIZE(solo_dev)); 363 364 return out - buf; 365} 366 367static ssize_t sdram_show(struct file *file, struct kobject *kobj, 368 struct bin_attribute *a, char *buf, 369 loff_t off, size_t count) 370{ 371 struct device *dev = kobj_to_dev(kobj); 372 struct solo_dev *solo_dev = 373 container_of(dev, struct solo_dev, dev); 374 const int size = solo_dev->sdram_size; 375 376 if (off >= size) 377 return 0; 378 379 if (off + count > size) 380 count = size - off; 381 382 if (solo_p2m_dma(solo_dev, 0, buf, off, count, 0, 0)) 383 return -EIO; 384 385 return count; 386} 387 388static const struct device_attribute solo_dev_attrs[] = { 389 __ATTR(eeprom, 0640, eeprom_show, eeprom_store), 390 __ATTR(p2m_timeout, 0644, p2m_timeout_show, p2m_timeout_store), 391 __ATTR_RO(p2m_timeouts), 392 __ATTR_RO(sdram_size), 393 __ATTR_RO(tw28xx), 394 __ATTR_RO(input_map), 395 __ATTR_RO(intervals), 396 __ATTR_RO(sdram_offsets), 397}; 398 399static void solo_device_release(struct device *dev) 400{ 401 /* Do nothing */ 402} 403 404static int solo_sysfs_init(struct solo_dev *solo_dev) 405{ 406 struct bin_attribute *sdram_attr = &solo_dev->sdram_attr; 407 struct device *dev = &solo_dev->dev; 408 const char *driver; 409 int i; 410 411 if (solo_dev->type == SOLO_DEV_6110) 412 driver = "solo6110"; 413 else 414 driver = "solo6010"; 415 416 dev->release = solo_device_release; 417 dev->parent = &solo_dev->pdev->dev; 418 set_dev_node(dev, dev_to_node(&solo_dev->pdev->dev)); 419 dev_set_name(dev, "%s-%d-%d", driver, solo_dev->vfd->num, 420 solo_dev->nr_chans); 421 422 if (device_register(dev)) { 423 dev->parent = NULL; 424 return -ENOMEM; 425 } 426 427 for (i = 0; i < ARRAY_SIZE(solo_dev_attrs); i++) { 428 if (device_create_file(dev, &solo_dev_attrs[i])) { 429 device_unregister(dev); 430 return -ENOMEM; 431 } 432 } 433 434 sysfs_attr_init(&sdram_attr->attr); 435 sdram_attr->attr.name = "sdram"; 436 sdram_attr->attr.mode = 0440; 437 sdram_attr->read = sdram_show; 438 sdram_attr->size = solo_dev->sdram_size; 439 440 if (device_create_bin_file(dev, sdram_attr)) { 441 device_unregister(dev); 442 return -ENOMEM; 443 } 444 445 return 0; 446} 447 448static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 449{ 450 struct solo_dev *solo_dev; 451 int ret; 452 u8 chip_id; 453 454 solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL); 455 if (solo_dev == NULL) 456 return -ENOMEM; 457 458 if (id->driver_data == SOLO_DEV_6010) 459 dev_info(&pdev->dev, "Probing Softlogic 6010\n"); 460 else 461 dev_info(&pdev->dev, "Probing Softlogic 6110\n"); 462 463 solo_dev->type = id->driver_data; 464 solo_dev->pdev = pdev; 465 ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev); 466 if (ret) 467 goto fail_probe; 468 469 /* Only for during init */ 470 solo_dev->p2m_jiffies = msecs_to_jiffies(100); 471 472 ret = pci_enable_device(pdev); 473 if (ret) 474 goto fail_probe; 475 476 pci_set_master(pdev); 477 478 /* RETRY/TRDY Timeout disabled */ 479 pci_write_config_byte(pdev, 0x40, 0x00); 480 pci_write_config_byte(pdev, 0x41, 0x00); 481 482 ret = pci_request_regions(pdev, SOLO6X10_NAME); 483 if (ret) 484 goto fail_probe; 485 486 solo_dev->reg_base = pci_ioremap_bar(pdev, 0); 487 if (solo_dev->reg_base == NULL) { 488 ret = -ENOMEM; 489 goto fail_probe; 490 } 491 492 chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) & 493 SOLO_CHIP_ID_MASK; 494 switch (chip_id) { 495 case 7: 496 solo_dev->nr_chans = 16; 497 solo_dev->nr_ext = 5; 498 break; 499 case 6: 500 solo_dev->nr_chans = 8; 501 solo_dev->nr_ext = 2; 502 break; 503 default: 504 dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, assuming 4 ch\n", 505 chip_id); 506 fallthrough; 507 case 5: 508 solo_dev->nr_chans = 4; 509 solo_dev->nr_ext = 1; 510 } 511 512 /* Disable all interrupts to start */ 513 solo_irq_off(solo_dev, ~0); 514 515 /* Initial global settings */ 516 if (solo_dev->type == SOLO_DEV_6010) { 517 solo_dev->clock_mhz = 108; 518 solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT 519 | SOLO_SYS_CFG_INPUTDIV(25) 520 | SOLO_SYS_CFG_FEEDBACKDIV(solo_dev->clock_mhz * 2 - 2) 521 | SOLO_SYS_CFG_OUTDIV(3); 522 solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); 523 } else { 524 u32 divq, divf; 525 526 solo_dev->clock_mhz = 135; 527 528 if (solo_dev->clock_mhz < 125) { 529 divq = 3; 530 divf = (solo_dev->clock_mhz * 4) / 3 - 1; 531 } else { 532 divq = 2; 533 divf = (solo_dev->clock_mhz * 2) / 3 - 1; 534 } 535 536 solo_reg_write(solo_dev, SOLO_PLL_CONFIG, 537 (1 << 20) | /* PLL_RANGE */ 538 (8 << 15) | /* PLL_DIVR */ 539 (divq << 12) | 540 (divf << 4) | 541 (1 << 1) /* PLL_FSEN */); 542 543 solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT; 544 } 545 546 solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); 547 solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, 548 solo_dev->clock_mhz - 1); 549 550 /* PLL locking time of 1ms */ 551 mdelay(1); 552 553 ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME, 554 solo_dev); 555 if (ret) 556 goto fail_probe; 557 558 /* Handle this from the start */ 559 solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR); 560 561 ret = solo_i2c_init(solo_dev); 562 if (ret) 563 goto fail_probe; 564 565 /* Setup the DMA engine */ 566 solo_reg_write(solo_dev, SOLO_DMA_CTRL, 567 SOLO_DMA_CTRL_REFRESH_CYCLE(1) | 568 SOLO_DMA_CTRL_SDRAM_SIZE(2) | 569 SOLO_DMA_CTRL_SDRAM_CLK_INVERT | 570 SOLO_DMA_CTRL_READ_CLK_SELECT | 571 SOLO_DMA_CTRL_LATENCY(1)); 572 573 /* Undocumented crap */ 574 solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 575 solo_dev->type == SOLO_DEV_6010 ? 0x100 : 0x300); 576 577 if (solo_dev->type != SOLO_DEV_6010) { 578 solo_dev->usec_lsb = 0x3f; 579 solo_set_time(solo_dev); 580 } 581 582 /* Disable watchdog */ 583 solo_reg_write(solo_dev, SOLO_WATCHDOG, 0); 584 585 /* Initialize sub components */ 586 587 ret = solo_p2m_init(solo_dev); 588 if (ret) 589 goto fail_probe; 590 591 ret = solo_disp_init(solo_dev); 592 if (ret) 593 goto fail_probe; 594 595 ret = solo_gpio_init(solo_dev); 596 if (ret) 597 goto fail_probe; 598 599 ret = solo_tw28_init(solo_dev); 600 if (ret) 601 goto fail_probe; 602 603 ret = solo_v4l2_init(solo_dev, video_nr); 604 if (ret) 605 goto fail_probe; 606 607 ret = solo_enc_init(solo_dev); 608 if (ret) 609 goto fail_probe; 610 611 ret = solo_enc_v4l2_init(solo_dev, video_nr); 612 if (ret) 613 goto fail_probe; 614 615 ret = solo_g723_init(solo_dev); 616 if (ret) 617 goto fail_probe; 618 619 ret = solo_sysfs_init(solo_dev); 620 if (ret) 621 goto fail_probe; 622 623 /* Now that init is over, set this lower */ 624 solo_dev->p2m_jiffies = msecs_to_jiffies(20); 625 626 return 0; 627 628fail_probe: 629 free_solo_dev(solo_dev); 630 return ret; 631} 632 633static void solo_pci_remove(struct pci_dev *pdev) 634{ 635 struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); 636 struct solo_dev *solo_dev = container_of(v4l2_dev, struct solo_dev, v4l2_dev); 637 638 free_solo_dev(solo_dev); 639} 640 641static const struct pci_device_id solo_id_table[] = { 642 /* 6010 based cards */ 643 { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010), 644 .driver_data = SOLO_DEV_6010 }, 645 { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4), 646 .driver_data = SOLO_DEV_6010 }, 647 { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9), 648 .driver_data = SOLO_DEV_6010 }, 649 { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16), 650 .driver_data = SOLO_DEV_6010 }, 651 { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4), 652 .driver_data = SOLO_DEV_6010 }, 653 { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9), 654 .driver_data = SOLO_DEV_6010 }, 655 { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16), 656 .driver_data = SOLO_DEV_6010 }, 657 /* 6110 based cards */ 658 { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110), 659 .driver_data = SOLO_DEV_6110 }, 660 { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4), 661 .driver_data = SOLO_DEV_6110 }, 662 { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8), 663 .driver_data = SOLO_DEV_6110 }, 664 { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16), 665 .driver_data = SOLO_DEV_6110 }, 666 {0,} 667}; 668 669MODULE_DEVICE_TABLE(pci, solo_id_table); 670 671static struct pci_driver solo_pci_driver = { 672 .name = SOLO6X10_NAME, 673 .id_table = solo_id_table, 674 .probe = solo_pci_probe, 675 .remove = solo_pci_remove, 676}; 677 678module_pci_driver(solo_pci_driver);