kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / dev / disk / ct / bshw_machdep.c
1 /* $FreeBSD: src/sys/dev/ct/bshw_machdep.c,v 1.3.2.1 2001/07/26 02:32:18 nyan Exp $ */
2 /* $DragonFly: src/sys/dev/disk/ct/Attic/bshw_machdep.c,v 1.3 2003/08/07 21:16:52 dillon Exp $ */
3 /*      $NecBSD: bshw_machdep.c,v 1.8.12.6 2001/06/29 06:28:05 honda Exp $      */
4 /*      $NetBSD$        */
5
6 /*
7  * [NetBSD for NEC PC-98 series]
8  *  Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
9  *      NetBSD/pc98 porting staff. All rights reserved.
10  * 
11  *  Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
12  *      Naofumi HONDA.  All rights reserved.
13  *
14  *  Redistribution and use in source and binary forms, with or without
15  *  modification, are permitted provided that the following conditions
16  *  are met:
17  *  1. Redistributions of source code must retain the above copyright
18  *     notice, this list of conditions and the following disclaimer.
19  *  2. Redistributions in binary form must reproduce the above copyright
20  *     notice, this list of conditions and the following disclaimer in the
21  *     documentation and/or other materials provided with the distribution.
22  *  3. The name of the author may not be used to endorse or promote products
23  *     derived from this software without specific prior written permission.
24  * 
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
29  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37
38 #include "opt_ddb.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #if defined(__FreeBSD__) && __FreeBSD_version > 500001
44 #include <sys/bio.h>
45 #endif  /* __ FreeBSD__ */
46 #include <sys/buf.h>
47 #include <sys/queue.h>
48 #include <sys/malloc.h>
49 #include <sys/errno.h>
50
51 #include <vm/vm.h>
52
53 #ifdef __NetBSD__
54 #include <sys/device.h>
55
56 #include <machine/bus.h>
57 #include <machine/intr.h>
58
59 #include <dev/scsipi/scsi_all.h>
60 #include <dev/scsipi/scsipi_all.h>
61 #include <dev/scsipi/scsiconf.h>
62 #include <dev/scsipi/scsi_disk.h>
63
64 #include <machine/dvcfg.h>
65 #include <machine/physio_proc.h>
66
67 #include <i386/Cbus/dev/scsi_low.h>
68
69 #include <dev/ic/wd33c93reg.h>
70 #include <i386/Cbus/dev/ct/ctvar.h>
71 #include <i386/Cbus/dev/ct/ct_machdep.h>
72 #include <i386/Cbus/dev/ct/bshwvar.h>
73 #endif /* __NetBSD__ */
74
75 #ifdef __FreeBSD__
76 #include <machine/bus.h>
77 #include <machine/clock.h>
78 #include <machine/md_var.h>
79
80 #include <machine/dvcfg.h>
81 #include <machine/physio_proc.h>
82
83 #include <bus/cam/scsi/scsi_low.h>
84
85 #include <dev/ic/wd33c93reg.h>
86 #include "ctvar.h"
87 #include "ct_machdep.h"
88 #include "bshwvar.h"
89
90 #include <vm/pmap.h>
91 #endif /* __FreeBSD__ */
92
93 #define BSHW_IO_CONTROL_FLAGS   0
94
95 u_int bshw_io_control = BSHW_IO_CONTROL_FLAGS;
96 int bshw_data_read_bytes = 4096;
97 int bshw_data_write_bytes = 4096;
98
99 /*********************************************************
100  * OS dep part
101  *********************************************************/
102 #ifdef  __NetBSD__
103 #define BSHW_PAGE_SIZE NBPG
104 #endif  /* __NetBSD__ */
105
106 #ifdef  __FreeBSD__
107 #define BSHW_PAGE_SIZE PAGE_SIZE
108 typedef unsigned long vaddr_t;
109 #endif /* __FreeBSD__ */
110
111 /*********************************************************
112  * GENERIC MACHDEP FUNCTIONS
113  *********************************************************/
114 void
115 bshw_synch_setup(ct, ti)
116         struct ct_softc *ct;
117         struct targ_info *ti;
118 {
119         struct ct_bus_access_handle *chp = &ct->sc_ch;
120         struct ct_targ_info *cti = (void *) ti;
121         struct bshw_softc *bs = ct->ct_hw;
122         struct bshw *hw = bs->sc_hw;
123
124         if (hw->hw_sregaddr == 0)
125                 return;
126
127         ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id, cti->cti_syncreg);
128         if (hw->hw_flags & BSHW_DOUBLE_DMACHAN)
129         {
130                 ct_cr_write_1(chp, hw->hw_sregaddr + ti->ti_id + 8, 
131                               cti->cti_syncreg);
132         }
133 }
134
135 void
136 bshw_bus_reset(ct)
137         struct ct_softc *ct;
138 {
139         struct scsi_low_softc *slp = &ct->sc_sclow;
140         struct ct_bus_access_handle *chp = &ct->sc_ch;
141         struct bshw_softc *bs = ct->ct_hw;
142         struct bshw *hw = bs->sc_hw;
143         bus_addr_t offs;
144         u_int8_t regv;
145         int i;
146
147         /* open hardware busmaster mode */
148         if (hw->hw_dma_init != NULL && ((*hw->hw_dma_init)(ct)) != 0)
149         {
150                 printf("%s: change mode using external DMA (%x)\n",
151                     slp->sl_xname, (u_int)ct_cr_read_1(chp, 0x37));
152         }
153
154         /* clear hardware synch registers */
155         offs = hw->hw_sregaddr;
156         if (offs != 0)
157         {
158                 for (i = 0; i < 8; i ++, offs ++)
159                 {
160                         ct_cr_write_1(chp, offs, 0);
161                         if ((hw->hw_flags & BSHW_DOUBLE_DMACHAN) != 0)
162                                 ct_cr_write_1(chp, offs + 8, 0);
163                 }
164         }
165
166         /* disable interrupt & assert reset */
167         regv = ct_cr_read_1(chp, wd3s_mbank);
168         regv |= MBR_RST;
169         regv &= ~MBR_IEN;
170         ct_cr_write_1(chp, wd3s_mbank, regv);
171
172         SCSI_LOW_DELAY(500000);
173
174         /* reset signal off */
175         regv &= ~MBR_RST;
176         ct_cr_write_1(chp, wd3s_mbank, regv);
177
178         /* interrupt enable */
179         regv |= MBR_IEN;
180         ct_cr_write_1(chp, wd3s_mbank, regv);
181 }
182
183 /* probe */
184 int
185 bshw_read_settings(chp, bs)
186         struct ct_bus_access_handle *chp;
187         struct bshw_softc *bs;
188 {
189         static int irq_tbl[] = { 3, 5, 6, 9, 12, 13 };
190
191         bs->sc_hostid = (ct_cr_read_1(chp, wd3s_auxc) & AUXCR_HIDM);
192         bs->sc_irq = irq_tbl[(ct_cr_read_1(chp, wd3s_auxc) >> 3) & 7];
193         bs->sc_drq = ct_cmdp_read_1(chp) & 3;
194         return 0;
195 }
196
197 /*********************************************************
198  * DMA PIO TRANSFER (SMIT)
199  *********************************************************/
200 #define LC_SMIT_TIMEOUT 2       /* 2 sec: timeout for a fifo status ready */
201 #define LC_SMIT_OFFSET  0x1000
202 #define LC_FSZ          DEV_BSIZE
203 #define LC_SFSZ         0x0c
204 #define LC_REST         (LC_FSZ - LC_SFSZ)
205
206 #define BSHW_LC_FSET    0x36
207 #define BSHW_LC_FCTRL   0x44
208 #define FCTRL_EN        0x01
209 #define FCTRL_WRITE     0x02
210
211 #define SF_ABORT        0x08
212 #define SF_RDY          0x10
213
214 static __inline void bshw_lc_smit_start __P((struct ct_softc *, int, u_int));
215 static __inline void bshw_lc_smit_stop __P((struct ct_softc *));
216 static int bshw_lc_smit_fstat __P((struct ct_softc *, int, int));
217
218 static __inline void
219 bshw_lc_smit_stop(ct)
220         struct ct_softc *ct;
221 {
222         struct ct_bus_access_handle *chp = &ct->sc_ch;
223
224         ct_cr_write_1(chp, BSHW_LC_FCTRL, 0);
225         ct_cmdp_write_1(chp, CMDP_DMER);
226 }
227
228 static __inline void
229 bshw_lc_smit_start(ct, count, direction)
230         struct ct_softc *ct;
231         int count;
232         u_int direction;
233 {
234         struct ct_bus_access_handle *chp = &ct->sc_ch;
235         u_int8_t pval, val;
236
237         val = ct_cr_read_1(chp, BSHW_LC_FSET);
238         cthw_set_count(chp, count);
239
240         pval = FCTRL_EN;
241         if (direction == SCSI_LOW_WRITE)
242                 pval |= (val & 0xe0) | FCTRL_WRITE;
243         ct_cr_write_1(chp, BSHW_LC_FCTRL, pval);
244         ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
245 }
246
247 static int
248 bshw_lc_smit_fstat(ct, wc, read)
249         struct ct_softc *ct;
250         int wc, read;
251 {
252         struct ct_bus_access_handle *chp = &ct->sc_ch;
253         u_int8_t stat;
254
255         while (wc -- > 0)
256         {
257                 chp->ch_bus_weight(chp);
258                 stat = ct_cmdp_read_1(chp);
259                 if (read == SCSI_LOW_READ)
260                 {
261                         if ((stat & SF_RDY) != 0)
262                                 return 0;
263                         if ((stat & SF_ABORT) != 0)
264                                 return EIO;
265                 }
266                 else
267                 {
268                         if ((stat & SF_ABORT) != 0)
269                                 return EIO;
270                         if ((stat & SF_RDY) != 0)
271                                 return 0;
272                 }
273         }
274
275         printf("%s: SMIT fifo status timeout\n", ct->sc_sclow.sl_xname);
276         return EIO;
277 }
278
279 void
280 bshw_smit_xfer_stop(ct)
281         struct ct_softc *ct;
282 {
283         struct scsi_low_softc *slp = &ct->sc_sclow;
284         struct bshw_softc *bs = ct->ct_hw;
285         struct targ_info *ti;
286         struct sc_p *sp = &slp->sl_scp;
287         u_int count;
288
289         bshw_lc_smit_stop(ct);
290
291         ti = slp->sl_Tnexus;
292         if (ti == NULL)
293                 return;
294
295         if (ti->ti_phase == PH_DATA)
296         {
297                 count = cthw_get_count(&ct->sc_ch);
298                 if (count < bs->sc_sdatalen)
299                 {
300                         if (sp->scp_direction == SCSI_LOW_READ &&
301                             count != bs->sc_edatalen)
302                                 goto bad;
303
304                         count = bs->sc_sdatalen - count;
305                         if (count > (u_int) sp->scp_datalen)
306                                 goto bad;
307
308                         sp->scp_data += count;
309                         sp->scp_datalen -= count;
310                 }
311                 else if (count > bs->sc_sdatalen)
312                 {
313 bad:
314                         printf("%s: smit_xfer_end: cnt error\n", slp->sl_xname);
315                         slp->sl_error |= PDMAERR;
316                 }
317                 scsi_low_data_finish(slp);
318         }
319         else
320         {
321                 printf("%s: smit_xfer_end: phase miss\n", slp->sl_xname);
322                 slp->sl_error |= PDMAERR;
323         }
324 }
325
326 int
327 bshw_smit_xfer_start(ct)
328         struct ct_softc *ct;
329 {
330         struct scsi_low_softc *slp = &ct->sc_sclow;
331         struct ct_bus_access_handle *chp = &ct->sc_ch;
332         struct bshw_softc *bs = ct->ct_hw;
333         struct sc_p *sp = &slp->sl_scp;
334         struct targ_info *ti = slp->sl_Tnexus;
335         struct ct_targ_info *cti = (void *) ti;
336         u_int datalen, count, io_control;
337         int wc;
338         u_int8_t *data;
339
340         io_control = bs->sc_io_control | bshw_io_control;
341         if ((io_control & BSHW_SMIT_BLOCK) != 0)
342                 return EINVAL;
343
344         if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0)
345                 return EINVAL;
346
347         datalen = sp->scp_datalen;
348         if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
349         {
350                 if ((io_control & BSHW_READ_INTERRUPT_DRIVEN) != 0 &&
351                      datalen > bshw_data_read_bytes)
352                         datalen = bshw_data_read_bytes;
353         }
354         else 
355         {
356                 if ((io_control & BSHW_WRITE_INTERRUPT_DRIVEN) != 0 &&
357                     datalen > bshw_data_write_bytes)
358                         datalen = bshw_data_write_bytes;
359         }
360
361         bs->sc_sdatalen = datalen;
362         data = sp->scp_data;
363         wc = LC_SMIT_TIMEOUT * 1024 * 1024;
364
365         ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
366         bshw_lc_smit_start(ct, datalen, sp->scp_direction);
367
368         if (sp->scp_direction == SCSI_LOW_READ)
369         {
370                 do
371                 {
372                         if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_READ))
373                                 break;
374
375                         count = (datalen > LC_FSZ ? LC_FSZ : datalen);
376                         bus_space_read_region_4(chp->ch_memt, chp->ch_memh,
377                                 LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2);
378                         data += count;
379                         datalen -= count;
380                 }
381                 while (datalen > 0);
382
383                 bs->sc_edatalen = datalen;
384         }
385         else
386         {
387                 do
388                 {
389                         if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE))
390                                 break;
391                         if (cti->cti_syncreg == 0)
392                         {
393                                 /* XXX:
394                                  * If async transfer, reconfirm a scsi phase
395                                  * again. Unless C bus might hang up.
396                                  */
397                                 if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE))
398                                         break;
399                         }
400
401                         count = (datalen > LC_SFSZ ? LC_SFSZ : datalen);
402                         bus_space_write_region_4(chp->ch_memt, chp->ch_memh,
403                                 LC_SMIT_OFFSET, (u_int32_t *) data, count >> 2);
404                         data += count;
405                         datalen -= count;
406
407                         if (bshw_lc_smit_fstat(ct, wc, SCSI_LOW_WRITE))
408                                 break;
409
410                         count = (datalen > LC_REST ? LC_REST : datalen);
411                         bus_space_write_region_4(chp->ch_memt, chp->ch_memh,
412                                                  LC_SMIT_OFFSET + LC_SFSZ, 
413                                                  (u_int32_t *) data, count >> 2);
414                         data += count;
415                         datalen -= count;
416                 }
417                 while (datalen > 0);
418         }
419         return 0;
420 }
421
422 /*********************************************************
423  * DMA TRANSFER (BS)
424  *********************************************************/
425 static __inline void bshw_dma_write_1 \
426         __P((struct ct_bus_access_handle *, bus_addr_t, u_int8_t));
427 static void bshw_dmastart __P((struct ct_softc *));
428 static void bshw_dmadone __P((struct ct_softc *));
429
430 int
431 bshw_dma_xfer_start(ct)
432         struct ct_softc *ct;
433 {
434         struct scsi_low_softc *slp = &ct->sc_sclow;
435         struct sc_p *sp = &slp->sl_scp;
436         struct ct_bus_access_handle *chp = &ct->sc_ch;
437         struct bshw_softc *bs = ct->ct_hw;
438         vaddr_t va, endva, phys, nphys;
439         u_int io_control;
440
441         io_control = bs->sc_io_control | bshw_io_control;
442         if ((io_control & BSHW_DMA_BLOCK) != 0 && sp->scp_datalen < 256)
443                 return EINVAL;
444
445         ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
446         phys = vtophys((vaddr_t) sp->scp_data);
447         if (phys >= bs->sc_minphys)
448         {
449                 /* setup segaddr */
450                 bs->sc_segaddr = bs->sc_bounce_phys;
451                 /* setup seglen */
452                 bs->sc_seglen = sp->scp_datalen;
453                 if (bs->sc_seglen > bs->sc_bounce_size)
454                         bs->sc_seglen = bs->sc_bounce_size;
455                 /* setup bufp */
456                 bs->sc_bufp = bs->sc_bounce_addr;
457                 if (sp->scp_direction == SCSI_LOW_WRITE)
458                         bcopy(sp->scp_data, bs->sc_bufp, bs->sc_seglen);
459         }
460         else
461         {
462                 /* setup segaddr */
463                 bs->sc_segaddr = (u_int8_t *) phys;
464                 /* setup seglen */
465                 endva = (vaddr_t) round_page((vaddr_t) sp->scp_data + sp->scp_datalen);
466                 for (va = (vaddr_t) sp->scp_data; ; phys = nphys)
467                 {
468                         if ((va += BSHW_PAGE_SIZE) >= endva)
469                         {
470                                 bs->sc_seglen = sp->scp_datalen;
471                                 break;
472                         }
473
474                         nphys = vtophys(va);
475                         if (phys + BSHW_PAGE_SIZE != nphys || nphys >= bs->sc_minphys)
476                         {
477                                 bs->sc_seglen =
478                                     (u_int8_t *) trunc_page(va) - sp->scp_data;
479                                 break;
480                         }
481                 }
482                 /* setup bufp */
483                 bs->sc_bufp = NULL;
484         }
485
486         bshw_dmastart(ct);
487         cthw_set_count(chp, bs->sc_seglen);
488         ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
489         return 0;
490 }
491
492 void
493 bshw_dma_xfer_stop(ct)
494         struct ct_softc *ct;
495 {
496         struct scsi_low_softc *slp = &ct->sc_sclow;
497         struct sc_p *sp = &slp->sl_scp;
498         struct bshw_softc *bs = ct->ct_hw;
499         struct targ_info *ti;
500         u_int count, transbytes;
501
502         bshw_dmadone(ct);
503
504         ti = slp->sl_Tnexus;
505         if (ti == NULL)
506                 return;
507
508         if (ti->ti_phase == PH_DATA)
509         {
510                 count = cthw_get_count(&ct->sc_ch);
511                 if (count < (u_int) bs->sc_seglen)
512                 {
513                         transbytes = bs->sc_seglen - count;
514                         if (bs->sc_bufp != NULL &&
515                             sp->scp_direction == SCSI_LOW_READ)
516                                 bcopy(bs->sc_bufp, sp->scp_data, transbytes);
517
518                         sp->scp_data += transbytes;
519                         sp->scp_datalen -= transbytes;
520                 }
521                 else if (count > (u_int) bs->sc_seglen)
522                 {
523                         printf("%s: port data %x != seglen %x\n",
524                                 slp->sl_xname, count, bs->sc_seglen);
525                         slp->sl_error |= PDMAERR;
526                 }
527
528                 scsi_low_data_finish(slp);
529         }
530         else
531         {
532                 printf("%s: extra DMA interrupt\n", slp->sl_xname);
533                 slp->sl_error |= PDMAERR;
534         }
535
536         bs->sc_bufp = NULL;
537 }
538
539 /* common dma settings */
540 #undef  DMA1_SMSK
541 #define DMA1_SMSK       (0x15)
542 #undef  DMA1_MODE
543 #define DMA1_MODE       (0x17)
544 #undef  DMA1_FFC
545 #define DMA1_FFC        (0x19)
546 #undef  DMA1_CHN
547 #define DMA1_CHN(c)     (0x01 + ((c) << 2))
548
549 #define DMA37SM_SET     0x04
550 #define DMA37MD_WRITE   0x04
551 #define DMA37MD_READ    0x08
552 #define DMA37MD_SINGLE  0x40
553
554 static bus_addr_t dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 };
555
556 static __inline void 
557 bshw_dma_write_1(chp, port, val)
558         struct ct_bus_access_handle *chp;
559         bus_addr_t port;
560         u_int8_t val;
561 {
562
563         CT_BUS_WEIGHT(chp);
564         outb(port, val);
565 }
566
567 static void
568 bshw_dmastart(ct)
569         struct ct_softc *ct;
570 {
571         struct scsi_low_softc *slp = &ct->sc_sclow;
572         struct bshw_softc *bs = ct->ct_hw;
573         struct ct_bus_access_handle *chp = &ct->sc_ch;
574         int chan = bs->sc_drq;
575         bus_addr_t waport;
576         u_int8_t regv, *phys = bs->sc_segaddr;
577         u_int nbytes = bs->sc_seglen;
578
579         /* flush cpu cache */
580         (*bs->sc_dmasync_before) (ct);
581
582         /*
583          * Program one of DMA channels 0..3. These are
584          * byte mode channels.
585          */
586         /* set dma channel mode, and reset address ff */
587
588         if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
589                 regv = DMA37MD_WRITE | DMA37MD_SINGLE | chan;
590         else
591                 regv = DMA37MD_READ | DMA37MD_SINGLE | chan;
592
593         bshw_dma_write_1(chp, DMA1_MODE, regv);
594         bshw_dma_write_1(chp, DMA1_FFC, 0);
595
596         /* send start address */
597         waport = DMA1_CHN(chan);
598         bshw_dma_write_1(chp, waport, (u_int) phys);
599         bshw_dma_write_1(chp, waport, ((u_int) phys) >> 8);
600         bshw_dma_write_1(chp, dmapageport[chan], ((u_int) phys) >> 16);
601
602         /* send count */
603         bshw_dma_write_1(chp, waport + 2, --nbytes);
604         bshw_dma_write_1(chp, waport + 2, nbytes >> 8);
605
606         /* vendor unique hook */
607         if (bs->sc_hw->hw_dma_start)
608                 (*bs->sc_hw->hw_dma_start)(ct);
609
610         bshw_dma_write_1(chp, DMA1_SMSK, chan);
611         ct_cmdp_write_1(chp, CMDP_DMES);
612 }
613
614 static void
615 bshw_dmadone(ct)
616         struct ct_softc *ct;
617 {
618         struct bshw_softc *bs = ct->ct_hw;
619         struct ct_bus_access_handle *chp = &ct->sc_ch;
620
621         bshw_dma_write_1(chp, DMA1_SMSK, (bs->sc_drq | DMA37SM_SET));
622         ct_cmdp_write_1(chp, CMDP_DMER);
623
624         /* vendor unique hook */
625         if (bs->sc_hw->hw_dma_stop)
626                 (*bs->sc_hw->hw_dma_stop) (ct);
627
628         /* flush cpu cache */
629         (*bs->sc_dmasync_after) (ct);
630 }
631
632 /**********************************************
633  * VENDOR UNIQUE DMA FUNCS
634  **********************************************/
635 static int bshw_dma_init_sc98 __P((struct ct_softc *));
636 static void bshw_dma_start_sc98 __P((struct ct_softc *));
637 static void bshw_dma_stop_sc98 __P((struct ct_softc *));
638 static int bshw_dma_init_texa __P((struct ct_softc *));
639 static void bshw_dma_start_elecom __P((struct ct_softc *));
640 static void bshw_dma_stop_elecom __P((struct ct_softc *));
641
642 static int
643 bshw_dma_init_texa(ct)
644         struct ct_softc *ct;
645 {
646         struct ct_bus_access_handle *chp = &ct->sc_ch;
647         u_int8_t regval;
648
649         if ((regval = ct_cr_read_1(chp, 0x37)) & 0x08)
650                 return 0;
651
652         ct_cr_write_1(chp, 0x37, regval | 0x08);
653         regval = ct_cr_read_1(chp, 0x3f);
654         ct_cr_write_1(chp, 0x3f, regval | 0x08);
655         return 1;
656 }
657
658 static int
659 bshw_dma_init_sc98(ct)
660         struct ct_softc *ct;
661 {
662         struct ct_bus_access_handle *chp = &ct->sc_ch;
663
664         if (ct_cr_read_1(chp, 0x37) & 0x08)
665                 return 0;
666
667         /* If your card is SC98 with bios ver 1.01 or 1.02 under no PCI */
668         ct_cr_write_1(chp, 0x37, 0x1a);
669         ct_cr_write_1(chp, 0x3f, 0x1a);
670 #if     0
671         /* only valid for IO */
672         ct_cr_write_1(chp, 0x40, 0xf4);
673         ct_cr_write_1(chp, 0x41, 0x9);
674         ct_cr_write_1(chp, 0x43, 0xff);
675         ct_cr_write_1(chp, 0x46, 0x4e);
676
677         ct_cr_write_1(chp, 0x48, 0xf4);
678         ct_cr_write_1(chp, 0x49, 0x9);
679         ct_cr_write_1(chp, 0x4b, 0xff);
680         ct_cr_write_1(chp, 0x4e, 0x4e);
681 #endif
682         return 1;
683 }
684
685 static void
686 bshw_dma_start_sc98(ct)
687         struct ct_softc *ct;
688 {
689         struct ct_bus_access_handle *chp = &ct->sc_ch;
690
691         ct_cr_write_1(chp, 0x73, 0x32);
692         ct_cr_write_1(chp, 0x74, 0x23);
693 }
694
695 static void
696 bshw_dma_stop_sc98(ct)
697         struct ct_softc *ct;
698 {
699         struct ct_bus_access_handle *chp = &ct->sc_ch;
700
701         ct_cr_write_1(chp, 0x73, 0x43);
702         ct_cr_write_1(chp, 0x74, 0x34);
703 }
704
705 static void
706 bshw_dma_start_elecom(ct)
707         struct ct_softc *ct;
708 {
709         struct ct_bus_access_handle *chp = &ct->sc_ch;
710         u_int8_t tmp = ct_cr_read_1(chp, 0x4c);
711
712         ct_cr_write_1(chp, 0x32, tmp & 0xdf);
713 }
714
715 static void
716 bshw_dma_stop_elecom(ct)
717         struct ct_softc *ct;
718 {
719         struct ct_bus_access_handle *chp = &ct->sc_ch;
720         u_int8_t tmp = ct_cr_read_1(chp, 0x4c);
721
722         ct_cr_write_1(chp, 0x32, tmp | 0x20);
723 }
724
725 static struct bshw bshw_generic = {
726         BSHW_SYNC_RELOAD,
727
728         0,
729
730         NULL,
731         NULL,
732         NULL,
733 };
734
735 static struct bshw bshw_sc98 = {
736         BSHW_DOUBLE_DMACHAN,
737
738         0x60,
739
740         bshw_dma_init_sc98,
741         bshw_dma_start_sc98,
742         bshw_dma_stop_sc98,
743 };
744
745 static struct bshw bshw_texa = {
746         BSHW_DOUBLE_DMACHAN,
747
748         0x60,
749
750         bshw_dma_init_texa,
751         NULL,
752         NULL,
753 };
754
755 static struct bshw bshw_elecom = {
756         0,
757
758         0x38,
759
760         NULL,
761         bshw_dma_start_elecom,
762         bshw_dma_stop_elecom,
763 };
764
765 static struct bshw bshw_lc_smit = {
766         BSHW_SMFIFO | BSHW_DOUBLE_DMACHAN,
767
768         0x60,
769
770         NULL,
771         NULL,
772         NULL,
773 };
774
775 static struct bshw bshw_lha20X = {
776         BSHW_DOUBLE_DMACHAN,
777
778         0x60,
779
780         NULL,
781         NULL,
782         NULL,
783 };
784
785 /* hw tabs */
786 static dvcfg_hw_t bshw_hwsel_array[] = {
787 /* 0x00 */      &bshw_generic,
788 /* 0x01 */      &bshw_sc98,
789 /* 0x02 */      &bshw_texa,
790 /* 0x03 */      &bshw_elecom,
791 /* 0x04 */      &bshw_lc_smit,
792 /* 0x05 */      &bshw_lha20X,
793 };
794
795 struct dvcfg_hwsel bshw_hwsel = {
796         DVCFG_HWSEL_SZ(bshw_hwsel_array),
797         bshw_hwsel_array
798 };