^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 1996-2001 Linus Torvalds & author (see below)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Version 0.03 Cleaned auto-tune, added probe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Version 0.04 Added second channel tuning
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Version 0.05 Enhanced tuning ; added qd6500 support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Version 0.06 Added dos driver's list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Version 0.07 Second channel bug fix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * QDI QD6500/QD6580 EIDE controller fast support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * To activate controller support, use "ide0=qd65xx"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * Samuel Thibault <samuel.thibault@ens-lyon.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/blkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/ide.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define DRV_NAME "qd65xx"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include "qd65xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * -- qd6500 is a single IDE interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * -- qd6580 is a dual IDE interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * More research on qd6580 being done by willmore@cig.mot.com (David)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * More Information given by Petr Soucek (petr@ryston.cz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * http://www.ryston.cz/petr/vlb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * base: Timer1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * base+0x01: Config (R/O)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * bit 3: qd6500: 1 = disabled, 0 = enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * qd6580: 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * upper nibble:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * qd6500: 1100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * qd6580: either 1010 or 0101
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * base+0x02: Timer2 (qd6580 only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * base+0x03: Control (qd6580 only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * bits 0-3 must always be set 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * 0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * channel 1 for hdc & hdd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * bit 1 : 1 = only disks on primary port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * 0 = disks & ATAPI devices on primary port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * bit 2-4 : always 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * bit 5 : status, but of what ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * bit 6 : always set 1 by dos driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * bit 7 : set 1 for non-ATAPI devices on primary port
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * (maybe read-ahead and post-write buffer ?)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * qd65xx_select:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * This routine is invoked to prepare for access to a given drive.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static void qd65xx_dev_select(ide_drive_t *drive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) (QD_TIMREG(drive) & 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (timings[index] != QD_TIMING(drive))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * qd6500_compute_timing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * computes the timing value where
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * lower nibble represents active time, in count of VLB clocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * upper nibble represents recovery time, in count of VLB clocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int clk = ide_vlb_clk ? ide_vlb_clk : 50;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) u8 act_cyc, rec_cyc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (clk <= 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) act_cyc = 9 - IDE_IN(active_time * clk / 1000 + 1, 2, 9);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) act_cyc = 8 - IDE_IN(active_time * clk / 1000 + 1, 1, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return (rec_cyc << 4) | 0x08 | act_cyc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * qd6580_compute_timing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * idem for qd6580
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static u8 qd6580_compute_timing (int active_time, int recovery_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int clk = ide_vlb_clk ? ide_vlb_clk : 50;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) u8 act_cyc, rec_cyc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) act_cyc = 17 - IDE_IN(active_time * clk / 1000 + 1, 2, 17);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return (rec_cyc << 4) | act_cyc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * qd_find_disk_type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * tries to find timing from dos driver's table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static int qd_find_disk_type (ide_drive_t *drive,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int *active_time, int *recovery_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) struct qd65xx_timing_s *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) char *m = (char *)&drive->id[ATA_ID_PROD];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) char model[ATA_ID_PROD_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (*m == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) strncpy(model, m, ATA_ID_PROD_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) for (p = qd65xx_timing ; p->offset != -1 ; p++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (!strncmp(p->model, model+p->offset, 4)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) printk(KERN_DEBUG "%s: listed !\n", drive->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) *active_time = p->active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) *recovery_time = p->recovery;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * qd_set_timing:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * records the timing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static void qd_set_timing (ide_drive_t *drive, u8 timing)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) unsigned long data = (unsigned long)ide_get_drivedata(drive);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) data &= 0xff00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) data |= timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) ide_set_drivedata(drive, (void *)data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static void qd6500_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) u16 *id = drive->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) int active_time = 175;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) int recovery_time = 415; /* worst case values from the dos driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* FIXME: use drive->pio_mode value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) id[ATA_ID_EIDE_PIO] >= 240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) id[ATA_ID_OLD_PIO_MODES] & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) active_time = 110;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) qd_set_timing(drive, qd6500_compute_timing(drive->hwif,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) active_time, recovery_time));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static void qd6580_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) const u8 pio = drive->pio_mode - XFER_PIO_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) unsigned int cycle_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) int active_time = 175;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) int recovery_time = 415; /* worst case values from the dos driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) u8 base = (hwif->config_data & 0xff00) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) cycle_time = ide_pio_cycle_time(drive, pio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) switch (pio) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) case 0: break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (cycle_time >= 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) active_time = 86;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) recovery_time = cycle_time - 102;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (cycle_time >= 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) active_time = 70;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) recovery_time = cycle_time - 61;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (cycle_time >= 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) active_time = 110;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) recovery_time = cycle_time - 120;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) active_time = t->active;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) recovery_time = cycle_time - active_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (!hwif->channel && drive->media != ide_disk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) outb(0x5f, QD_CONTROL_PORT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) "and post-write buffer on %s.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) drive->name, hwif->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * qd_testreg
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * tests if the given port is a register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static int __init qd_testreg(int port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) u8 savereg, readreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) savereg = inb_p(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) outb_p(QD_TESTVAL, port); /* safe value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) readreg = inb_p(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) outb(savereg, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (savereg == QD_TESTVAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) printk(KERN_ERR "Assuming qd65xx is not present.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return (readreg != QD_TESTVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static void __init qd6500_init_dev(ide_drive_t *drive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) ide_hwif_t *hwif = drive->hwif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) u8 base = (hwif->config_data & 0xff00) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) u8 config = QD_CONFIG(hwif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) ide_set_drivedata(drive, (void *)QD6500_DEF_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static void __init qd6580_init_dev(ide_drive_t *drive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) ide_hwif_t *hwif = drive->hwif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) unsigned long t1, t2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) u8 base = (hwif->config_data & 0xff00) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) u8 config = QD_CONFIG(hwif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (hwif->host_flags & IDE_HFLAG_SINGLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) t1 = QD6580_DEF_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) t2 = QD6580_DEF_DATA2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) static const struct ide_tp_ops qd65xx_tp_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .exec_command = ide_exec_command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .read_status = ide_read_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .read_altstatus = ide_read_altstatus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .write_devctl = ide_write_devctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .dev_select = qd65xx_dev_select,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .tf_load = ide_tf_load,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .tf_read = ide_tf_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .input_data = ide_input_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) .output_data = ide_output_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) static const struct ide_port_ops qd6500_port_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) .init_dev = qd6500_init_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) .set_pio_mode = qd6500_set_pio_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) static const struct ide_port_ops qd6580_port_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) .init_dev = qd6580_init_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) .set_pio_mode = qd6580_set_pio_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static const struct ide_port_info qd65xx_port_info __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) .tp_ops = &qd65xx_tp_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) .chipset = ide_qd65xx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) .host_flags = IDE_HFLAG_IO_32BIT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) IDE_HFLAG_NO_DMA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) .pio_mask = ATA_PIO4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) * qd_probe:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) * looks at the specified baseport, and if qd found, registers & initialises it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) * return 1 if another qd may be probed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) static int __init qd_probe(int base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) u8 config, unit, control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) struct ide_port_info d = qd65xx_port_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) config = inb(QD_CONFIG_PORT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) unit = ! (config & QD_CONFIG_IDE_BASEPORT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (unit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) d.host_flags |= IDE_HFLAG_QD_2ND_PORT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) switch (config & 0xf0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) case QD_CONFIG_QD6500:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (qd_testreg(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return -ENODEV; /* bad register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (config & QD_CONFIG_DISABLED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) printk(KERN_WARNING "qd6500 is disabled !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) printk(KERN_NOTICE "qd6500 at %#x\n", base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) config, QD_ID3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) d.port_ops = &qd6500_port_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) d.host_flags |= IDE_HFLAG_SINGLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) case QD_CONFIG_QD6580_A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) case QD_CONFIG_QD6580_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (qd_testreg(base) || qd_testreg(base + 0x02))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return -ENODEV; /* bad registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) control = inb(QD_CONTROL_PORT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) printk(KERN_NOTICE "qd6580 at %#x\n", base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) config, control, QD_ID3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) outb(QD_DEF_CONTR, QD_CONTROL_PORT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) d.port_ops = &qd6580_port_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (control & QD_CONTR_SEC_DISABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) d.host_flags |= IDE_HFLAG_SINGLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) printk(KERN_INFO "qd6580: %s IDE board\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) rc = ide_legacy_device_add(&d, (base << 8) | config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (d.host_flags & IDE_HFLAG_SINGLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return (rc == 0) ? 1 : rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static bool probe_qd65xx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) module_param_named(probe, probe_qd65xx, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static int __init qd65xx_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) int rc1, rc2 = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if (probe_qd65xx == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) rc1 = qd_probe(0x30);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (rc1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) rc2 = qd_probe(0xb0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (rc1 < 0 && rc2 < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) module_init(qd65xx_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) MODULE_AUTHOR("Samuel Thibault");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) MODULE_LICENSE("GPL");