Index: sys/arch/dreamcast/conf/files.dreamcast =================================================================== RCS file: /cvsroot/src/sys/arch/dreamcast/conf/files.dreamcast,v retrieving revision 1.30 diff -u -r1.30 files.dreamcast --- sys/arch/dreamcast/conf/files.dreamcast 20 Feb 2008 21:43:33 -0000 1.30 +++ sys/arch/dreamcast/conf/files.dreamcast 3 Oct 2009 19:10:27 -0000 @@ -104,4 +104,15 @@ attach aica at g2bus file arch/dreamcast/dev/g2/aica.c aica needs-flag +device dcext { [port = -1], [irq = -1] } +attach dcext at g2bus +file arch/dreamcast/dev/g2/dcext.c dcext +file arch/dreamcast/dev/g2/dcext_bus_mem.c dcext + +attach wdc at dcext with wdc_dcext +file arch/dreamcast/dev/g2/wdc_dcext.c wdc_dcext + +attach ne at dcext with ne_dcext: rtl80x9 +file arch/dreamcast/dev/g2/if_ne_dcext.c ne_dcext + include "arch/dreamcast/conf/majors.dreamcast" Index: sys/arch/dreamcast/dev/g2/g2bus_bus_mem.c =================================================================== RCS file: /cvsroot/src/sys/arch/dreamcast/dev/g2/g2bus_bus_mem.c,v retrieving revision 1.14 diff -u -r1.14 g2bus_bus_mem.c --- sys/arch/dreamcast/dev/g2/g2bus_bus_mem.c 28 Apr 2008 20:23:16 -0000 1.14 +++ sys/arch/dreamcast/dev/g2/g2bus_bus_mem.c 3 Oct 2009 19:10:27 -0000 @@ -54,57 +54,6 @@ bus_space_handle_t *); void g2bus_bus_mem_unmap(void *, bus_space_handle_t, bus_size_t); -uint8_t g2bus_bus_mem_read_1(void *, bus_space_handle_t, bus_size_t); -uint16_t g2bus_bus_mem_read_2(void *, bus_space_handle_t, bus_size_t); -uint32_t g2bus_bus_mem_read_4(void *, bus_space_handle_t, bus_size_t); - -void g2bus_bus_mem_write_1(void *, bus_space_handle_t, bus_size_t, - uint8_t); -void g2bus_bus_mem_write_2(void *, bus_space_handle_t, bus_size_t, - uint16_t); -void g2bus_bus_mem_write_4(void *, bus_space_handle_t, bus_size_t, - uint32_t); - -void g2bus_bus_mem_read_region_1(void *, bus_space_handle_t, bus_size_t, - uint8_t *, bus_size_t); -void g2bus_bus_mem_read_region_2(void *, bus_space_handle_t, bus_size_t, - uint16_t *, bus_size_t); -void g2bus_bus_mem_read_region_4(void *, bus_space_handle_t, bus_size_t, - uint32_t *, bus_size_t); - -void g2bus_bus_mem_write_region_1(void *, bus_space_handle_t, bus_size_t, - const uint8_t *, bus_size_t); -void g2bus_bus_mem_write_region_2(void *, bus_space_handle_t, bus_size_t, - const uint16_t *, bus_size_t); -void g2bus_bus_mem_write_region_4(void *, bus_space_handle_t, bus_size_t, - const uint32_t *, bus_size_t); - -void g2bus_bus_mem_set_region_4(void *, bus_space_handle_t, bus_size_t, - uint32_t, bus_size_t); - -uint8_t g2bus_sparse_bus_mem_read_1(void *, bus_space_handle_t, bus_size_t); -uint16_t g2bus_sparse_bus_mem_read_2(void *, bus_space_handle_t, bus_size_t); -uint32_t g2bus_sparse_bus_mem_read_4(void *, bus_space_handle_t, bus_size_t); - -void g2bus_sparse_bus_mem_write_1(void *, bus_space_handle_t, bus_size_t, - uint8_t); -void g2bus_sparse_bus_mem_write_2(void *, bus_space_handle_t, bus_size_t, - uint16_t); -void g2bus_sparse_bus_mem_write_4(void *, bus_space_handle_t, bus_size_t, - uint32_t); - -void g2bus_sparse_bus_mem_read_region_1(void *, bus_space_handle_t, - bus_size_t, uint8_t *, bus_size_t); - -void g2bus_sparse_bus_mem_write_region_1(void *, bus_space_handle_t, - bus_size_t, const uint8_t *, bus_size_t); - -void g2bus_sparse_bus_mem_read_multi_1(void *, bus_space_handle_t, - bus_size_t, uint8_t *, bus_size_t); - -void g2bus_sparse_bus_mem_write_multi_1(void *, bus_space_handle_t, - bus_size_t, const uint8_t *, bus_size_t); - void g2bus_bus_mem_init(struct g2bus_softc *sc) { @@ -175,6 +124,8 @@ _cpu_intr_resume(__s); \ } while (/*CONSTCOND*/0) +#define G2BUSMEM_UNROLL_ITERATIONS + uint8_t g2bus_bus_mem_read_1(void *v, bus_space_handle_t sh, bus_size_t off) { @@ -267,6 +218,31 @@ volatile const uint8_t *baddr = (uint8_t *)(sh + off); G2_LOCK(); +#ifdef G2BUSMEM_UNROLL_ITERATIONS + for (; len >= 16; len -= 16) { + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + *addr++ = *baddr++; + if (((len & ~0xf) & 0x1ff) == 0) { + /* drain pending interrupts */ + G2_UNLOCK(); + G2_LOCK(); + } + } +#endif /* G2BUSMEM_UNROLL_ITERATIONS */ while (len--) *addr++ = *baddr++; @@ -312,6 +288,31 @@ volatile uint8_t *baddr = (uint8_t *)(sh + off); G2_LOCK(); +#ifdef G2BUSMEM_UNROLL_ITERATIONS + for (; len >= 16; len -= 16) { + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + *baddr++ = *addr++; + if (((len & ~0xf) & 0x1ff) == 0) { + /* drain pending interrupts */ + G2_UNLOCK(); + G2_LOCK(); + } + } +#endif /* G2BUSMEM_UNROLL_ITERATIONS */ while (len--) *baddr++ = *addr++; @@ -477,6 +478,31 @@ volatile const uint8_t *baddr = (uint8_t *)(sh + (off * 4)); G2_LOCK(); +#ifdef G2BUSMEM_UNROLL_ITERATIONS + for (; len >= 8; len -= 8) { + *addr++ = *baddr; + baddr += 4; + *addr++ = *baddr; + baddr += 4; + *addr++ = *baddr; + baddr += 4; + *addr++ = *baddr; + baddr += 4; + *addr++ = *baddr; + baddr += 4; + *addr++ = *baddr; + baddr += 4; + *addr++ = *baddr; + baddr += 4; + *addr++ = *baddr; + baddr += 4; + if (((len & ~0x7) & 0x1ff) == 0) { + /* drain pending interrupts */ + G2_UNLOCK(); + G2_LOCK(); + } + } +#endif /* G2BUSMEM_UNROLL_ITERATIONS */ while (len--) { *addr++ = *baddr; @@ -494,6 +520,31 @@ volatile uint8_t *baddr = (uint8_t *)(sh + (off * 4)); G2_LOCK(); +#ifdef G2BUSMEM_UNROLL_ITERATIONS + for (; len >= 8; len -= 8) { + *baddr = *addr++; + baddr += 4; + *baddr = *addr++; + baddr += 4; + *baddr = *addr++; + baddr += 4; + *baddr = *addr++; + baddr += 4; + *baddr = *addr++; + baddr += 4; + *baddr = *addr++; + baddr += 4; + *baddr = *addr++; + baddr += 4; + *baddr = *addr++; + baddr += 4; + if (((len & ~0x7) & 0x1ff) == 0) { + /* drain pending interrupts */ + G2_UNLOCK(); + G2_LOCK(); + } + } +#endif /* G2BUSMEM_UNROLL_ITERATIONS */ while (len--) { *baddr = *addr++; @@ -511,6 +562,73 @@ volatile const uint8_t *baddr = (uint8_t *)(sh + (off * 4)); G2_LOCK(); +#ifdef G2BUSMEM_UNROLL_ITERATIONS + for (; len >= 16; len -= 16) { + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + if (((len & ~0xf) & 0x1ff) == 0) { + /* drain pending interrupts */ + G2_UNLOCK(); + G2_LOCK(); + } + } +#endif /* G2BUSMEM_UNROLL_ITERATIONS */ + + while (len--) + *addr++ = *baddr; + + G2_UNLOCK(); +} + +void +g2bus_sparse_bus_mem_read_multi_2(void *v, bus_space_handle_t sh, + bus_size_t off, uint16_t *addr, bus_size_t len) +{ + G2LOCK_DECL; + __volatile uint16_t *baddr; + + baddr = (uint16_t *)(sh + (off * 4)); + + G2_LOCK(); +#ifdef G2BUSMEM_UNROLL_ITERATIONS + for (; len >= 16; len -= 16) { + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + *addr++ = *baddr; + if (((len & ~0xf) & 0x1ff) == 0) { + /* drain pending interrupts */ + G2_UNLOCK(); + G2_LOCK(); + } + } +#endif /* G2BUSMEM_UNROLL_ITERATIONS */ while (len--) *addr++ = *baddr; @@ -526,6 +644,73 @@ volatile uint8_t *baddr = (uint8_t *)(sh + (off * 4)); G2_LOCK(); +#ifdef G2BUSMEM_UNROLL_ITERATIONS + for (; len >= 16; len -= 16) { + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + if (((len & ~0xf) & 0x1ff) == 0) { + /* drain pending interrupts */ + G2_UNLOCK(); + G2_LOCK(); + } + } +#endif /* G2BUSMEM_UNROLL_ITERATIONS */ + + while (len--) + *baddr = *addr++; + + G2_UNLOCK(); +} + +void +g2bus_sparse_bus_mem_write_multi_2(void *v, bus_space_handle_t sh, + bus_size_t off, const uint16_t *addr, bus_size_t len) +{ + G2LOCK_DECL; + __volatile uint16_t *baddr; + + baddr = (uint16_t *)(sh + (off * 4)); + + G2_LOCK(); +#ifdef G2BUSMEM_UNROLL_ITERATIONS + for (; len >= 16; len -= 16) { + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + *baddr = *addr++; + if (((len & ~0xf) & 0x1ff) == 0) { + /* drain pending interrupts */ + G2_UNLOCK(); + G2_LOCK(); + } + } +#endif /* G2BUSMEM_UNROLL_ITERATIONS */ while (len--) *baddr = *addr++; Index: sys/arch/dreamcast/dev/g2/g2busvar.h =================================================================== RCS file: /cvsroot/src/sys/arch/dreamcast/dev/g2/g2busvar.h,v retrieving revision 1.4 diff -u -r1.4 g2busvar.h --- sys/arch/dreamcast/dev/g2/g2busvar.h 27 Dec 2002 11:34:05 -0000 1.4 +++ sys/arch/dreamcast/dev/g2/g2busvar.h 3 Oct 2009 19:10:27 -0000 @@ -66,4 +66,59 @@ void g2bus_bus_mem_init(struct g2bus_softc *); void g2bus_set_bus_mem_sparse(bus_space_tag_t); +u_int8_t g2bus_bus_mem_read_1(void *, bus_space_handle_t, bus_size_t); +u_int16_t g2bus_bus_mem_read_2(void *, bus_space_handle_t, bus_size_t); +u_int32_t g2bus_bus_mem_read_4(void *, bus_space_handle_t, bus_size_t); + +void g2bus_bus_mem_write_1(void *, bus_space_handle_t, bus_size_t, + u_int8_t); +void g2bus_bus_mem_write_2(void *, bus_space_handle_t, bus_size_t, + u_int16_t); +void g2bus_bus_mem_write_4(void *, bus_space_handle_t, bus_size_t, + u_int32_t); + +void g2bus_bus_mem_read_region_1(void *, bus_space_handle_t, bus_size_t, + u_int8_t *, bus_size_t); +void g2bus_bus_mem_read_region_2(void *, bus_space_handle_t, bus_size_t, + u_int16_t *, bus_size_t); +void g2bus_bus_mem_read_region_4(void *, bus_space_handle_t, bus_size_t, + u_int32_t *, bus_size_t); + +void g2bus_bus_mem_write_region_1(void *, bus_space_handle_t, bus_size_t, + const u_int8_t *, bus_size_t); +void g2bus_bus_mem_write_region_2(void *, bus_space_handle_t, bus_size_t, + const u_int16_t *, bus_size_t); +void g2bus_bus_mem_write_region_4(void *, bus_space_handle_t, bus_size_t, + const u_int32_t *, bus_size_t); + +void g2bus_bus_mem_set_region_4(void *, bus_space_handle_t, bus_size_t, + u_int32_t, bus_size_t); + +u_int8_t g2bus_sparse_bus_mem_read_1(void *, bus_space_handle_t, bus_size_t); +u_int16_t g2bus_sparse_bus_mem_read_2(void *, bus_space_handle_t, bus_size_t); +u_int32_t g2bus_sparse_bus_mem_read_4(void *, bus_space_handle_t, bus_size_t); + +void g2bus_sparse_bus_mem_write_1(void *, bus_space_handle_t, bus_size_t, + u_int8_t); +void g2bus_sparse_bus_mem_write_2(void *, bus_space_handle_t, bus_size_t, + u_int16_t); +void g2bus_sparse_bus_mem_write_4(void *, bus_space_handle_t, bus_size_t, + u_int32_t); + +void g2bus_sparse_bus_mem_read_region_1(void *, bus_space_handle_t, + bus_size_t, u_int8_t *, bus_size_t); + +void g2bus_sparse_bus_mem_write_region_1(void *, bus_space_handle_t, + bus_size_t, const u_int8_t *, bus_size_t); + +void g2bus_sparse_bus_mem_read_multi_1(void *, bus_space_handle_t, + bus_size_t, u_int8_t *, bus_size_t); +void g2bus_sparse_bus_mem_read_multi_2(void *, bus_space_handle_t, + bus_size_t, u_int16_t *, bus_size_t); + +void g2bus_sparse_bus_mem_write_multi_1(void *, bus_space_handle_t, + bus_size_t, const u_int8_t *, bus_size_t); +void g2bus_sparse_bus_mem_write_multi_2(void *, bus_space_handle_t, + bus_size_t, const u_int16_t *, bus_size_t); + #endif /* _DREAMCAST_G2BUSVAR_H_ */ Index: sys/arch/dreamcast/dreamcast/machdep.c =================================================================== RCS file: /cvsroot/src/sys/arch/dreamcast/dreamcast/machdep.c,v retrieving revision 1.36 diff -u -r1.36 machdep.c --- sys/arch/dreamcast/dreamcast/machdep.c 28 Apr 2008 20:23:16 -0000 1.36 +++ sys/arch/dreamcast/dreamcast/machdep.c 3 Oct 2009 19:10:27 -0000 @@ -177,6 +177,10 @@ strcpy(cpu_model, "SEGA Dreamcast\n"); sh_startup(); + +#ifdef FORCE_RB_SINGLE + boothowto |= RB_SINGLE; +#endif } SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") --- /dev/null 2009-10-04 03:15:01.000000000 +0900 +++ sys/arch/dreamcast/conf/DCEXT 2008-12-23 20:12:32.000000000 +0900 @@ -0,0 +1,38 @@ +include "arch/dreamcast/conf/GENERIC" + +# Enable experimental buffer queue strategy for better responsiveness under +# high disk I/O load. Likely stable but not yet the default. +#options BUFQ_READPRIO +options BUFQ_PRIOCSCAN + +no options EXEC_COFF + +no options SYMTAB_SPACE +options SYMTAB_SPACE=307200 + +no options FONT_BOLD8x16 +options FONT_VT220ISO8x16 + +no config netbsd +config netbsd root on wd0a type ? + +# +# DCext bus +# irq = IDE | IRQ9 | IRQ5 | IRQ11 | IRQ10 +# +dcext0 at g2bus? + +wdc0 at dcext? port 0x400 irq 14 +atabus* at wdc? channel ? +wd* at atabus? drive ? flags 0x0000 + +atapibus* at atapi? +cd* at atapibus? drive ? flags 0x0000 +#sd* at atapibus? drive ? flags 0x0000 +#uk* at atapibus? drive ? flags 0x0000 + +ne0 at dcext? port 0x280 irq 9 +ne1 at dcext? port 0x300 irq 5 + +no pseudo-device accf_data +no pseudo-device accf_http --- /dev/null 2009-10-04 03:15:01.000000000 +0900 +++ sys/arch/dreamcast/dev/g2/dcext.c 2008-12-24 00:05:51.000000000 +0900 @@ -0,0 +1,270 @@ +/* $NetBSD$ */ + +/*- + * Copyright (C) 2002,2003 Izumi Tsutsui. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include + +#include + +#include "locators.h" + +/* #define DCEXT_EVENT_COUNTERS */ + +static const int isatodcextirq[] = { + -1, /* 0: N/A */ + -1, /* 1: N/A */ + -1, /* 2: N/A */ + -1, /* 3: N/A */ + -1, /* 4: N/A */ + 0x0004, /* 5: ISA slot */ + -1, /* 6: N/A */ + -1, /* 7: N/A */ + -1, /* 8: N/A */ + 0x0008, /* 9: N/A */ + 0x0001, /* 10: ISA slot */ + 0x0002, /* 11: ISA slot */ + -1, /* 12: N/A */ + -1, /* 13: N/A */ + 0x0010, /* 14: wdc port */ + -1 /* 15: N/A */ +}; + +int dcext_match(struct device *, struct cfdata *, void *); +void dcext_attach(struct device *, struct device *, void *); +int dcext_print(void *, const char *); +int dcext_search(struct device *, struct cfdata *, const int *, void *); + +CFATTACH_DECL(dcext, sizeof(struct dcext_softc), + dcext_match, dcext_attach, NULL, NULL); + +struct dcext_intr dcext_intr_list; + +int +dcext_match(struct device *parent, struct cfdata *cf, void *aux) +{ + volatile uint16_t *irqaddr, *reset; + + /* XXX needs real probe strategy */ + reset = (void *)DCEXT_RESETADDR; + *reset = 0x0000; + delay(1000); + *reset = 0x0001; + delay(1000); + *reset = 0x0000; + delay(1000); + + irqaddr = (void *)DCEXT_IRQADDR; + + if ((*irqaddr & 0x1000) != 0) /* XXX */ + return 0; + + return 1; +} + +void +dcext_attach(struct device *parent, struct device *self, void *aux) +{ + struct dcext_softc *sc = (void *)self; + volatile uint16_t *reset; + + printf(": Dreamcast Extension board\n"); + printf("%s: using %s\n", sc->sc_dev.dv_xname, + sysasic_intr_string(SYSASIC_IRL11)); + + TAILQ_INIT(&sc->sc_subdevs); + + reset = (void *)DCEXT_RESETADDR; + *reset = 0x0000; + delay(1000); + *reset = 0x0001; + delay(1000); + *reset = 0x0000; + delay(1000); + + dcext_bus_mem_init(sc); + + config_search_ia(dcext_search, self, "dcext", NULL); +} + +int +dcext_print(void *aux, const char *pnp) +{ + struct dcext_attach_args *da = aux; + + printf(" port 0x%x", da->da_iobase); + if (da->da_irq > 0) + printf(" irq %d", da->da_irq); + + return UNCONF; +} + +int +dcext_search(struct device *parent, struct cfdata *cf, + const int *ldesc, void *aux) +{ + struct dcext_attach_args da; + struct dcext_softc *sc = (void *)parent; + + da.da_iot = &sc->sc_memt; + da.da_iobase = cf->cf_loc[DCEXTCF_PORT]; + da.da_irq = cf->cf_loc[DCEXTCF_IRQ]; + + if (config_match(parent, cf, &da) > 0) + config_attach(parent, cf, &da, dcext_print); + + return 0; +} + +void +dcext_intr_init(void) +{ + struct dcext_intr *di; + + di = &dcext_intr_list; + LIST_INIT(&di->di_q); +#ifdef DCEXT_EVENT_COUNTERS + evcnt_attach_dynamic(&di->di_evcnt, EVCNT_TYPE_INTR, + NULL, "intr", "dcext"); +#endif + + sysasic_intr_establish(SYSASIC_EVENT_EXT, IPL_NET, SYSASIC_IRL11, + dcext_intr_dispatch, NULL); +} + +void * +dcext_intr_establish(int irq, int ipl, int (*func)(void *), void *arg, + const char *ev_name) +{ + struct dcext_intr *di; + struct dcext_intrhand *newih, *curih; + + /* check IRQ value */ + if (irq < 0 || irq > 15 || isatodcextirq[irq] == -1) { + printf("dcext_intr_establish: invalid IRQ value\n"); + return NULL; + } + + di = &dcext_intr_list; + + newih = malloc(sizeof *newih, M_DEVBUF, M_NOWAIT); + if (newih == NULL) + panic("dcext_intr_establish: can't allocate memory"); + + /* fill in the new entry */ + newih->ih_func = func; + newih->ih_arg = arg; + newih->ih_ipl = ipl; + newih->ih_irq = isatodcextirq[irq]; + + evcnt_attach_dynamic(&newih->ih_evcnt, EVCNT_TYPE_INTR, + NULL, "dcext", ev_name); + + if (LIST_EMPTY(&di->di_q)) { + dcext_intr_init(); + LIST_INSERT_HEAD(&di->di_q, newih, ih_q); + goto done; + } + + for (curih = LIST_FIRST(&di->di_q); + LIST_NEXT(curih, ih_q) != NULL; + curih = LIST_NEXT(curih, ih_q)) { + if (newih->ih_ipl > curih->ih_ipl) { + LIST_INSERT_BEFORE(curih, newih, ih_q); + goto done; + } + } + + LIST_INSERT_AFTER(curih, newih, ih_q); + + done: + return newih; +} + +void +dcext_intr_disestablish(void *arg) +{ + struct dcext_intrhand *ih = arg; + + LIST_REMOVE(ih, ih_q); + free(ih, M_DEVBUF); +} + +int +dcext_intr_dispatch(void *arg) +{ + struct dcext_intrhand *ih; + struct dcext_intr *list; + int handled, rv; + u_int irqs; + static int straycount, unexpected; + int s; + + s = _cpu_intr_suspend(); + + handled = 0; + irqs = *(volatile uint16_t *)DCEXT_IRQADDR; + list = &dcext_intr_list; + + if (__predict_false(LIST_EMPTY(&list->di_q))) { + printf("dcext_intr_dispatch: unexpected interrupt\n"); + if (++unexpected > 10) + panic("too many unexpected interrupts"); + goto out; + } + + LIST_FOREACH(ih, &list->di_q, ih_q) { + if ((ih->ih_irq & irqs) != 0) { + _cpu_intr_resume(s); + rv = (*ih->ih_func)(ih->ih_arg); + s = _cpu_intr_suspend(); + if (rv != 0) { + handled = 1; + ih->ih_evcnt.ev_count++; + } + } + } + + if (__predict_true(handled)) { +#ifdef DCEXT_EVENT_COUNTERS + list->di_evcnt.ev_count++; +#endif + straycount = 0; + } else if (++straycount > 50) + panic("dcext_intr_dispatch: too many stray interrupts"); + else + printf("dcext_intr_dispatch: stray interrupt: irqs = 0x%04x\n", + irqs); + + out: + _cpu_intr_resume(s); + + return handled; +} --- /dev/null 2009-10-04 03:15:01.000000000 +0900 +++ sys/arch/dreamcast/dev/g2/dcext_bus_mem.c 2008-12-23 19:44:00.000000000 +0900 @@ -0,0 +1,114 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Bus space implementation for the dcext devices. + */ + +#include /* RCS ID & Copyright macro defns */ + +#include +#include +#include + +#include +#include + +#include +#include + +int dcext_bus_mem_map(void *, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +void dcext_bus_mem_unmap(void *, bus_space_handle_t, bus_size_t); + +int dcext_space_subregion(void *, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); + +void +dcext_bus_mem_init(struct dcext_softc *sc) +{ + bus_space_tag_t t = &sc->sc_memt; + + memset(t, 0, sizeof(*t)); + + t->dbs_map = dcext_bus_mem_map; + t->dbs_unmap = dcext_bus_mem_unmap; + + t->dbs_r_1 = g2bus_sparse_bus_mem_read_1; + t->dbs_r_2 = g2bus_sparse_bus_mem_read_2; + t->dbs_r_4 = g2bus_sparse_bus_mem_read_4; + + t->dbs_w_1 = g2bus_sparse_bus_mem_write_1; + t->dbs_w_2 = g2bus_sparse_bus_mem_write_2; + t->dbs_w_4 = g2bus_sparse_bus_mem_write_4; + + t->dbs_rr_1 = g2bus_sparse_bus_mem_read_region_1; + + t->dbs_wr_1 = g2bus_sparse_bus_mem_write_region_1; + + t->dbs_rm_1 = g2bus_sparse_bus_mem_read_multi_1; + t->dbs_rm_2 = g2bus_sparse_bus_mem_read_multi_2; + + t->dbs_wm_1 = g2bus_sparse_bus_mem_write_multi_1; + t->dbs_wm_2 = g2bus_sparse_bus_mem_write_multi_2; + + t->dbs_subregion = dcext_space_subregion; +} + +int +dcext_bus_mem_map(void *v, bus_addr_t addr, bus_size_t size, int flags, + bus_space_handle_t *shp) +{ + + KASSERT((addr & SH3_PHYS_MASK) == addr); + + addr |= 0xb4000000; + *shp = SH3_PHYS_TO_P2SEG(addr); + + return 0; +} + +void +dcext_bus_mem_unmap(void *v, bus_space_handle_t sh, bus_size_t size) +{ + + KASSERT(sh >= SH3_P2SEG_BASE && sh <= SH3_P2SEG_END); + /* Nothing to do. */ +} + +int +dcext_space_subregion(void *v, bus_space_handle_t handle, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nhandlep) +{ + + *nhandlep = handle + (offset << DCEXT_STRIDE); + return 0; +} --- /dev/null 2009-10-04 03:15:01.000000000 +0900 +++ sys/arch/dreamcast/dev/g2/dcextvar.h 2008-12-23 19:44:39.000000000 +0900 @@ -0,0 +1,95 @@ +/* $NetBSD$ */ + +/*- + * Copyright (C) 2002 Izumi Tsutsui. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DREAMCAST_DPPBUSVAR_H_ +#define _DREAMCAST_DPPBUSVAR_H_ + +#include +#include "locators.h" + +/* + * DCext driver attach arguments + */ +struct dcext_attach_args { + bus_space_tag_t da_iot; + int da_iobase; /* base i/o address */ + int da_irq; /* interrupt request */ +}; + +/* + * Per-device DCext variables + */ +struct dcextdev { + struct device *dd_dev; /* back pointer to generic */ + TAILQ_ENTRY(dcextdev) + dd_bchain; /* bus chain */ +}; + +/* + * master bus + */ +struct dcext_softc { + struct device sc_dev; /* base device */ + struct dreamcast_bus_space sc_memt; + TAILQ_HEAD(, dcextdev) + sc_subdevs; /* list of all children */ +}; + +/* + * structures for interrupt handling + */ +struct dcext_intrhand { + LIST_ENTRY(dcext_intrhand) ih_q; + int (*ih_func)(void *); + void *ih_arg; + int ih_ipl; + int ih_irq; + struct evcnt ih_evcnt; +}; + +struct dcext_intr { + LIST_HEAD(, dcext_intrhand) di_q; + struct evcnt di_evcnt; +}; + +#define DCEXT_IRQADDR 0xb400c000 +#define DCEXT_RESETADDR 0xb400f000 +#define DCEXT_STRIDE 2 + +#define DCEXT_ISAIOTOPA(ioaddr) ((ioaddr) << DCEXT_STRIDE) + +/* + * functions declarations + */ + +void dcext_bus_mem_init(struct dcext_softc *); + +void dcext_intr_init(void); +void *dcext_intr_establish(int, int, int (*)(void *), void *, const char *); +void dcext_intr_disestablish(void *); +int dcext_intr_dispatch(void *); + +#endif /* _DREAMCAST_DPPBUSVAR_H_ */ --- /dev/null 2009-10-04 03:15:01.000000000 +0900 +++ sys/arch/dreamcast/dev/g2/if_ne_dcext.c 2008-12-23 19:45:24.000000000 +0900 @@ -0,0 +1,198 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +int ne_dcext_probe(device_t, cfdata_t, void *); +void ne_dcext_attach(device_t, device_t, void *); + +struct ne_dcext_softc { + struct ne2000_softc sc_ne2000; /* real "ne2000" softc */ + void *sc_ih; + + /* DCEXT-specific goo. */ + int sc_irq; +}; + +CFATTACH_DECL_NEW(ne_dcext, sizeof(struct ne_dcext_softc), + ne_dcext_probe, ne_dcext_attach, NULL, NULL); + +int +ne_dcext_probe(device_t parent, cfdata_t match, void *aux) +{ + struct dcext_attach_args *da = aux; + bus_space_tag_t nict = da->da_iot; + bus_space_handle_t nich; + bus_space_tag_t asict; + bus_space_handle_t asich; + int rv; + + rv = 0; + /* Disallow wildcarded values. */ + if (da->da_irq == DCEXTCF_IRQ_DEFAULT || + da->da_iobase == DCEXTCF_PORT_DEFAULT) + return 0; + + /* Map i/o space. */ + if (bus_space_map(nict, DCEXT_ISAIOTOPA(da->da_iobase), NE2000_NPORTS, + 0, &nich)) + return 0; + + asict = nict; + if (bus_space_subregion(nict, nich, NE2000_ASIC_OFFSET, + NE2000_ASIC_NPORTS, &asich)) + goto out; + + /* Look for an NE2000-compatible card. */ + rv = ne2000_detect(nict, nich, asict, asich); +#if 0 + if (rv) + da->da_iosize = NE2000_NPORTS; +#endif + + out: + bus_space_unmap(nict, nich, NE2000_NPORTS); + return rv; +} + +void +ne_dcext_attach(device_t parent, device_t self, void *aux) +{ + struct ne_dcext_softc *isc = device_private(self); + struct ne2000_softc *nsc = &isc->sc_ne2000; + struct dp8390_softc *dsc = &nsc->sc_dp8390; + struct dcext_attach_args *da = aux; + bus_space_tag_t nict = da->da_iot; + bus_space_handle_t nich; + bus_space_tag_t asict = nict; + bus_space_handle_t asich; + const char *typestr; + int netype; + + dsc->sc_dev = self; + aprint_normal("\n"); + + /* Map i/o space. */ + if (bus_space_map(nict, DCEXT_ISAIOTOPA(da->da_iobase), NE2000_NPORTS, + 0, &nich)) { + aprint_error_dev(self, "can't map i/o space\n"); + return; + } + + if (bus_space_subregion(nict, nich, NE2000_ASIC_OFFSET, + NE2000_ASIC_NPORTS, &asich)) { + aprint_error_dev(self, "can't subregion i/o space\n"); + return; + } + + isc->sc_irq = da->da_irq; + + dsc->sc_regt = nict; + dsc->sc_regh = nich; + + nsc->sc_asict = asict; + nsc->sc_asich = asich; + + /* + * Detect it again, so we can print some information about the + * interface. + */ + netype = ne2000_detect(nict, nich, asict, asich); + switch (netype) { + case NE2000_TYPE_NE1000: + typestr = "NE1000"; + break; + + case NE2000_TYPE_NE2000: + typestr = "NE2000"; + /* + * Check for a RealTek 8019. + */ + bus_space_write_1(nict, nich, ED_P0_CR, + ED_CR_PAGE_0 | ED_CR_STP); + if (bus_space_read_1(nict, nich, NERTL_RTL0_8019ID0) == + RTL0_8019ID0 && + bus_space_read_1(nict, nich, NERTL_RTL0_8019ID1) == + RTL0_8019ID1) { + typestr = "NE2000 (RTL8019)"; + dsc->sc_mediachange = rtl80x9_mediachange; + dsc->sc_mediastatus = rtl80x9_mediastatus; + dsc->init_card = rtl80x9_init_card; + dsc->sc_media_init = rtl80x9_media_init; + } + break; + + default: + aprint_error_dev(self, "where did the card go?!\n"); + return; + } + + aprint_normal_dev(self, "%s Ethernet\n", typestr); + + /* This interface is always enabled. */ + dsc->sc_enabled = 1; + + /* + * Do generic NE2000 attach. This will read the station address + * from the EEPROM. + */ + ne2000_attach(nsc, NULL); + + /* Establish the interrupt handler. */ + isc->sc_ih = dcext_intr_establish(isc->sc_irq, IPL_NET, + dp8390_intr, dsc, device_xname(self)); + if (isc->sc_ih == NULL) + aprint_error_dev(self, + "couldn't establish interrupt handler\n"); +} --- /dev/null 2009-10-04 03:15:01.000000000 +0900 +++ sys/arch/dreamcast/dev/g2/wdc_dcext.c 2008-12-23 19:45:43.000000000 +0900 @@ -0,0 +1,161 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum and by Onno van der Linden. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#define WDC_DCEXT_REG_NPORTS 8 +#define WDC_DCEXT_AUXREG_OFFSET 0x206 +#define WDC_DCEXT_AUXREG_NPORTS 1 + +struct wdc_dcext_softc { + struct wdc_softc sc_wdcdev; + struct ata_channel *wdc_chanlist[1]; + struct ata_channel ata_channel; + struct ata_queue wdc_chqueue; + struct wdc_regs wdc_regs; + void *sc_ih; + int sc_irq; +}; + +int wdc_dcext_match(device_t, cfdata_t, void *); +void wdc_dcext_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(wdc_dcext, sizeof(struct wdc_dcext_softc), + wdc_dcext_match, wdc_dcext_attach, NULL, NULL); + +int +wdc_dcext_match(device_t parent, cfdata_t cf, void *aux) +{ + struct ata_channel ch; + struct dcext_attach_args *da = aux; + struct wdc_softc wdc; + struct wdc_regs wdr; + int result = 0, i; + + memset(&wdc, 0, sizeof(wdc)); + memset(&ch, 0, sizeof(ch)); + ch.ch_atac = &wdc.sc_atac; + wdc.regs = &wdr; + + wdr.cmd_iot = da->da_iot; + if (bus_space_map(wdr.cmd_iot, DCEXT_ISAIOTOPA(da->da_iobase), + WDC_DCEXT_REG_NPORTS, 0, &wdr.cmd_baseioh)) + goto out; + + for (i = 0; i < WDC_DCEXT_REG_NPORTS; i++) { + if (bus_space_subregion(wdr.cmd_iot, wdr.cmd_baseioh, i, + i == 0 ? 4 : 1, &wdr.cmd_iohs[i]) != 0) + goto outunmap; + } + + wdc_init_shadow_regs(&ch); + + wdr.ctl_iot = da->da_iot; + if (bus_space_map(wdr.ctl_iot, + DCEXT_ISAIOTOPA(da->da_iobase + WDC_DCEXT_AUXREG_OFFSET), + WDC_DCEXT_AUXREG_NPORTS, 0, &wdr.ctl_ioh)) + goto outunmap; + + result = wdcprobe(&ch); + + bus_space_unmap(wdr.ctl_iot, wdr.ctl_ioh, WDC_DCEXT_AUXREG_NPORTS); + outunmap: + bus_space_unmap(wdr.cmd_iot, wdr.cmd_baseioh, WDC_DCEXT_REG_NPORTS); + out: + return result; +} + +void +wdc_dcext_attach(struct device *parent, struct device *self, void *aux) +{ + struct wdc_dcext_softc *sc = device_private(self); + struct wdc_regs *wdr; + struct dcext_attach_args *da = aux; + int i; + + sc->sc_wdcdev.sc_atac.atac_dev = self; + sc->sc_wdcdev.regs = wdr = &sc->wdc_regs; + + sc->sc_irq = da->da_irq; + wdr->cmd_iot = da->da_iot; + wdr->ctl_iot = da->da_iot; + if (bus_space_map(wdr->cmd_iot, + DCEXT_ISAIOTOPA(da->da_iobase), + WDC_DCEXT_REG_NPORTS, 0, &wdr->cmd_baseioh) || + bus_space_map(wdr->ctl_iot, + DCEXT_ISAIOTOPA(da->da_iobase + WDC_DCEXT_AUXREG_OFFSET), + WDC_DCEXT_AUXREG_NPORTS, 0, &wdr->ctl_ioh)) { + aprint_error(": couldn't map registers\n"); + return; + } + + for (i = 0; i < WDC_DCEXT_REG_NPORTS; i++) { + if (bus_space_subregion(wdr->cmd_iot, + wdr->cmd_baseioh, i, i == 0 ? 2 : 1, + &wdr->cmd_iohs[i]) != 0) { + aprint_error(": couldn't subregion registers\n"); + return; + } + } + + sc->sc_wdcdev.cap |= WDC_CAPABILITY_PREATA; + sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16; + sc->sc_wdcdev.sc_atac.atac_pio_cap = 0; + sc->wdc_chanlist[0] = &sc->ata_channel; + sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist; + sc->sc_wdcdev.sc_atac.atac_nchannels = 1; + sc->ata_channel.ch_channel = 0; + sc->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac; + sc->ata_channel.ch_queue = &sc->wdc_chqueue; + sc->ata_channel.ch_ndrive = 2; + wdc_init_shadow_regs(&sc->ata_channel); + + aprint_normal("\n"); + + sc->sc_ih = dcext_intr_establish(sc->sc_irq, IPL_BIO, + wdcintr, &sc->ata_channel, device_xname(self)); + if (sc->sc_ih == NULL) + panic("wdc_dcext_attach: can't establish interrupt"); + + wdcattach(&sc->ata_channel); +}