| 1 | |
| 2 | |
| 3 | * pata_serverworks.c - Serverworks PATA for new ATA layer
|
| 4 | * (C) 2005 Red Hat Inc
|
| 5 | * (C) 2010 Bartlomiej Zolnierkiewicz
|
| 6 | *
|
| 7 | * based upon
|
| 8 | *
|
| 9 | * serverworks.c
|
| 10 | *
|
| 11 | * Copyright (C) 1998-2000 Michel Aubry
|
| 12 | * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
|
| 13 | * Copyright (C) 1998-2000 Andre Hedrick <[email protected]>
|
| 14 | * Portions copyright (c) 2001 Sun Microsystems
|
| 15 | *
|
| 16 | *
|
| 17 | * RCC/ServerWorks IDE driver for Linux
|
| 18 | *
|
| 19 | * OSB4: `Open South Bridge' IDE Interface (fn 1)
|
| 20 | * supports UDMA mode 2 (33 MB/s)
|
| 21 | *
|
| 22 | * CSB5: `Champion South Bridge' IDE Interface (fn 1)
|
| 23 | * all revisions support UDMA mode 4 (66 MB/s)
|
| 24 | * revision A2.0 and up support UDMA mode 5 (100 MB/s)
|
| 25 | *
|
| 26 | * *** The CSB5 does not provide ANY register ***
|
| 27 | * *** to detect 80-conductor cable presence. ***
|
| 28 | *
|
| 29 | * CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
|
| 30 | *
|
| 31 | * Documentation:
|
| 32 | * Available under NDA only. Errata info very hard to get.
|
| 33 |
|
| 34 |
|
| 35 | #include <linux/kernel.h>
|
| 36 | #include <linux/module.h>
|
| 37 | #include <linux/pci.h>
|
| 38 | #include <linux/blkdev.h>
|
| 39 | #include <linux/delay.h>
|
| 40 | #include <scsi/scsi_host.h>
|
| 41 | #include <linux/libata.h>
|
| 42 |
|
| 43 | #define DRV_NAME "pata_serverworks"
|
| 44 | #define DRV_VERSION "0.4.3"
|
| 45 |
|
| 46 | #define SVWKS_CSB5_REVISION_NEW 0x92
|
| 47 | #define SVWKS_CSB6_REVISION 0xa0
|
| 48 |
|
| 49 | |
| 50 | * Seagate Barracuda ATA IV Family drives in UDMA mode 5
|
| 51 | * can overrun their FIFOs when used with the CSB5.
|
| 52 |
|
| 53 | static const char * const csb_bad_ata100[] = {
|
| 54 | "ST320011A",
|
| 55 | "ST340016A",
|
| 56 | "ST360021A",
|
| 57 | "ST380021A",
|
| 58 | NULL
|
| 59 | };
|
| 60 |
|
| 61 | |
| 62 | * oem_cable - Dell/Sun serverworks cable detection
|
| 63 | * @ap: ATA port to do cable detect
|
| 64 | *
|
| 65 | * Dell PowerEdge and Sun Cobalt 'Alpine' hide the 40/80 pin select
|
| 66 | * for their interfaces in the top two bits of the subsystem ID.
|
| 67 |
|
| 68 |
|
| 69 | static int oem_cable(struct ata_port *ap)
|
| 70 | {
|
| 71 | struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
| 72 |
|
| 73 | if (pdev->subsystem_device & (1 << (ap->port_no + 14)))
|
| 74 | return ATA_CBL_PATA80;
|
| 75 | return ATA_CBL_PATA40;
|
| 76 | }
|
| 77 |
|
| 78 | struct sv_cable_table {
|
| 79 | int device;
|
| 80 | int subvendor;
|
| 81 | int (*cable_detect)(struct ata_port *ap);
|
| 82 | };
|
| 83 |
|
| 84 | static struct sv_cable_table cable_detect[] = {
|
| 85 | { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, oem_cable },
|
| 86 | { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, oem_cable },
|
| 87 | { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, oem_cable },
|
| 88 | { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, ata_cable_40wire },
|
| 89 | { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, ata_cable_unknown },
|
| 90 | { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, ata_cable_unknown },
|
| 91 | { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, ata_cable_unknown },
|
| 92 | { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, ata_cable_unknown },
|
| 93 | { }
|
| 94 | };
|
| 95 |
|
| 96 | |
| 97 | * serverworks_cable_detect - cable detection
|
| 98 | * @ap: ATA port
|
| 99 | *
|
| 100 | * Perform cable detection according to the device and subvendor
|
| 101 | * identifications
|
| 102 |
|
| 103 |
|
| 104 | static int serverworks_cable_detect(struct ata_port *ap)
|
| 105 | {
|
| 106 | struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
| 107 | struct sv_cable_table *cb = cable_detect;
|
| 108 |
|
| 109 | while(cb->device) {
|
| 110 | if (cb->device == pdev->device &&
|
| 111 | (cb->subvendor == pdev->subsystem_vendor ||
|
| 112 | cb->subvendor == PCI_ANY_ID)) {
|
| 113 | return cb->cable_detect(ap);
|
| 114 | }
|
| 115 | cb++;
|
| 116 | }
|
| 117 |
|
| 118 | BUG();
|
| 119 | return -1;
|
| 120 | }
|
| 121 |
|
| 122 | |
| 123 | * serverworks_is_csb - Check for CSB or OSB
|
| 124 | * @pdev: PCI device to check
|
| 125 | *
|
| 126 | * Returns true if the device being checked is known to be a CSB
|
| 127 | * series device.
|
| 128 |
|
| 129 |
|
| 130 | static u8 serverworks_is_csb(struct pci_dev *pdev)
|
| 131 | {
|
| 132 | switch (pdev->device) {
|
| 133 | case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
|
| 134 | case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
|
| 135 | case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
|
| 136 | case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
|
| 137 | return 1;
|
| 138 | default:
|
| 139 | break;
|
| 140 | }
|
| 141 | return 0;
|
| 142 | }
|
| 143 |
|
| 144 | |
| 145 | * serverworks_osb4_filter - mode selection filter
|
| 146 | * @adev: ATA device
|
| 147 | * @mask: Mask of proposed modes
|
| 148 | *
|
| 149 | * Filter the offered modes for the device to apply controller
|
| 150 | * specific rules. OSB4 requires no UDMA for disks due to a FIFO
|
| 151 | * bug we hit.
|
| 152 |
|
| 153 |
|
| 154 | static unsigned int serverworks_osb4_filter(struct ata_device *adev, unsigned int mask)
|
| 155 | {
|
| 156 | if (adev->class == ATA_DEV_ATA)
|
| 157 | mask &= ~ATA_MASK_UDMA;
|
| 158 | return mask;
|
| 159 | }
|
| 160 |
|
| 161 |
|
| 162 | |
| 163 | * serverworks_csb_filter - mode selection filter
|
| 164 | * @adev: ATA device
|
| 165 | * @mask: Mask of proposed modes
|
| 166 | *
|
| 167 | * Check the list of devices with broken UDMA5 and
|
| 168 | * disable UDMA5 if matched.
|
| 169 |
|
| 170 | static unsigned int serverworks_csb_filter(struct ata_device *adev,
|
| 171 | unsigned int mask)
|
| 172 | {
|
| 173 | const char *p;
|
| 174 | char model_num[ATA_ID_PROD_LEN + 1];
|
| 175 | int i;
|
| 176 |
|
| 177 |
|
| 178 | if (adev->class != ATA_DEV_ATA)
|
| 179 | return mask;
|
| 180 |
|
| 181 |
|
| 182 | ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
|
| 183 |
|
| 184 | for (i = 0; (p = csb_bad_ata100[i]) != NULL; i++) {
|
| 185 | if (!strcmp(p, model_num))
|
| 186 | mask &= ~(0xE0 << ATA_SHIFT_UDMA);
|
| 187 | }
|
| 188 | return mask;
|
| 189 | }
|
| 190 |
|
| 191 | |
| 192 | * serverworks_set_piomode - set initial PIO mode data
|
| 193 | * @ap: ATA interface
|
| 194 | * @adev: ATA device
|
| 195 | *
|
| 196 | * Program the OSB4/CSB5 timing registers for PIO. The PIO register
|
| 197 | * load is done as a simple lookup.
|
| 198 |
|
| 199 | static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
| 200 | {
|
| 201 | static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
|
| 202 | int offset = 1 + 2 * ap->port_no - adev->devno;
|
| 203 | int devbits = (2 * ap->port_no + adev->devno) * 4;
|
| 204 | u16 csb5_pio;
|
| 205 | struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
| 206 | int pio = adev->pio_mode - XFER_PIO_0;
|
| 207 |
|
| 208 | pci_write_config_byte(pdev, 0x40 + offset, pio_mode[pio]);
|
| 209 |
|
| 210 | |
| 211 | mode number as well
|
| 212 | if (serverworks_is_csb(pdev)) {
|
| 213 | pci_read_config_word(pdev, 0x4A, &csb5_pio);
|
| 214 | csb5_pio &= ~(0x0F << devbits);
|
| 215 | pci_write_config_word(pdev, 0x4A, csb5_pio | (pio << devbits));
|
| 216 | }
|
| 217 | }
|
| 218 |
|
| 219 | |
| 220 | * serverworks_set_dmamode - set initial DMA mode data
|
| 221 | * @ap: ATA interface
|
| 222 | * @adev: ATA device
|
| 223 | *
|
| 224 | * Program the MWDMA/UDMA modes for the serverworks OSB4/CSB5
|
| 225 | * chipset. The MWDMA mode values are pulled from a lookup table
|
| 226 | * while the chipset uses mode number for UDMA.
|
| 227 |
|
| 228 |
|
| 229 | static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev)
|
| 230 | {
|
| 231 | static const u8 dma_mode[] = { 0x77, 0x21, 0x20 };
|
| 232 | int offset = 1 + 2 * ap->port_no - adev->devno;
|
| 233 | int devbits = 2 * ap->port_no + adev->devno;
|
| 234 | u8 ultra;
|
| 235 | u8 ultra_cfg;
|
| 236 | struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
| 237 |
|
| 238 | pci_read_config_byte(pdev, 0x54, &ultra_cfg);
|
| 239 | pci_read_config_byte(pdev, 0x56 + ap->port_no, &ultra);
|
| 240 | ultra &= ~(0x0F << (adev->devno * 4));
|
| 241 |
|
| 242 | if (adev->dma_mode >= XFER_UDMA_0) {
|
| 243 | pci_write_config_byte(pdev, 0x44 + offset, 0x20);
|
| 244 |
|
| 245 | ultra |= (adev->dma_mode - XFER_UDMA_0)
|
| 246 | << (adev->devno * 4);
|
| 247 | ultra_cfg |= (1 << devbits);
|
| 248 | } else {
|
| 249 | pci_write_config_byte(pdev, 0x44 + offset,
|
| 250 | dma_mode[adev->dma_mode - XFER_MW_DMA_0]);
|
| 251 | ultra_cfg &= ~(1 << devbits);
|
| 252 | }
|
| 253 | pci_write_config_byte(pdev, 0x56 + ap->port_no, ultra);
|
| 254 | pci_write_config_byte(pdev, 0x54, ultra_cfg);
|
| 255 | }
|
| 256 |
|
| 257 | static const struct scsi_host_template serverworks_osb4_sht = {
|
| 258 | ATA_BASE_SHT(DRV_NAME),
|
| 259 | .sg_tablesize = LIBATA_DUMB_MAX_PRD,
|
| 260 | .dma_boundary = ATA_DMA_BOUNDARY,
|
| 261 | };
|
| 262 |
|
| 263 | static const struct scsi_host_template serverworks_csb_sht = {
|
| 264 | ATA_BMDMA_SHT(DRV_NAME),
|
| 265 | };
|
| 266 |
|
| 267 | static struct ata_port_operations serverworks_osb4_port_ops = {
|
| 268 | .inherits = &ata_bmdma_port_ops,
|
| 269 | .qc_prep = ata_bmdma_dumb_qc_prep,
|
| 270 | .cable_detect = serverworks_cable_detect,
|
| 271 | .mode_filter = serverworks_osb4_filter,
|
| 272 | .set_piomode = serverworks_set_piomode,
|
| 273 | .set_dmamode = serverworks_set_dmamode,
|
| 274 | };
|
| 275 |
|
| 276 | static struct ata_port_operations serverworks_csb_port_ops = {
|
| 277 | .inherits = &serverworks_osb4_port_ops,
|
| 278 | .qc_prep = ata_bmdma_qc_prep,
|
| 279 | .mode_filter = serverworks_csb_filter,
|
| 280 | };
|
| 281 |
|
| 282 | static int serverworks_fixup_osb4(struct pci_dev *pdev)
|
| 283 | {
|
| 284 | u32 reg;
|
| 285 | struct pci_dev *isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
|
| 286 | PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
|
| 287 | if (isa_dev) {
|
| 288 | pci_read_config_dword(isa_dev, 0x64, ®);
|
| 289 | reg &= ~0x00002000;
|
| 290 | if (!(reg & 0x00004000))
|
| 291 | dev_info(&pdev->dev, "UDMA not BIOS enabled.\n");
|
| 292 | reg |= 0x00004000;
|
| 293 | pci_write_config_dword(isa_dev, 0x64, reg);
|
| 294 | pci_dev_put(isa_dev);
|
| 295 | return 0;
|
| 296 | }
|
| 297 | dev_warn(&pdev->dev, "Unable to find bridge.\n");
|
| 298 | return -ENODEV;
|
| 299 | }
|
| 300 |
|
| 301 | static int serverworks_fixup_csb(struct pci_dev *pdev)
|
| 302 | {
|
| 303 | u8 btr;
|
| 304 |
|
| 305 |
|
| 306 | if (!(PCI_FUNC(pdev->devfn) & 1)) {
|
| 307 | struct pci_dev * findev = NULL;
|
| 308 | u32 reg4c = 0;
|
| 309 | findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
|
| 310 | PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
|
| 311 | if (findev) {
|
| 312 | pci_read_config_dword(findev, 0x4C, ®4c);
|
| 313 | reg4c &= ~0x000007FF;
|
| 314 | reg4c |= 0x00000040;
|
| 315 | reg4c |= 0x00000020;
|
| 316 | pci_write_config_dword(findev, 0x4C, reg4c);
|
| 317 | pci_dev_put(findev);
|
| 318 | }
|
| 319 | } else {
|
| 320 | struct pci_dev * findev = NULL;
|
| 321 | u8 reg41 = 0;
|
| 322 |
|
| 323 | findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
|
| 324 | PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
|
| 325 | if (findev) {
|
| 326 | pci_read_config_byte(findev, 0x41, ®41);
|
| 327 | reg41 &= ~0x40;
|
| 328 | pci_write_config_byte(findev, 0x41, reg41);
|
| 329 | pci_dev_put(findev);
|
| 330 | }
|
| 331 | }
|
| 332 | |
| 333 | *
|
| 334 | * 1. clear bit 6 to enable DMA
|
| 335 | * 2. enable DMA modes with bits 0-1
|
| 336 | * 00 : legacy
|
| 337 | * 01 : udma2
|
| 338 | * 10 : udma2/udma4
|
| 339 | * 11 : udma2/udma4/udma5
|
| 340 |
|
| 341 | pci_read_config_byte(pdev, 0x5A, &btr);
|
| 342 | btr &= ~0x40;
|
| 343 | if (!(PCI_FUNC(pdev->devfn) & 1))
|
| 344 | btr |= 0x2;
|
| 345 | else
|
| 346 | btr |= (pdev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
|
| 347 | pci_write_config_byte(pdev, 0x5A, btr);
|
| 348 |
|
| 349 | return btr;
|
| 350 | }
|
| 351 |
|
| 352 | static void serverworks_fixup_ht1000(struct pci_dev *pdev)
|
| 353 | {
|
| 354 | u8 btr;
|
| 355 |
|
| 356 | pci_read_config_byte(pdev, 0x5A, &btr);
|
| 357 | btr &= ~0x40;
|
| 358 | btr |= 0x3;
|
| 359 | pci_write_config_byte(pdev, 0x5A, btr);
|
| 360 | }
|
| 361 |
|
| 362 | static int serverworks_fixup(struct pci_dev *pdev)
|
| 363 | {
|
| 364 | int rc = 0;
|
| 365 |
|
| 366 |
|
| 367 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
|
| 368 |
|
| 369 | switch (pdev->device) {
|
| 370 | case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
|
| 371 | rc = serverworks_fixup_osb4(pdev);
|
| 372 | break;
|
| 373 | case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
|
| 374 | ata_pci_bmdma_clear_simplex(pdev);
|
| 375 | fallthrough;
|
| 376 | case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
|
| 377 | case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
|
| 378 | rc = serverworks_fixup_csb(pdev);
|
| 379 | break;
|
| 380 | case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
|
| 381 | serverworks_fixup_ht1000(pdev);
|
| 382 | break;
|
| 383 | }
|
| 384 |
|
| 385 | return rc;
|
| 386 | }
|
| 387 |
|
| 388 | static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
| 389 | {
|
| 390 | static const struct ata_port_info info[4] = {
|
| 391 | {
|
| 392 | .flags = ATA_FLAG_SLAVE_POSS,
|
| 393 | .pio_mask = ATA_PIO4,
|
| 394 | .mwdma_mask = ATA_MWDMA2,
|
| 395 | .udma_mask = ATA_UDMA2,
|
| 396 | .port_ops = &serverworks_osb4_port_ops
|
| 397 | }, {
|
| 398 | .flags = ATA_FLAG_SLAVE_POSS,
|
| 399 | .pio_mask = ATA_PIO4,
|
| 400 | .mwdma_mask = ATA_MWDMA2,
|
| 401 |
|
| 402 | .port_ops = &serverworks_osb4_port_ops
|
| 403 | }, {
|
| 404 | .flags = ATA_FLAG_SLAVE_POSS,
|
| 405 | .pio_mask = ATA_PIO4,
|
| 406 | .mwdma_mask = ATA_MWDMA2,
|
| 407 | .udma_mask = ATA_UDMA4,
|
| 408 | .port_ops = &serverworks_csb_port_ops
|
| 409 | }, {
|
| 410 | .flags = ATA_FLAG_SLAVE_POSS,
|
| 411 | .pio_mask = ATA_PIO4,
|
| 412 | .mwdma_mask = ATA_MWDMA2,
|
| 413 | .udma_mask = ATA_UDMA5,
|
| 414 | .port_ops = &serverworks_csb_port_ops
|
| 415 | }
|
| 416 | };
|
| 417 | const struct ata_port_info *ppi[] = { &info[id->driver_data], NULL };
|
| 418 | const struct scsi_host_template *sht = &serverworks_csb_sht;
|
| 419 | int rc;
|
| 420 |
|
| 421 | rc = pcim_enable_device(pdev);
|
| 422 | if (rc)
|
| 423 | return rc;
|
| 424 |
|
| 425 | rc = serverworks_fixup(pdev);
|
| 426 |
|
| 427 |
|
| 428 | if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
|
| 429 |
|
| 430 | if (rc < 0)
|
| 431 | ppi[0] = &info[1];
|
| 432 | sht = &serverworks_osb4_sht;
|
| 433 | }
|
| 434 |
|
| 435 | else if ((pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
|
| 436 | (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
|
| 437 | (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
|
| 438 |
|
| 439 | |
| 440 | select the right info block
|
| 441 | if (rc == 3)
|
| 442 | ppi[0] = &info[3];
|
| 443 |
|
| 444 |
|
| 445 | if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)
|
| 446 | ppi[1] = &ata_dummy_port_info;
|
| 447 | }
|
| 448 |
|
| 449 | return ata_pci_bmdma_init_one(pdev, ppi, sht, NULL, 0);
|
| 450 | }
|
| 451 |
|
| 452 | #ifdef CONFIG_PM_SLEEP
|
| 453 | static int serverworks_reinit_one(struct pci_dev *pdev)
|
| 454 | {
|
| 455 | struct ata_host *host = pci_get_drvdata(pdev);
|
| 456 | int rc;
|
| 457 |
|
| 458 | rc = ata_pci_device_do_resume(pdev);
|
| 459 | if (rc)
|
| 460 | return rc;
|
| 461 |
|
| 462 | (void)serverworks_fixup(pdev);
|
| 463 |
|
| 464 | ata_host_resume(host);
|
| 465 | return 0;
|
| 466 | }
|
| 467 | #endif
|
| 468 |
|
| 469 | static const struct pci_device_id serverworks[] = {
|
| 470 | {
|
| 471 | PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE),
|
| 472 | .driver_data = 0,
|
| 473 | }, {
|
| 474 | PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE),
|
| 475 | .driver_data = 2,
|
| 476 | }, {
|
| 477 | PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE),
|
| 478 | .driver_data = 2,
|
| 479 | }, {
|
| 480 | PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2),
|
| 481 | .driver_data = 2,
|
| 482 | }, {
|
| 483 | PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE),
|
| 484 | .driver_data = 2
|
| 485 | },
|
| 486 | { }
|
| 487 | };
|
| 488 |
|
| 489 | static struct pci_driver serverworks_pci_driver = {
|
| 490 | .name = DRV_NAME,
|
| 491 | .id_table = serverworks,
|
| 492 | .probe = serverworks_init_one,
|
| 493 | .remove = ata_pci_remove_one,
|
| 494 | #ifdef CONFIG_PM_SLEEP
|
| 495 | .suspend = ata_pci_device_suspend,
|
| 496 | .resume = serverworks_reinit_one,
|
| 497 | #endif
|
| 498 | };
|
| 499 |
|
| 500 | module_pci_driver(serverworks_pci_driver);
|
| 501 |
|
| 502 | MODULE_AUTHOR("Alan Cox");
|
| 503 | MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6");
|
| 504 | MODULE_LICENSE("GPL");
|
| 505 | MODULE_DEVICE_TABLE(pci, serverworks);
|
| 506 | MODULE_VERSION(DRV_VERSION);
|