diff --exclude=CVS --exclude='.#*' --exclude='obj.*' --exclude='makeBuild*' -uNr src.orig/sys/dev/sdmmc/sdhc.c src/sys/dev/sdmmc/sdhc.c
--- src.orig/sys/dev/sdmmc/sdhc.c	2011-06-29 15:21:16.000000000 +0900
+++ src/sys/dev/sdmmc/sdhc.c	2012-02-01 12:16:10.000000000 +0900
@@ -64,6 +64,7 @@
 
 	struct kmutex host_mtx;
 
+	int specver;			/* sdhc spec version */
 	u_int clkbase;			/* base clock frequency in KHz */
 	int maxblklen;			/* maximum block length */
 	uint32_t ocr;			/* OCR value from capabilities */
@@ -78,6 +79,7 @@
 	uint32_t flags;			/* flags for this host */
 #define SHF_USE_DMA		0x0001
 #define SHF_USE_4BIT_MODE	0x0002
+#define SHF_USE_ADMA		0x0004
 };
 
 #define HDEVNAME(hp)	(device_xname((hp)->sc->sc_dev))
@@ -165,26 +167,29 @@
 {
 	struct sdmmcbus_attach_args saa;
 	struct sdhc_host *hp;
-	uint32_t caps;
-#ifdef SDHC_DEBUG
+	uint32_t caps[2];
 	uint16_t sdhcver;
 
 	sdhcver = bus_space_read_2(iot, ioh, SDHC_HOST_CTL_VERSION);
 	aprint_normal_dev(sc->sc_dev, "SD Host Specification/Vendor Version ");
 	switch (SDHC_SPEC_VERSION(sdhcver)) {
-	case 0x00:
-		aprint_normal("1.0/%u\n", SDHC_VENDOR_VERSION(sdhcver));
+	case SDHC_SPEC_VERS_100:
+		aprint_normal("1.0/0x%x\n", SDHC_VENDOR_VERSION(sdhcver));
+		break;
+
+	case SDHC_SPEC_VERS_200:
+		aprint_normal("2.0/0x%x\n", SDHC_VENDOR_VERSION(sdhcver));
 		break;
 
-	case 0x01:
-		aprint_normal("2.0/%u\n", SDHC_VENDOR_VERSION(sdhcver));
+	case SDHC_SPEC_VERS_300:
+		aprint_normal("3.0/0x%x\n", SDHC_VENDOR_VERSION(sdhcver));
 		break;
 
 	default:
-		aprint_normal(">2.0/%u\n", SDHC_VENDOR_VERSION(sdhcver));
+		aprint_normal("unknown(0x%0x)/0x%x\n",
+		    SDHC_SPEC_VERSION(sdhcver), SDHC_VENDOR_VERSION(sdhcver));
 		break;
 	}
-#endif
 
 	/* Allocate one more host structure. */
 	hp = malloc(sizeof(struct sdhc_host), M_DEVBUF, M_WAITOK|M_ZERO);
@@ -200,6 +205,7 @@
 	hp->iot = iot;
 	hp->ioh = ioh;
 	hp->dmat = sc->sc_dmat;
+	hp->specver = SDHC_SPEC_VERSION(sdhcver);
 
 	mutex_init(&hp->host_mtx, MUTEX_DEFAULT, IPL_SDMMC);
 	mutex_init(&hp->intr_mtx, MUTEX_DEFAULT, IPL_SDMMC);
@@ -212,28 +218,36 @@
 
 	/* Determine host capabilities. */
 	mutex_enter(&hp->host_mtx);
-	caps = HREAD4(hp, SDHC_CAPABILITIES);
+	caps[0] = HREAD4(hp, SDHC_CAPABILITIES);
+	caps[1] = (hp->specver >= SDHC_SPEC_VERS_300) ?
+	    HREAD4(hp, SDHC_CAPABILITIES_1) : 0;
 	mutex_exit(&hp->host_mtx);
 
 #if notyet
 	/* Use DMA if the host system and the controller support it. */
 	if (ISSET(sc->sc_flags, SDHC_FLAG_FORCE_DMA)
 	 || ((ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA)
-	   && ISSET(caps, SDHC_DMA_SUPPORT)))) {
+	   && ISSET(caps[0], SDHC_DMA_SUPPORT))))
 		SET(hp->flags, SHF_USE_DMA);
-		aprint_normal_dev(sc->sc_dev, "using DMA transfer\n");
-	}
+	if (ISSET(sc->sc_flags, SDHC_FLAG_BROKEN_DMA))
+		CLR(hp->flags, SHF_USE_DMA);
+
+	if ((hp->specver >= SDHC_SPEC_VERS_200)
+	 && ISSET(caps[0], SDHC_ADMA2_SUPPORT))
+		SET(hp->flags, SHF_USE_ADMA);
+	if (ISSET(sc->sc_flags, SDHC_FLAG_BROKEN_ADMA))
+		CLR(hp->flags, SHF_USE_ADMA);
 #endif
 
 	/*
 	 * Determine the base clock frequency. (2.2.24)
 	 */
-	if (SDHC_BASE_FREQ_KHZ(caps) != 0)
-		hp->clkbase = SDHC_BASE_FREQ_KHZ(caps);
+	hp->clkbase = SDHC_BASE_FREQ_KHZ(caps[0]);
 	if (hp->clkbase == 0) {
 		if (sc->sc_clkbase == 0) {
 			/* The attachment driver must tell us. */
-			aprint_error_dev(sc->sc_dev,"unknown base clock frequency\n");
+			aprint_error_dev(sc->sc_dev,
+			    "unknown base clock frequency\n");
 			goto err;
 		}
 		hp->clkbase = sc->sc_clkbase;
@@ -257,18 +271,18 @@
 	/*
 	 * Determine SD bus voltage levels supported by the controller.
 	 */
-	if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V))
+	if (ISSET(caps[0], SDHC_VOLTAGE_SUPP_1_8V))
 		SET(hp->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
-	if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V))
+	if (ISSET(caps[0], SDHC_VOLTAGE_SUPP_3_0V))
 		SET(hp->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
-	if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V))
+	if (ISSET(caps[0], SDHC_VOLTAGE_SUPP_3_3V))
 		SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
 
 	/*
 	 * Determine the maximum block length supported by the host
 	 * controller. (2.2.24)
 	 */
-	switch((caps >> SDHC_MAX_BLK_LEN_SHIFT) & SDHC_MAX_BLK_LEN_MASK) {
+	switch((caps[0] >> SDHC_MAX_BLK_LEN_SHIFT) & SDHC_MAX_BLK_LEN_MASK) {
 	case SDHC_MAX_BLK_LEN_512:
 		hp->maxblklen = 512;
 		break;
@@ -293,6 +307,13 @@
 	    device_xname(sc->sc_dev), hp->maxblklen,
 	    hp->maxblklen > 1 ? "s" : ""));
 
+#if notyet
+	if (ISSET(hp->flags, SHF_USE_ADMA))
+		aprint_normal_dev(sc->sc_dev, "using ADMA transfer\n");
+	else if (ISSET(hp->flags, SHF_USE_DMA))
+		aprint_normal_dev(sc->sc_dev, "using DMA transfer\n");
+#endif
+
 	/*
 	 * Attach the generic SD/MMC bus driver.  (The bus driver must
 	 * not invoke any chipset functions before it is attached.)
@@ -308,8 +329,10 @@
 		saa.saa_clkmin /= 16;
 	saa.saa_caps = SMC_CAPS_4BIT_MODE|SMC_CAPS_AUTO_STOP;
 #if notyet
-	if (ISSET(hp->flags, SHF_USE_DMA))
-		saa.saa_caps |= SMC_CAPS_DMA;
+	if (ISSET(hp->flags, SHF_USE_DMA|SHF_USE_ADMA))
+		SET(saa.saa_caps, SMC_CAPS_DMA);
+	if (ISSET(hp->flags, SHF_USE_ADMA))
+		SET(saa.saa_caps, SMC_CAPS_MULTI_SEG_DMA);
 #endif
 	hp->sdmmc = config_found(sc->sc_dev, &saa, NULL);
 
@@ -395,6 +418,48 @@
 	return true;
 }
 
+uint8_t
+sdhc_read_1(struct sdhc_host *hp, int reg)
+{
+
+	return HREAD1(hp, reg);
+}
+
+uint16_t
+sdhc_read_2(struct sdhc_host *hp, int reg)
+{
+
+	return HREAD2(hp, reg);
+}
+
+uint32_t
+sdhc_read_4(struct sdhc_host *hp, int reg)
+{
+
+	return HREAD4(hp, reg);
+}
+
+void
+sdhc_write_1(struct sdhc_host *hp, int reg, uint8_t val)
+{
+
+	HWRITE1(hp, reg, val);
+}
+
+void
+sdhc_write_2(struct sdhc_host *hp, int reg, uint16_t val)
+{
+
+	HWRITE2(hp, reg, val);
+}
+
+void
+sdhc_write_4(struct sdhc_host *hp, int reg, uint32_t val)
+{
+
+	HWRITE4(hp, reg, val);
+}
+
 /*
  * Reset the host controller.  Called during initialization, when
  * cards are removed, upon resume, and during error recovery.
@@ -609,9 +674,7 @@
 	int error = 0;
 #ifdef DIAGNOSTIC
 	int ispresent;
-#endif
 
-#ifdef DIAGNOSTIC
 	mutex_enter(&hp->host_mtx);
 	ispresent = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CMD_INHIBIT_MASK);
 	mutex_exit(&hp->host_mtx);
@@ -1282,6 +1345,8 @@
 	    HREAD2(hp, SDHC_EINTR_SIGNAL_EN));
 	printf("0x%02x CAPABILITIES:     %x\n", SDHC_CAPABILITIES,
 	    HREAD4(hp, SDHC_CAPABILITIES));
+	printf("0x%02x CAPABILITIES:     %x\n", SDHC_CAPABILITIES_1,
+	    HREAD4(hp, SDHC_CAPABILITIES_1));
 	printf("0x%02x MAX_CAPABILITIES: %x\n", SDHC_MAX_CAPABILITIES,
 	    HREAD4(hp, SDHC_MAX_CAPABILITIES));
 }
diff --exclude=CVS --exclude='.#*' --exclude='obj.*' --exclude='makeBuild*' -uNr src.orig/sys/dev/sdmmc/sdhcreg.h src/sys/dev/sdmmc/sdhcreg.h
--- src.orig/sys/dev/sdmmc/sdhcreg.h	2012-02-02 08:02:22.000000000 +0900
+++ src/sys/dev/sdmmc/sdhcreg.h	2012-02-02 08:02:31.000000000 +0900
@@ -72,6 +72,12 @@
 #define  SDHC_CMD_INHIBIT_CMD		(1<<0)
 #define  SDHC_CMD_INHIBIT_MASK		0x0003
 #define SDHC_HOST_CTL			0x28
+#define  _SDHC_8BIT_MODE		(1<<5)
+#define  SDHC_CTL_DMA_MASK		(3<<3)
+#define   SDHC_CTL_DMA_SDMA		(0<<3)
+#define   SDHC_CTL_DMA_ADMA1		(1<<3)
+#define   SDHC_CTL_DMA_ADMA2_32		(2<<3)
+#define   SDHC_CTL_DMA_ADMA2_64		(3<<3)
 #define  SDHC_HIGH_SPEED		(1<<2)
 #define  SDHC_8BIT_MODE			(1<<2)	/* ESDHC */
 #define  SDHC_4BIT_MODE			(1<<1)
@@ -136,11 +142,15 @@
 #define  SDHC_EINTR_SIGNAL_MASK		0x01ff	/* excluding vendor signals */
 #define SDHC_CMD12_ERROR_STATUS		0x3c
 #define SDHC_CAPABILITIES		0x40
+#define  SDHC_64BIT_SUPPORT		(1<<28)
 #define  SDHC_VOLTAGE_SUPP_1_8V		(1<<26)
 #define  SDHC_VOLTAGE_SUPP_3_0V		(1<<25)
 #define  SDHC_VOLTAGE_SUPP_3_3V		(1<<24)
 #define  SDHC_DMA_SUPPORT		(1<<22)
-#define  SDHC_HIGH_SPEED_SUPP		(1<<21)
+#define  SDHC_HIGH_SPEED_SUPPORT	(1<<21)
+#define  SDHC_ADMA1_SUPPORT		(1<<20)
+#define  SDHC_ADMA2_SUPPORT		(1<<19)
+#define  SDHC_8BIT_MODE_SUPPORT		(1<<18)
 #define  SDHC_MAX_BLK_LEN_512		0
 #define  SDHC_MAX_BLK_LEN_1024		1
 #define  SDHC_MAX_BLK_LEN_2048		2
@@ -149,9 +159,24 @@
 #define  SDHC_MAX_BLK_LEN_MASK		0x3
 #define  SDHC_BASE_FREQ_SHIFT		8
 #define  SDHC_BASE_FREQ_MASK		0x3f
+#define  SDHC_SPEC300_BASE_FREQ_MASK	0xff
 #define  SDHC_TIMEOUT_FREQ_UNIT		(1<<7)	/* 0=KHz, 1=MHz */
 #define  SDHC_TIMEOUT_FREQ_SHIFT	0
 #define  SDHC_TIMEOUT_FREQ_MASK		0x1f
+#define SDHC_CAPABILITIES_1		0x44
+#define  SDHC_SDR50_SUPP		(1U<<0)
+#define  SDHC_SDR104_SUPP		(1U<<1)
+#define  SDHC_DDR50_SUPP		(1U<<2)
+#define  SDHC_DRIVER_TYPE_A		(1U<<4)
+#define  SDHC_DRIVER_TYPE_C		(1U<<5)
+#define  SDHC_DRIVER_TYPE_D		(1U<<6)
+#define  SDHC_RET_TIMER_CNT_SHIFT	8
+#define  SDHC_RET_TIMER_CNT_MASK	0xf
+#define  SDHC_USE_SDR50_TUNING		(1U<<13)
+#define  SDHC_RET_MODE_SHIFT		14
+#define  SDHC_RET_MODE_MASK		0x3
+#define  SDHC_CLOCK_MUL_SHIFT		16
+#define  SDHC_CLOCK_MUL_MASK		0xff
 #define SDHC_MAX_CAPABILITIES		0x48
 #define	SDHC_HOST_VER			0xFC
 #define  SDHC_VVN_MASK			0x0f
@@ -167,9 +192,16 @@
 #define	SDHC_DMA_CTL			0x40c	/* eSDHC */
 #define	 SDHC_DMA_SNOOP			0x40
 
+/* SDHC_SPEC_VERS */
+#define  SDHC_SPEC_VERS_100		0x00
+#define  SDHC_SPEC_VERS_200		0x01
+#define  SDHC_SPEC_VERS_300		0x02
+
 /* SDHC_CAPABILITIES decoding */
 #define SDHC_BASE_FREQ_KHZ(cap)						\
 	((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_BASE_FREQ_MASK) * 1000)
+#define SDHC_SPEC300_BASE_FREQ_KHZ(cap)					\
+	((((cap) >> SDHC_BASE_FREQ_SHIFT) & SDHC_SPEC300_BASE_FREQ_MASK) * 1000)
 #define SDHC_TIMEOUT_FREQ(cap)						\
 	(((cap) >> SDHC_TIMEOUT_FREQ_SHIFT) & SDHC_TIMEOUT_FREQ_MASK)
 #define SDHC_TIMEOUT_FREQ_KHZ(cap)					\
@@ -177,6 +209,14 @@
 	    SDHC_TIMEOUT_FREQ(cap) * 1000:				\
 	    SDHC_TIMEOUT_FREQ(cap))
 
+/* SDHC_CAPABILITIES_1 decoding */
+#define SDHC_RET_TIMER_CNT(cap)						\
+	(((cap) >> SDHC_RET_TIMER_CNT_SHIFT) & SDHC_RET_TIMER_CNT_MASK)
+#define SDHC_RET_MODE(cap)						\
+	(((cap) >> SDHC_RET_MODE_SHIFT) & SDHC_RET_MODE_MASK)
+#define SDHC_CLOCK_MUL(cap)						\
+	(((cap) >> SDHC_CLOCK_MUL_SHIFT) & SDHC_CLOCK_MUL_MASK)
+
 /* SDHC_HOST_CTL_VERSION decoding */
 #define SDHC_SPEC_VERSION(hcv)						\
 	(((hcv) >> SDHC_SPEC_VERS_SHIFT) & SDHC_SPEC_VERS_MASK)
diff --exclude=CVS --exclude='.#*' --exclude='obj.*' --exclude='makeBuild*' -uNr src.orig/sys/dev/sdmmc/sdhcvar.h src/sys/dev/sdmmc/sdhcvar.h
--- src.orig/sys/dev/sdmmc/sdhcvar.h	2012-02-02 08:07:22.000000000 +0900
+++ src/sys/dev/sdmmc/sdhcvar.h	2012-02-02 08:06:43.000000000 +0900
@@ -35,14 +35,18 @@
 	bus_dma_tag_t		sc_dmat;
 
 	uint32_t		sc_flags;
-#define	SDHC_FLAG_USE_DMA	0x0001
-#define	SDHC_FLAG_FORCE_DMA	0x0002
-#define	SDHC_FLAG_NO_PWR0	0x0004	/* Freescale ESDHC */
-#define	SDHC_FLAG_HAVE_DVS	0x0008	/* Freescale ESDHC */
-#define	SDHC_FLAG_32BIT_ACCESS	0x0010	/* Freescale ESDHC */
-#define	SDHC_FLAG_ENHANCED	0x0020	/* Freescale ESDHC */
-#define	SDHC_FLAG_8BIT_MODE	0x0040	/* MMC 8bit mode is supported */
-#define	SDHC_FLAG_HAVE_CGM	0x0080	/* Netlogic XLP */
+#define	SDHC_FLAG_USE_DMA		0x0001
+#define	SDHC_FLAG_FORCE_DMA		0x0002
+#define	SDHC_FLAG_NO_PWR0		0x0004	/* Freescale ESDHC */
+#define	SDHC_FLAG_HAVE_DVS		0x0008	/* Freescale ESDHC */
+#define	SDHC_FLAG_32BIT_ACCESS		0x0010	/* Freescale ESDHC */
+#define	SDHC_FLAG_ENHANCED		0x0020	/* Freescale ESDHC */
+#define	SDHC_FLAG_8BIT_MODE		0x0040	/* MMC 8bit mode is supported */
+#define	SDHC_FLAG_HAVE_CGM		0x0080	/* Netlogic XLP */
+#define	SDHC_FLAG_BROKEN_DMA		0x0100
+#define	SDHC_FLAG_BROKEN_ADMA		0x0200
+#define	SDHC_FLAG_BROKEN_RO_DETECT	0x0400
+
 	uint32_t		sc_clkbase;
 };
 
@@ -55,4 +59,11 @@
 bool	sdhc_resume(device_t, const pmf_qual_t *);
 bool	sdhc_shutdown(device_t, int);
 
+uint8_t	sdhc_read_1(struct sdhc_host *, int reg);
+uint16_t sdhc_read_2(struct sdhc_host *, int reg);
+uint32_t sdhc_read_4(struct sdhc_host *, int reg);
+void	sdhc_write_1(struct sdhc_host *, int reg, uint8_t);
+void	sdhc_write_2(struct sdhc_host *, int reg, uint16_t);
+void	sdhc_write_4(struct sdhc_host *, int reg, uint32_t);
+
 #endif	/* _SDHCVAR_H_ */
--- src.orig/sys/dev/pci/sdhc_pci.c	2012-02-02 07:41:02.000000000 +0900
+++ src/sys/dev/pci/sdhc_pci.c	2012-02-02 07:40:03.000000000 +0900
@@ -20,6 +20,8 @@
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: sdhc_pci.c,v 1.5 2012/01/30 19:41:23 drochner Exp $");
 
+#include "opt_sdmmc.h"
+
 #include <sys/param.h>
 #include <sys/device.h>
 #include <sys/systm.h>
@@ -33,9 +35,11 @@
 #include <dev/sdmmc/sdhcvar.h>
 #include <dev/sdmmc/sdmmcvar.h>
 
-/* PCI base address registers */
-#define SDHC_PCI_BAR_START		PCI_MAPREG_START
-#define SDHC_PCI_BAR_END		PCI_MAPREG_END
+#ifdef SDHC_DEBUG
+#define	DPRINTF(s)	printf s
+#else
+#define	DPRINTF(s)	/**/
+#endif
 
 /* PCI interface classes */
 #define SDHC_PCI_INTERFACE_NO_DMA	0x00
@@ -50,9 +54,14 @@
 #define SDHC_PCI_NUM_SLOTS(info)	((((info) >> 4) & 0x7) + 1)
 #define SDHC_PCI_FIRST_BAR(info)	((info) & 0x7)
 
+struct sdhc_pci_quirk;
 struct sdhc_pci_softc {
 	struct sdhc_softc sc;
 	void *sc_ih;
+	pci_chipset_tag_t sc_pct;
+	pcitag_t sc_pt;
+	pcireg_t sc_id;
+	const struct sdhc_pci_quirk *sc_quirk;
 };
 
 static int sdhc_pci_match(device_t, cfdata_t, void *);
@@ -61,31 +70,64 @@
 CFATTACH_DECL_NEW(sdhc_pci, sizeof(struct sdhc_pci_softc),
     sdhc_pci_match, sdhc_pci_attach, NULL, NULL);
 
-#ifdef SDHC_DEBUG
-#define	DPRINTF(s)	printf s
-#else
-#define	DPRINTF(s)	/**/
-#endif
+static bool sdhc_pci_suspend(device_t, const pmf_qual_t *);
+static bool sdhc_pci_resume(device_t, const pmf_qual_t *);
+
+static void sdhc_pci_quirk_ti_hack(struct pci_attach_args *,
+    struct sdhc_pci_softc *);
+static void sdhc_pci_quirk_jmicron_hack(struct pci_attach_args *,
+    struct sdhc_pci_softc *);
+static int sdhc_pci_quirk_jmicron_host_add(struct pci_attach_args *,
+    struct sdhc_pci_softc *);
+static void sdhc_pci_quirk_jmicron_host_remove(struct sdhc_pci_softc *);
+static bool shdc_pci_quirk_jmicron_suspend(struct sdhc_pci_softc *,
+    const pmf_qual_t *);
+static bool shdc_pci_quirk_jmicron_resume(struct sdhc_pci_softc *,
+    const pmf_qual_t *);
+
+struct sdhc_pci_quirk {
+	uint32_t flags;	/* sdhc_softc.sc_flags */
+
+	int	(*match)(struct pci_attach_args *);
+	void	(*hack)(struct pci_attach_args *, struct sdhc_pci_softc *);
+	int	(*host_add)(struct pci_attach_args *, struct sdhc_pci_softc *);
+	void	(*host_remove)(struct sdhc_pci_softc *);
+	bool	(*suspend)(struct sdhc_pci_softc *, const pmf_qual_t *);
+	bool	(*resume)(struct sdhc_pci_softc *, const pmf_qual_t *);
+};
+
+static struct sdhc_pci_quirk ti_quirk = {
+	.hack		= sdhc_pci_quirk_ti_hack,
+};
+
+static struct sdhc_pci_quirk ene_quirk = {
+	.flags		= SDHC_FLAG_NO_PWR0,
+};
 
-static const struct sdhc_pci_quirk {
+static struct sdhc_pci_quirk jmicron_quirk = {
+	.hack		= sdhc_pci_quirk_jmicron_hack,
+	.host_add	= sdhc_pci_quirk_jmicron_host_add,
+	.host_remove	= sdhc_pci_quirk_jmicron_host_remove,
+	.suspend	= shdc_pci_quirk_jmicron_suspend,
+	.resume		= shdc_pci_quirk_jmicron_resume,
+};
+
+static const struct sdhc_pci_quirks {
 	pci_vendor_id_t		vendor;
 	pci_product_id_t	product;
 	pci_vendor_id_t		subvendor;
 	pci_product_id_t	subproduct;
 	u_int			function;
 
-	uint32_t		flags;
-#define	SDHC_PCI_QUIRK_FORCE_DMA	(1U << 0)
-#define	SDHC_PCI_QUIRK_TI_HACK		(1U << 1)
-#define	SDHC_PCI_QUIRK_NO_PWR0		(1U << 2)
-} sdhc_pci_quirk_table[] = {
+	const struct sdhc_pci_quirk *quirk;
+} sdhc_pci_quirks_table[] = {
 	{
 		PCI_VENDOR_TI,
 		PCI_PRODUCT_TI_PCI72111SD,
 		0xffff,
 		0xffff,
 		4,
-		SDHC_PCI_QUIRK_TI_HACK
+		&ti_quirk,
 	},
 
 	{
@@ -94,7 +136,7 @@
 		0xffff,
 		0xffff,
 		3,
-		SDHC_PCI_QUIRK_TI_HACK
+		&ti_quirk,
 	},
 
 	{
@@ -103,23 +145,57 @@
 		0xffff,
 		0xffff,
 		0,
-		SDHC_PCI_QUIRK_NO_PWR0
+		&ene_quirk,
+	},
+
+	{
+		PCI_VENDOR_JMICRON,
+		PCI_PRODUCT_JMICRON_JMB38X_SD,
+		0xffff,
+		0xffff,
+		~0,
+		&jmicron_quirk,
 	},
-};
 
-static void sdhc_pci_quirk_ti_hack(struct pci_attach_args *);
+	{
+		PCI_VENDOR_JMICRON,
+		PCI_PRODUCT_JMICRON_JMB38X_MMC,
+		0xffff,
+		0xffff,
+		~0,
+		&jmicron_quirk,
+	},
 
-static uint32_t
-sdhc_pci_lookup_quirk_flags(struct pci_attach_args *pa)
+	{
+		PCI_VENDOR_JMICRON,
+		PCI_PRODUCT_JMICRON_JMB388_SD,
+		0xffff,
+		0xffff,
+		~0,
+		&jmicron_quirk,
+	},
+
+	{
+		PCI_VENDOR_JMICRON,
+		PCI_PRODUCT_JMICRON_JMB388_MMC,
+		0xffff,
+		0xffff,
+		~0,
+		&jmicron_quirk,
+	},
+};
+
+static const struct sdhc_pci_quirk *
+sdhc_pci_lookup_quirk(struct pci_attach_args *pa)
 {
-	const struct sdhc_pci_quirk *q;
+	const struct sdhc_pci_quirks *q;
 	pcireg_t id;
 	pci_vendor_id_t vendor;
 	pci_product_id_t product;
 	int i;
 
-	for (i = 0; i < __arraycount(sdhc_pci_quirk_table); i++) {
-		q = &sdhc_pci_quirk_table[i];
+	for (i = 0; i < __arraycount(sdhc_pci_quirks_table); i++) {
+		q = &sdhc_pci_quirks_table[i];
 
 		if ((PCI_VENDOR(pa->pa_id) == q->vendor)
 		 && (PCI_PRODUCT(pa->pa_id) == q->product)) {
@@ -129,7 +205,7 @@
 
 			if ((q->subvendor == 0xffff)
 			 && (q->subproduct == 0xffff))
-				return q->flags;
+				return q->quirk;
 
 			id = pci_conf_read(pa->pa_pc, pa->pa_tag,
 			    PCI_SUBSYS_ID_REG);
@@ -140,30 +216,39 @@
 			 && (q->subproduct != 0xffff)) {
 				if ((vendor == q->subvendor)
 				 && (product == q->subproduct))
-					return q->flags;
+					return q->quirk;
 			} else if (q->subvendor != 0xffff) {
 				if (product == q->subproduct)
-					return q->flags;
+					return q->quirk;
 			} else {
 				if (vendor == q->subvendor)
-					return q->flags;
+					return q->quirk;
 			}
 		}
 	}
 
-	return 0;
+	return NULL;
 }
 
 static int
 sdhc_pci_match(device_t parent, cfdata_t cf, void *aux)
 {
 	struct pci_attach_args *pa = aux;
+	const struct sdhc_pci_quirk *quirk;
+	int error;
 
-	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SYSTEM &&
-	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SYSTEM_SDHC)
-		return 1;
+	if (PCI_CLASS(pa->pa_class) != PCI_CLASS_SYSTEM ||
+	    PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_SYSTEM_SDHC)
+		return 0;
+
+	quirk = sdhc_pci_lookup_quirk(pa);
+	if (quirk && quirk->match) {
+		error = (*quirk->match)(pa);
+		if (error)
+			return 0;
+	}
 
-	return 0;
+	return 1;
 }
 
 static void
@@ -177,28 +262,35 @@
 	pcireg_t csr;
 	pcireg_t slotinfo;
 	char const *intrstr;
-	int nslots;
+	int nslots, n;
 	int reg;
-	int cnt;
+	int cnt, i;
 	bus_space_tag_t iot;
 	bus_space_handle_t ioh;
 	bus_size_t size;
-	uint32_t flags;
+	pcireg_t memtype;
+	struct {
+		pcireg_t reg;
+		pcireg_t type;
+	} bar[(PCI_MAPREG_END - PCI_MAPREG_START) / sizeof(uint32_t)];
+	int maxbar;
 
 	sc->sc.sc_dev = self;
 	sc->sc.sc_dmat = pa->pa_dmat;
 	sc->sc.sc_host = NULL;
+	sc->sc_pct = pa->pa_pc;
+	sc->sc_pt = pa->pa_tag;
+	sc->sc_id = pa->pa_id;
 
 	pci_aprint_devinfo(pa, NULL);
 
 	/* Some controllers needs special treatment. */
-	flags = sdhc_pci_lookup_quirk_flags(pa);
-	if (ISSET(flags, SDHC_PCI_QUIRK_TI_HACK))
-		sdhc_pci_quirk_ti_hack(pa);
-	if (ISSET(flags, SDHC_PCI_QUIRK_FORCE_DMA))
-		SET(sc->sc.sc_flags, SDHC_FLAG_FORCE_DMA);
-	if (ISSET(flags, SDHC_PCI_QUIRK_NO_PWR0))
-		SET(sc->sc.sc_flags, SDHC_FLAG_NO_PWR0);
+	sc->sc_quirk = sdhc_pci_lookup_quirk(pa);
+	if (sc->sc_quirk) {
+		SET(sc->sc.sc_flags, sc->sc_quirk->flags);
+		if (sc->sc_quirk->hack)
+			(*sc->sc_quirk->hack)(pa, sc);
+	}
 
 	/*
 	 * Map and attach all hosts supported by the host controller.
@@ -237,30 +329,50 @@
 	if ((PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA))
 		SET(sc->sc.sc_flags, SDHC_FLAG_USE_DMA);
 
-	/* XXX: handle 64-bit BARs */
+	for (reg = PCI_MAPREG_START, i = 0, n = nslots;
+	     reg < PCI_MAPREG_END && n > 0; i++, --n) {
+		memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, reg);
+		bar[i].reg = reg;
+		bar[i].type = memtype;
+		if (memtype == (PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_64BIT))
+			reg += sizeof(uint64_t);
+		else
+			reg += sizeof(uint32_t);
+	}
+	maxbar = i;
+#ifdef SDHC_DEBUG
+	for (i = 0; i < maxbar; i++) {
+		printf("%s: bar[%d]: reg=0x%x, type=%s\n",
+		    device_xname(self), i, bar[i].reg,
+		    ((PCI_MAPREG_TYPE(bar[i].type) == PCI_MAPREG_TYPE_IO) ? "IO"
+		      : (bar[i].type ==
+		        (PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_64BIT)) ?
+		           "MEM64" : "MEM32"));
+	}
+#endif
+
 	cnt = 0;
-	for (reg = SDHC_PCI_BAR_START + SDHC_PCI_FIRST_BAR(slotinfo) *
-		 sizeof(uint32_t);
-	     reg < SDHC_PCI_BAR_END && nslots > 0;
-	     reg += sizeof(uint32_t), nslots--) {
-		if (pci_mapreg_map(pa, reg, PCI_MAPREG_TYPE_MEM, 0,
-		    &iot, &ioh, NULL, &size)) {
+	for (i = SDHC_PCI_FIRST_BAR(slotinfo);
+	     i < maxbar && nslots > 0; i++, --nslots) {
+		if (PCI_MAPREG_TYPE(bar[i].type) != PCI_MAPREG_TYPE_MEM)
+			continue;
+		if (pci_mapreg_map(pa, bar[i].reg, bar[i].type, 0, &iot, &ioh,
+		    NULL, &size))
 			continue;
-		}
 
 		cnt++;
-		if (sdhc_host_found(&sc->sc, iot, ioh, size) != 0) {
-			/* XXX: sc->sc_host leak */
+		if (sdhc_host_found(&sc->sc, iot, ioh, size))
 			aprint_error_dev(self,
-			    "couldn't initialize host (0x%x)\n", reg);
-		}
+			    "couldn't initialize host (0x%x)\n", bar[i].reg);
+		else if (sc->sc_quirk && sc->sc_quirk->host_add)
+			(*sc->sc_quirk->host_add)(pa, sc);
 	}
 	if (cnt == 0) {
 		aprint_error_dev(self, "couldn't map register\n");
 		goto err;
 	}
 
-	if (!pmf_device_register1(self, sdhc_suspend, sdhc_resume,
+	if (!pmf_device_register1(self, sdhc_pci_suspend, sdhc_pci_resume,
 	    sdhc_shutdown)) {
 		aprint_error_dev(self, "couldn't establish powerhook\n");
 	}
@@ -272,12 +384,37 @@
 		free(sc->sc.sc_host, M_DEVBUF);
 }
 
-/* TI specific register */
+static bool
+sdhc_pci_suspend(device_t self, const pmf_qual_t *qual)
+{
+	struct sdhc_pci_softc *sc = device_private(self);
+
+	if (sc->sc_quirk && sc->sc_quirk->suspend)
+		(*sc->sc_quirk->suspend)(sc, qual);
+
+	return sdhc_suspend(self, qual);
+}
+
+static bool
+sdhc_pci_resume(device_t self, const pmf_qual_t *qual)
+{
+	struct sdhc_pci_softc *sc = device_private(self);
+
+	if (!sdhc_resume(self, qual))
+		return false;
+
+	if (sc->sc_quirk && sc->sc_quirk->resume)
+		(*sc->sc_quirk->resume)(sc, qual);
+
+	return true;
+}
+
+/* TI specific */
 #define SDHC_PCI_GENERAL_CTL		0x4c
 #define  MMC_SD_DIS			0x02
 
 static void
-sdhc_pci_quirk_ti_hack(struct pci_attach_args *pa)
+sdhc_pci_quirk_ti_hack(struct pci_attach_args *pa, struct sdhc_pci_softc *sc)
 {
 	pci_chipset_tag_t pc = pa->pa_pc;
 	pcitag_t tag;
@@ -302,6 +439,160 @@
 	 * SD host takes over.
 	 */
 	reg = pci_conf_read(pc, tag, SDHC_PCI_GENERAL_CTL);
-	reg |= MMC_SD_DIS;
+	SET(reg, MMC_SD_DIS);
 	pci_conf_write(pc, tag, SDHC_PCI_GENERAL_CTL, reg);
 }
+
+/* JMicron specific */
+#define	JMICRON_PMOS	0xae
+#define	 PMOS_ON	(1U << 0) /* Turn PMOS on */
+#define	 PMOS_DET_2_4V	(3U << 1) /* over current detection to 2.4V */
+#define	 PMOS_DEBOUNCE	(1U << 6) /* enable over current debouncing */
+
+/* pci_conf_{read,write}() require 4bytes aligned register number */
+#define	JMICRON_PMOS_REG	(JMICRON_PMOS & ~3)
+#define	JMICRON_PMOS_SB		((JMICRON_PMOS & 3) * 8)
+
+static __inline uint8_t
+jmicron_pmos_read(pci_chipset_tag_t pct, pcitag_t pt)
+{
+	pcireg_t reg;
+
+	reg = pci_conf_read(pct, pt, JMICRON_PMOS_REG);
+	reg >>= JMICRON_PMOS_SB;
+
+	return (uint8_t)reg;
+}
+
+static __inline void
+jmicron_pmos_write(pci_chipset_tag_t pct, pcitag_t pt, uint8_t pmos)
+{
+	pcireg_t reg;
+
+	reg = pci_conf_read(pct, pt, JMICRON_PMOS_REG);
+	CLR(reg, 0xff << JMICRON_PMOS_SB);
+	SET(reg, pmos << JMICRON_PMOS_SB);
+	pci_conf_write(pct, pt, JMICRON_PMOS_REG, reg);
+}
+
+static void
+jmicron_pmos(pci_chipset_tag_t pct, pcitag_t pt, int onoff)
+{
+	uint8_t pmos;
+
+	pmos = jmicron_pmos_read(pct, pt);
+	if (onoff)
+		SET(pmos, PMOS_ON | PMOS_DET_2_4V | PMOS_DEBOUNCE);
+	else
+		CLR(pmos, PMOS_ON | PMOS_DET_2_4V | PMOS_DEBOUNCE);
+	jmicron_pmos_write(pct, pt, pmos);
+}
+
+static void
+sdhc_pci_quirk_jmicron_hack(struct pci_attach_args *pa,
+    struct sdhc_pci_softc *sc)
+{
+
+	/* power on */
+	jmicron_pmos(sc->sc_pct, sc->sc_pt, 1);
+
+	switch (PCI_PRODUCT(sc->sc_id)) {
+	case PCI_PRODUCT_JMICRON_JMB38X_SD:
+	case PCI_PRODUCT_JMICRON_JMB388_SD:
+		SET(sc->sc.sc_flags, SDHC_FLAG_BROKEN_RO_DETECT);
+		break;
+	}
+}
+
+#define	JMICRON_MMC_INTR	0xc0
+#define	 MMC_INTR_EN		0x01
+
+static void
+jmicron_mmc_enable_intr(struct sdhc_host *hp, int onoff)
+{
+	uint8_t reg;
+
+	reg = sdhc_read_1(hp, JMICRON_MMC_INTR);
+	if (onoff)
+		SET(reg, MMC_INTR_EN);
+	else
+		CLR(reg, MMC_INTR_EN);
+	sdhc_write_1(hp, JMICRON_MMC_INTR, reg);
+}
+
+static int
+sdhc_pci_quirk_jmicron_host_add(struct pci_attach_args *pa,
+    struct sdhc_pci_softc *sc)
+{
+	struct sdhc_host *hp = sc->sc.sc_host[sc->sc.sc_nhosts - 1];
+	uint16_t sdhcver;
+
+	if (PCI_REVISION(pa->pa_class) == 0) {
+		sdhcver = sdhc_read_2(hp, SDHC_HOST_CTL_VERSION);
+		if (SDHC_VENDOR_VERSION(sdhcver) < 0xac)
+			SET(sc->sc.sc_flags, SDHC_FLAG_BROKEN_ADMA);
+	}
+
+	switch (PCI_PRODUCT(sc->sc_id)) {
+	case PCI_PRODUCT_JMICRON_JMB38X_MMC:
+	case PCI_PRODUCT_JMICRON_JMB388_MMC:
+		jmicron_mmc_enable_intr(hp, 1);
+		break;
+	}
+	return 0;
+}
+
+static void
+sdhc_pci_quirk_jmicron_host_remove(struct sdhc_pci_softc *sc)
+{
+	struct sdhc_host *hp = sc->sc.sc_host[sc->sc.sc_nhosts - 1];
+
+	switch (PCI_PRODUCT(sc->sc_id)) {
+	case PCI_PRODUCT_JMICRON_JMB38X_MMC:
+	case PCI_PRODUCT_JMICRON_JMB388_MMC:
+		jmicron_mmc_enable_intr(hp, 1);
+		break;
+	}
+}
+
+static bool
+shdc_pci_quirk_jmicron_suspend(struct sdhc_pci_softc *sc,
+    const pmf_qual_t *qual)
+{
+	int i;
+
+	switch (PCI_PRODUCT(sc->sc_id)) {
+	case PCI_PRODUCT_JMICRON_JMB38X_MMC:
+	case PCI_PRODUCT_JMICRON_JMB388_MMC:
+		for (i = 0; i < sc->sc.sc_nhosts; i++)
+			jmicron_mmc_enable_intr(sc->sc.sc_host[i], 0);
+		break;
+	}
+
+#if 0
+	/* power off */
+	jmicron_pmos(sc->sc_pct, sc->sc_pt, 0);
+#endif
+
+	return true;
+}
+
+static bool
+shdc_pci_quirk_jmicron_resume(struct sdhc_pci_softc *sc,
+    const pmf_qual_t *qual)
+{
+	int i;
+
+	switch (PCI_PRODUCT(sc->sc_id)) {
+	case PCI_PRODUCT_JMICRON_JMB38X_MMC:
+	case PCI_PRODUCT_JMICRON_JMB388_MMC:
+		for (i = 0; i < sc->sc.sc_nhosts; i++)
+			jmicron_mmc_enable_intr(sc->sc.sc_host[i], 1);
+		break;
+	}
+
+	/* power on */
+	jmicron_pmos(sc->sc_pct, sc->sc_pt, 1);
+
+	return true;
+}
--- src.orig/sys/dev/cardbus/sdhc_cardbus.c	2011-08-01 20:20:28.000000000 +0900
+++ src/sys/dev/cardbus/sdhc_cardbus.c	2012-02-02 07:40:31.000000000 +0900
@@ -28,6 +28,8 @@
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: sdhc_cardbus.c,v 1.3 2011/08/01 11:20:28 drochner Exp $");
 
+#include "opt_sdmmc.h"
+
 #include <sys/param.h>
 #include <sys/device.h>
 #include <sys/systm.h>