Home | History | Annotate | Line # | Download | only in maple
mlcd.c revision 1.1
      1  1.1  itohy /*	$NetBSD: mlcd.c,v 1.1 2002/11/15 14:10:51 itohy Exp $	*/
      2  1.1  itohy 
      3  1.1  itohy /*-
      4  1.1  itohy  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  1.1  itohy  * All rights reserved.
      6  1.1  itohy  *
      7  1.1  itohy  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1  itohy  * by ITOH Yasufumi.
      9  1.1  itohy  *
     10  1.1  itohy  * Redistribution and use in source and binary forms, with or without
     11  1.1  itohy  * modification, are permitted provided that the following conditions
     12  1.1  itohy  * are met:
     13  1.1  itohy  * 1. Redistributions of source code must retain the above copyright
     14  1.1  itohy  *    notice, this list of conditions and the following disclaimer.
     15  1.1  itohy  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1  itohy  *    notice, this list of conditions and the following disclaimer in the
     17  1.1  itohy  *    documentation and/or other materials provided with the distribution.
     18  1.1  itohy  * 3. All advertising materials mentioning features or use of this software
     19  1.1  itohy  *    must display the following acknowledgement:
     20  1.1  itohy  *	This product includes software developed by the NetBSD
     21  1.1  itohy  *	Foundation, Inc. and its contributors.
     22  1.1  itohy  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  1.1  itohy  *    contributors may be used to endorse or promote products derived
     24  1.1  itohy  *    from this software without specific prior written permission.
     25  1.1  itohy  *
     26  1.1  itohy  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  1.1  itohy  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  1.1  itohy  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  1.1  itohy  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  1.1  itohy  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  1.1  itohy  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  1.1  itohy  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  1.1  itohy  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  1.1  itohy  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  1.1  itohy  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  1.1  itohy  * POSSIBILITY OF SUCH DAMAGE.
     37  1.1  itohy  */
     38  1.1  itohy 
     39  1.1  itohy #include <sys/param.h>
     40  1.1  itohy #include <sys/buf.h>
     41  1.1  itohy #include <sys/device.h>
     42  1.1  itohy #include <sys/kernel.h>
     43  1.1  itohy #include <sys/malloc.h>
     44  1.1  itohy #include <sys/proc.h>
     45  1.1  itohy #include <sys/systm.h>
     46  1.1  itohy #include <sys/vnode.h>
     47  1.1  itohy #include <sys/conf.h>
     48  1.1  itohy 
     49  1.1  itohy #include <dreamcast/dev/maple/maple.h>
     50  1.1  itohy #include <dreamcast/dev/maple/mapleconf.h>
     51  1.1  itohy 
     52  1.1  itohy #define MLCD_MAXACCSIZE	1012	/* (255*4) - 8  =  253*32 / 8 */
     53  1.1  itohy 
     54  1.1  itohy struct mlcd_funcdef {	/* XXX assuming little-endian structure packing */
     55  1.1  itohy 	unsigned unused	: 6,
     56  1.1  itohy 		 bw	: 1,	/* 0: normally white, 1: normally black */
     57  1.1  itohy 		 hv	: 1,	/* 0: horizontal, 1: vertical */
     58  1.1  itohy 		 ra	: 4,	/* 0 */
     59  1.1  itohy 		 wa	: 4,	/* number of access / write */
     60  1.1  itohy 		 bb	: 8,	/* block size / 32 - 1 */
     61  1.1  itohy 		 pt	: 8;	/* number of partition - 1 */
     62  1.1  itohy };
     63  1.1  itohy 
     64  1.1  itohy struct mlcd_request_write_data {
     65  1.1  itohy 	u_int32_t	func_code;
     66  1.1  itohy 	u_int8_t	pt;
     67  1.1  itohy 	u_int8_t	phase;		/* 0, 1, 2, 3: for each 128 byte */
     68  1.1  itohy 	u_int16_t	block;
     69  1.1  itohy 	u_int8_t	data[MLCD_MAXACCSIZE];
     70  1.1  itohy };
     71  1.1  itohy #define MLCD_SIZE_REQW(sc)	((sc)->sc_waccsz + 8)
     72  1.1  itohy 
     73  1.1  itohy struct mlcd_request_get_media_info {
     74  1.1  itohy 	u_int32_t	func_code;
     75  1.1  itohy 	u_int32_t	pt;		/* pt (1 byte) and unused 3 bytes */
     76  1.1  itohy };
     77  1.1  itohy 
     78  1.1  itohy struct mlcd_media_info {
     79  1.1  itohy 	u_int8_t	width;		/* width - 1 */
     80  1.1  itohy 	u_int8_t	height;		/* height - 1 */
     81  1.1  itohy 	u_int8_t	rsvd[2];	/* ? 0x10 0x02 */
     82  1.1  itohy };
     83  1.1  itohy 
     84  1.1  itohy struct mlcd_response_media_info {
     85  1.1  itohy 	u_int32_t	func_code;	/* function code (big endian) */
     86  1.1  itohy 	struct mlcd_media_info info;
     87  1.1  itohy };
     88  1.1  itohy 
     89  1.1  itohy struct mlcd_softc {
     90  1.1  itohy 	struct device	sc_dev;
     91  1.1  itohy 
     92  1.1  itohy 	struct device	*sc_parent;
     93  1.1  itohy 	struct maple_unit *sc_unit;
     94  1.1  itohy 	enum mlcd_stat {
     95  1.1  itohy 		MLCD_INIT,	/* during initialization */
     96  1.1  itohy 		MLCD_INIT2,	/* during initialization */
     97  1.1  itohy 		MLCD_IDLE,	/* init done, not in I/O */
     98  1.1  itohy 		MLCD_WRITE,	/* in write operation */
     99  1.1  itohy 		MLCD_DETACH	/* detaching */
    100  1.1  itohy 	} sc_stat;
    101  1.1  itohy 
    102  1.1  itohy 	int		sc_npt;		/* number of partitions */
    103  1.1  itohy 	int		sc_bsize;	/* block size */
    104  1.1  itohy 	int		sc_wacc;	/* number of write access per block */
    105  1.1  itohy 	int		sc_waccsz;	/* size of a write access */
    106  1.1  itohy 
    107  1.1  itohy 	struct mlcd_pt {
    108  1.1  itohy 		int		pt_flags;
    109  1.1  itohy #define MLCD_PT_OK	1	/* partition is alive */
    110  1.1  itohy #define MLCD_PT_OPEN	2
    111  1.1  itohy 		struct mlcd_media_info pt_info;	/* geometry per part */
    112  1.1  itohy 		int		pt_size;	/* partition size in byte */
    113  1.1  itohy 		int		pt_nblk;	/* partition size on block */
    114  1.1  itohy 
    115  1.1  itohy 		char		pt_name[16 /* see device.h */ + 4 /* ".256" */];
    116  1.1  itohy 	} *sc_pt;
    117  1.1  itohy 
    118  1.1  itohy 	/* write request buffer (only one is used at a time) */
    119  1.1  itohy 	union {
    120  1.1  itohy 		struct mlcd_request_write_data req_write;
    121  1.1  itohy 		struct mlcd_request_get_media_info req_minfo;
    122  1.1  itohy 	} sc_req;
    123  1.1  itohy #define sc_reqw	sc_req.req_write
    124  1.1  itohy #define sc_reqm	sc_req.req_minfo
    125  1.1  itohy 
    126  1.1  itohy 	/* pending buffers */
    127  1.1  itohy 	struct bufq_state sc_q;
    128  1.1  itohy 
    129  1.1  itohy 	/* current I/O access */
    130  1.1  itohy 	struct buf	*sc_bp;
    131  1.1  itohy 	int		sc_retry;
    132  1.1  itohy #define MLCD_MAXRETRY	10
    133  1.1  itohy };
    134  1.1  itohy 
    135  1.1  itohy /*
    136  1.1  itohy  * minor number layout (mlcddetach() depends on this layout):
    137  1.1  itohy  *
    138  1.1  itohy  * 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
    139  1.1  itohy  * |---------------------------------| |---------------------|
    140  1.1  itohy  *                unit                          part
    141  1.1  itohy  */
    142  1.1  itohy #define MLCD_PART(dev)		(minor(dev) & 0xff)
    143  1.1  itohy #define MLCD_UNIT(dev)		(minor(dev) >> 8)
    144  1.1  itohy #define MLCD_MINOR(unit, part)	(((unit) << 8) | (part))
    145  1.1  itohy 
    146  1.1  itohy static int	mlcdmatch __P((struct device *, struct cfdata *, void *));
    147  1.1  itohy static void	mlcdattach __P((struct device *, struct device *, void *));
    148  1.1  itohy static int	mlcddetach __P((struct device *, int));
    149  1.1  itohy static void	mlcd_intr __P((void *, struct maple_response *, int, int));
    150  1.1  itohy static void	mlcd_printerror __P((const char *, u_int32_t));
    151  1.1  itohy static void	mlcdstart __P((struct mlcd_softc *));
    152  1.1  itohy static void	mlcdstart_bp __P((struct mlcd_softc *, struct buf *bp));
    153  1.1  itohy static void	mlcddone __P((struct mlcd_softc *));
    154  1.1  itohy 
    155  1.1  itohy dev_type_open(mlcdopen);
    156  1.1  itohy dev_type_close(mlcdclose);
    157  1.1  itohy dev_type_write(mlcdwrite);
    158  1.1  itohy dev_type_ioctl(mlcdioctl);
    159  1.1  itohy dev_type_strategy(mlcdstrategy);
    160  1.1  itohy 
    161  1.1  itohy const struct cdevsw mlcd_cdevsw = {
    162  1.1  itohy 	mlcdopen, mlcdclose, noread, mlcdwrite, mlcdioctl,
    163  1.1  itohy 	nostop, notty, nopoll, nommap, nokqfilter
    164  1.1  itohy };
    165  1.1  itohy 
    166  1.1  itohy CFATTACH_DECL(mlcd, sizeof(struct mlcd_softc),
    167  1.1  itohy     mlcdmatch, mlcdattach, mlcddetach, NULL);
    168  1.1  itohy 
    169  1.1  itohy extern struct cfdriver mlcd_cd;
    170  1.1  itohy 
    171  1.1  itohy /* initial image "NetBSD dreamcast" */
    172  1.1  itohy static const char initimg48x32[192] = {
    173  1.1  itohy 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    174  1.1  itohy 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    175  1.1  itohy 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    176  1.1  itohy 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    177  1.1  itohy 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    178  1.1  itohy 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xac, 0xe5, 0x56, 0x70, 0xb8,
    179  1.1  itohy 	0x14, 0x12, 0x15, 0x49, 0x08, 0xa4, 0x13, 0x1c, 0x15, 0x4e, 0x78, 0xa4,
    180  1.1  itohy 	0x10, 0x90, 0x15, 0x48, 0x49, 0xa4, 0x7b, 0x0c, 0xe3, 0xc6, 0x36, 0xb8,
    181  1.1  itohy 	0x10, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
    182  1.1  itohy 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    183  1.1  itohy 	0x07, 0xcf, 0x9f, 0xb8, 0x79, 0x8e, 0x19, 0x99, 0xb3, 0x6c, 0x8d, 0x8c,
    184  1.1  itohy 	0x31, 0xb1, 0x63, 0x4c, 0x0d, 0x8c, 0x31, 0xb0, 0x66, 0x18, 0x3b, 0x58,
    185  1.1  itohy 	0x63, 0x18, 0x66, 0x19, 0xdb, 0x58, 0x63, 0x0c, 0x3e, 0x7d, 0x93, 0x58,
    186  1.1  itohy 	0x63, 0x06, 0x46, 0x30, 0xe3, 0x78, 0x66, 0x66, 0xcc, 0x30, 0x06, 0x30,
    187  1.1  itohy 	0x36, 0x64, 0xcc, 0x00, 0x06, 0x30, 0x0f, 0x38, 0x7e, 0x00, 0x0e, 0x38,
    188  1.1  itohy 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    189  1.1  itohy };
    190  1.1  itohy 
    191  1.1  itohy static int
    192  1.1  itohy mlcdmatch(parent, cf, aux)
    193  1.1  itohy 	struct device *parent;
    194  1.1  itohy 	struct cfdata *cf;
    195  1.1  itohy 	void *aux;
    196  1.1  itohy {
    197  1.1  itohy 	struct maple_attach_args *ma = aux;
    198  1.1  itohy 
    199  1.1  itohy 	return (ma->ma_function == MAPLE_FN_LCD ? MAPLE_MATCH_FUNC : 0);
    200  1.1  itohy }
    201  1.1  itohy 
    202  1.1  itohy static void
    203  1.1  itohy mlcdattach(parent, self, aux)
    204  1.1  itohy 	struct device *parent, *self;
    205  1.1  itohy 	void *aux;
    206  1.1  itohy {
    207  1.1  itohy 	struct mlcd_softc *sc = (void *) self;
    208  1.1  itohy 	struct maple_attach_args *ma = aux;
    209  1.1  itohy 	int i;
    210  1.1  itohy 	union {
    211  1.1  itohy 		u_int32_t v;
    212  1.1  itohy 		struct mlcd_funcdef s;
    213  1.1  itohy 	} funcdef;
    214  1.1  itohy 
    215  1.1  itohy 	sc->sc_parent = parent;
    216  1.1  itohy 	sc->sc_unit = ma->ma_unit;
    217  1.1  itohy 
    218  1.1  itohy 	funcdef.v = maple_get_function_data(ma->ma_devinfo, MAPLE_FN_LCD);
    219  1.1  itohy 	printf(": LCD display\n");
    220  1.1  itohy 	printf("%s: %d LCD, %d bytes/block, ",
    221  1.1  itohy 	    sc->sc_dev.dv_xname,
    222  1.1  itohy 	    sc->sc_npt = funcdef.s.pt + 1,
    223  1.1  itohy 	    sc->sc_bsize = (funcdef.s.bb + 1) << 5);
    224  1.1  itohy 	if ((sc->sc_wacc = funcdef.s.wa) == 0)
    225  1.1  itohy 		printf("no ");
    226  1.1  itohy 	else
    227  1.1  itohy 		printf("%d acc/", sc->sc_wacc);
    228  1.1  itohy 	printf("write, %s, normally %s\n",
    229  1.1  itohy 	    funcdef.s.hv ? "vertical" : "horizontal",
    230  1.1  itohy 	    funcdef.s.bw ? "black" : "white");
    231  1.1  itohy 
    232  1.1  itohy 	/*
    233  1.1  itohy 	 * start init sequence
    234  1.1  itohy 	 */
    235  1.1  itohy 	sc->sc_stat = MLCD_INIT;
    236  1.1  itohy 	bufq_alloc(&sc->sc_q, BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK);
    237  1.1  itohy 
    238  1.1  itohy 	/* check consistency */
    239  1.1  itohy 	if (sc->sc_wacc != 0) {
    240  1.1  itohy 		sc->sc_waccsz = sc->sc_bsize / sc->sc_wacc;
    241  1.1  itohy 		if (sc->sc_bsize != sc->sc_waccsz * sc->sc_wacc) {
    242  1.1  itohy 			printf("%s: write access isn't equally divided\n",
    243  1.1  itohy 			    sc->sc_dev.dv_xname);
    244  1.1  itohy 			sc->sc_wacc = 0;	/* no write */
    245  1.1  itohy 		} else if (sc->sc_waccsz > MLCD_MAXACCSIZE) {
    246  1.1  itohy 			printf("%s: write access size is too large\n",
    247  1.1  itohy 			    sc->sc_dev.dv_xname);
    248  1.1  itohy 			sc->sc_wacc = 0;	/* no write */
    249  1.1  itohy 		}
    250  1.1  itohy 	}
    251  1.1  itohy 	if (sc->sc_wacc == 0) {
    252  1.1  itohy 		printf("%s: device doesn't support write\n",
    253  1.1  itohy 		    sc->sc_dev.dv_xname);
    254  1.1  itohy 		return;
    255  1.1  itohy 	}
    256  1.1  itohy 
    257  1.1  itohy 	/* per-part structure */
    258  1.1  itohy 	sc->sc_pt = malloc(sizeof(struct mlcd_pt) * sc->sc_npt, M_DEVBUF,
    259  1.1  itohy 	    M_WAITOK|M_ZERO);
    260  1.1  itohy 
    261  1.1  itohy 	for (i = 0; i < sc->sc_npt; i++) {
    262  1.1  itohy 		sprintf(sc->sc_pt[i].pt_name, "%s.%d", sc->sc_dev.dv_xname, i);
    263  1.1  itohy 	}
    264  1.1  itohy 
    265  1.1  itohy 	maple_set_callback(parent, sc->sc_unit, MAPLE_FN_LCD,
    266  1.1  itohy 	    mlcd_intr, sc);
    267  1.1  itohy 
    268  1.1  itohy 	/*
    269  1.1  itohy 	 * get size (start from partition 0)
    270  1.1  itohy 	 */
    271  1.1  itohy 	sc->sc_reqm.func_code = htonl(MAPLE_FUNC(MAPLE_FN_LCD));
    272  1.1  itohy 	sc->sc_reqm.pt = 0;
    273  1.1  itohy 	maple_command(sc->sc_parent, sc->sc_unit, MAPLE_FN_LCD,
    274  1.1  itohy 	    MAPLE_COMMAND_GETMINFO, sizeof sc->sc_reqm / 4, &sc->sc_reqm, 0);
    275  1.1  itohy }
    276  1.1  itohy 
    277  1.1  itohy static int
    278  1.1  itohy mlcddetach(self, flags)
    279  1.1  itohy 	struct device *self;
    280  1.1  itohy 	int flags;
    281  1.1  itohy {
    282  1.1  itohy 	struct mlcd_softc *sc = (struct mlcd_softc *) self;
    283  1.1  itohy 	struct buf *bp;
    284  1.1  itohy 	int minor_l, minor_h;
    285  1.1  itohy 
    286  1.1  itohy 	sc->sc_stat = MLCD_DETACH;	/* just in case */
    287  1.1  itohy 
    288  1.1  itohy 	/*
    289  1.1  itohy 	 * kill pending I/O
    290  1.1  itohy 	 */
    291  1.1  itohy 	if ((bp = sc->sc_bp) != NULL) {
    292  1.1  itohy 		bp->b_error = EIO;
    293  1.1  itohy 		bp->b_flags |= B_ERROR;
    294  1.1  itohy 		bp->b_resid = bp->b_bcount;
    295  1.1  itohy 		biodone(bp);
    296  1.1  itohy 	}
    297  1.1  itohy 	while ((bp = BUFQ_GET(&sc->sc_q)) != NULL) {
    298  1.1  itohy 		bp->b_error = EIO;
    299  1.1  itohy 		bp->b_flags |= B_ERROR;
    300  1.1  itohy 		bp->b_resid = bp->b_bcount;
    301  1.1  itohy 		biodone(bp);
    302  1.1  itohy 	}
    303  1.1  itohy 	bufq_free(&sc->sc_q);
    304  1.1  itohy 
    305  1.1  itohy 	/*
    306  1.1  itohy 	 * revoke vnodes
    307  1.1  itohy 	 */
    308  1.1  itohy 	minor_l = MLCD_MINOR(self->dv_unit, 0);
    309  1.1  itohy 	minor_h = MLCD_MINOR(self->dv_unit, sc->sc_npt - 1);
    310  1.1  itohy 	vdevgone(cdevsw_lookup_major(&mlcd_cdevsw), minor_l, minor_h, VCHR);
    311  1.1  itohy 
    312  1.1  itohy 	/*
    313  1.1  itohy 	 * free per-partition structure
    314  1.1  itohy 	 */
    315  1.1  itohy 	if (sc->sc_pt)
    316  1.1  itohy 		free(sc->sc_pt, M_DEVBUF);
    317  1.1  itohy 
    318  1.1  itohy 	return 0;
    319  1.1  itohy }
    320  1.1  itohy 
    321  1.1  itohy /*
    322  1.1  itohy  * called back from maple bus driver
    323  1.1  itohy  */
    324  1.1  itohy static void
    325  1.1  itohy mlcd_intr(dev, response, sz, flags)
    326  1.1  itohy 	void *dev;
    327  1.1  itohy 	struct maple_response *response;
    328  1.1  itohy 	int sz, flags;
    329  1.1  itohy {
    330  1.1  itohy 	struct mlcd_softc *sc = dev;
    331  1.1  itohy 	struct mlcd_response_media_info *rm = (void *) response->data;
    332  1.1  itohy 	struct buf *bp;
    333  1.1  itohy 	int part;
    334  1.1  itohy 	struct mlcd_pt *pt;
    335  1.1  itohy 
    336  1.1  itohy 	switch (sc->sc_stat) {
    337  1.1  itohy 	case MLCD_INIT:
    338  1.1  itohy 		/* checking part geometry */
    339  1.1  itohy 		part = sc->sc_reqm.pt;
    340  1.1  itohy 		pt = &sc->sc_pt[part];
    341  1.1  itohy 		switch ((maple_response_t) response->response_code) {
    342  1.1  itohy 		case MAPLE_RESPONSE_DATATRF:
    343  1.1  itohy 			pt->pt_info = rm->info;
    344  1.1  itohy 			pt->pt_size = ((pt->pt_info.width + 1) *
    345  1.1  itohy 			    (pt->pt_info.height + 1) + 7) / 8;
    346  1.1  itohy 			pt->pt_nblk = pt->pt_size / sc->sc_bsize;
    347  1.1  itohy 			printf("%s: %dx%d display, %d bytes\n",
    348  1.1  itohy 			    pt->pt_name,
    349  1.1  itohy 			    pt->pt_info.width + 1, pt->pt_info.height + 1,
    350  1.1  itohy 			    pt->pt_size);
    351  1.1  itohy 
    352  1.1  itohy 			/* this partition is active */
    353  1.1  itohy 			pt->pt_flags = MLCD_PT_OK;
    354  1.1  itohy 
    355  1.1  itohy 			break;
    356  1.1  itohy 		default:
    357  1.1  itohy 			printf("%s: init: unexpected response %#x, sz %d\n",
    358  1.1  itohy 			    pt->pt_name, ntohl(response->response_code), sz);
    359  1.1  itohy 			break;
    360  1.1  itohy 		}
    361  1.1  itohy 		if (++part == sc->sc_npt) {
    362  1.1  itohy 			/* init done */
    363  1.1  itohy 
    364  1.1  itohy 			/* XXX initial image for Visual Memory */
    365  1.1  itohy 			if (sc->sc_pt[0].pt_size == sizeof initimg48x32 &&
    366  1.1  itohy 			    sc->sc_waccsz == sizeof initimg48x32 &&
    367  1.1  itohy 			    sc->sc_wacc == 1) {
    368  1.1  itohy 				sc->sc_stat = MLCD_INIT2;
    369  1.1  itohy 				sc->sc_reqw.func_code =
    370  1.1  itohy 				    htonl(MAPLE_FUNC(MAPLE_FN_LCD));
    371  1.1  itohy 				sc->sc_reqw.pt = 0;	/* part 0 */
    372  1.1  itohy 				sc->sc_reqw.block = 0;
    373  1.1  itohy 				sc->sc_reqw.phase = 0;
    374  1.1  itohy 				bcopy(initimg48x32, sc->sc_reqw.data,
    375  1.1  itohy 				    sizeof initimg48x32);
    376  1.1  itohy 				maple_command(sc->sc_parent, sc->sc_unit,
    377  1.1  itohy 				    MAPLE_FN_LCD, MAPLE_COMMAND_BWRITE,
    378  1.1  itohy 				    MLCD_SIZE_REQW(sc) / 4, &sc->sc_reqw, 0);
    379  1.1  itohy 			} else
    380  1.1  itohy 				sc->sc_stat = MLCD_IDLE;	/* init done */
    381  1.1  itohy 		} else {
    382  1.1  itohy 			sc->sc_reqm.pt = part;
    383  1.1  itohy 			maple_command(sc->sc_parent, sc->sc_unit,
    384  1.1  itohy 			    MAPLE_FN_LCD, MAPLE_COMMAND_GETMINFO,
    385  1.1  itohy 			    sizeof sc->sc_reqm / 4, &sc->sc_reqm, 0);
    386  1.1  itohy 		}
    387  1.1  itohy 		break;
    388  1.1  itohy 
    389  1.1  itohy 	case MLCD_INIT2:
    390  1.1  itohy 		sc->sc_stat = MLCD_IDLE;	/* init done */
    391  1.1  itohy 		break;
    392  1.1  itohy 
    393  1.1  itohy 	case MLCD_WRITE:
    394  1.1  itohy 		bp = sc->sc_bp;
    395  1.1  itohy 
    396  1.1  itohy 		switch ((maple_response_t) response->response_code) {
    397  1.1  itohy 		case MAPLE_RESPONSE_OK:			/* write done */
    398  1.1  itohy 			if (++sc->sc_reqw.phase == sc->sc_wacc) {
    399  1.1  itohy 				/* all phase done */
    400  1.1  itohy 				mlcddone(sc);
    401  1.1  itohy 			} else {
    402  1.1  itohy 				/* go next phase */
    403  1.1  itohy 				bcopy(bp->b_data
    404  1.1  itohy 					+ sc->sc_waccsz * sc->sc_reqw.phase,
    405  1.1  itohy 				    sc->sc_reqw.data, sc->sc_waccsz);
    406  1.1  itohy 				maple_command(sc->sc_parent, sc->sc_unit,
    407  1.1  itohy 				    MAPLE_FN_LCD, MAPLE_COMMAND_BWRITE,
    408  1.1  itohy 				    MLCD_SIZE_REQW(sc) / 4, &sc->sc_reqw, 0);
    409  1.1  itohy 			}
    410  1.1  itohy 			break;
    411  1.1  itohy 		case MAPLE_RESPONSE_LCDERR:
    412  1.1  itohy 			mlcd_printerror(sc->sc_pt[sc->sc_reqw.pt].pt_name,
    413  1.1  itohy 			    rm->func_code /* XXX */);
    414  1.1  itohy 			mlcdstart_bp(sc, bp);		/* retry */
    415  1.1  itohy 			break;
    416  1.1  itohy 		default:
    417  1.1  itohy 			printf("%s: write: unexpected response %#x, %#x, sz %d\n",
    418  1.1  itohy 			    sc->sc_pt[sc->sc_reqw.pt].pt_name,
    419  1.1  itohy 			    ntohl(response->response_code),
    420  1.1  itohy 			    ntohl(rm->func_code), sz);
    421  1.1  itohy 			mlcdstart_bp(sc, bp);		/* retry */
    422  1.1  itohy 			break;
    423  1.1  itohy 		}
    424  1.1  itohy 		break;
    425  1.1  itohy 
    426  1.1  itohy 	default:
    427  1.1  itohy 		break;
    428  1.1  itohy 	}
    429  1.1  itohy }
    430  1.1  itohy 
    431  1.1  itohy static void
    432  1.1  itohy mlcd_printerror(head, code)
    433  1.1  itohy 	const char *head;
    434  1.1  itohy 	u_int32_t code;
    435  1.1  itohy {
    436  1.1  itohy 
    437  1.1  itohy 	printf("%s:", head);
    438  1.1  itohy 	NTOHL(code);
    439  1.1  itohy 	if (code & 1)
    440  1.1  itohy 		printf(" PT error");
    441  1.1  itohy 	if (code & 2)
    442  1.1  itohy 		printf(" Phase error");
    443  1.1  itohy 	if (code & 4)
    444  1.1  itohy 		printf(" Block error");
    445  1.1  itohy 	if (code & 010)
    446  1.1  itohy 		printf(" Write error");
    447  1.1  itohy 	if (code & 020)
    448  1.1  itohy 		printf(" Length error");
    449  1.1  itohy 	if (code & ~037)
    450  1.1  itohy 		printf(" Unknown error %#x", code & ~037);
    451  1.1  itohy 	printf("\n");
    452  1.1  itohy }
    453  1.1  itohy 
    454  1.1  itohy int
    455  1.1  itohy mlcdopen(dev, flags, devtype, p)
    456  1.1  itohy 	dev_t dev;
    457  1.1  itohy 	int flags, devtype;
    458  1.1  itohy 	struct proc *p;
    459  1.1  itohy {
    460  1.1  itohy 	int unit, part;
    461  1.1  itohy 	struct mlcd_softc *sc;
    462  1.1  itohy 	struct mlcd_pt *pt;
    463  1.1  itohy 
    464  1.1  itohy 	unit = MLCD_UNIT(dev);
    465  1.1  itohy 	part = MLCD_PART(dev);
    466  1.1  itohy 	if ((sc = device_lookup(&mlcd_cd, unit)) == NULL
    467  1.1  itohy 	    || sc->sc_stat == MLCD_INIT
    468  1.1  itohy 	    || sc->sc_stat == MLCD_INIT2
    469  1.1  itohy 	    || part >= sc->sc_npt || (pt = &sc->sc_pt[part])->pt_flags == 0)
    470  1.1  itohy 		return ENXIO;
    471  1.1  itohy 
    472  1.1  itohy 	if (pt->pt_flags & MLCD_PT_OPEN)
    473  1.1  itohy 		return EBUSY;
    474  1.1  itohy 
    475  1.1  itohy 	pt->pt_flags |= MLCD_PT_OPEN;
    476  1.1  itohy 
    477  1.1  itohy 	return 0;
    478  1.1  itohy }
    479  1.1  itohy 
    480  1.1  itohy int
    481  1.1  itohy mlcdclose(dev, flags, devtype, p)
    482  1.1  itohy 	dev_t dev;
    483  1.1  itohy 	int flags, devtype;
    484  1.1  itohy 	struct proc *p;
    485  1.1  itohy {
    486  1.1  itohy 	int unit, part;
    487  1.1  itohy 	struct mlcd_softc *sc;
    488  1.1  itohy 	struct mlcd_pt *pt;
    489  1.1  itohy 
    490  1.1  itohy 	unit = MLCD_UNIT(dev);
    491  1.1  itohy 	part = MLCD_PART(dev);
    492  1.1  itohy 	sc = mlcd_cd.cd_devs[unit];
    493  1.1  itohy 	pt = &sc->sc_pt[part];
    494  1.1  itohy 
    495  1.1  itohy 	pt->pt_flags &= ~MLCD_PT_OPEN;
    496  1.1  itohy 
    497  1.1  itohy 	return 0;
    498  1.1  itohy }
    499  1.1  itohy 
    500  1.1  itohy void
    501  1.1  itohy mlcdstrategy(bp)
    502  1.1  itohy 	struct buf *bp;
    503  1.1  itohy {
    504  1.1  itohy 	int dev, unit, part;
    505  1.1  itohy 	struct mlcd_softc *sc;
    506  1.1  itohy 	struct mlcd_pt *pt;
    507  1.1  itohy 	daddr_t off, nblk, cnt;
    508  1.1  itohy 
    509  1.1  itohy 	dev = bp->b_dev;
    510  1.1  itohy 	unit = MLCD_UNIT(dev);
    511  1.1  itohy 	part = MLCD_PART(dev);
    512  1.1  itohy 	sc = mlcd_cd.cd_devs[unit];
    513  1.1  itohy 	pt = &sc->sc_pt[part];
    514  1.1  itohy 
    515  1.1  itohy #if 0
    516  1.1  itohy 	printf("%s: mlcdstrategy: blkno %d, count %ld\n",
    517  1.1  itohy 	    pt->pt_name, bp->b_blkno, bp->b_bcount);
    518  1.1  itohy #endif
    519  1.1  itohy 
    520  1.1  itohy 	if (bp->b_flags & B_READ)
    521  1.1  itohy 		goto inval;			/* no read */
    522  1.1  itohy 
    523  1.1  itohy 	cnt = howmany(bp->b_bcount, sc->sc_bsize);
    524  1.1  itohy 	if (cnt == 0)
    525  1.1  itohy 		goto done;	/* no work */
    526  1.1  itohy 
    527  1.1  itohy 	/* XXX We have set the transfer is only one block in mlcd_minphys(). */
    528  1.1  itohy 	KASSERT(cnt == 1);
    529  1.1  itohy 
    530  1.1  itohy 	if (bp->b_blkno & ~(~(daddr_t)0 >> (DEV_BSHIFT + 1 /* sign bit */))
    531  1.1  itohy 	    /*|| (bp->b_bcount % sc->sc_bsize) != 0*/)
    532  1.1  itohy 		goto inval;
    533  1.1  itohy 
    534  1.1  itohy 	off = bp->b_blkno * DEV_BSIZE / sc->sc_bsize;
    535  1.1  itohy 	nblk = pt->pt_nblk;
    536  1.1  itohy 
    537  1.1  itohy 	/* deal with the EOF condition */
    538  1.1  itohy 	if (off + cnt > nblk) {
    539  1.1  itohy 		if (off >= nblk) {
    540  1.1  itohy 			if (off == nblk) {
    541  1.1  itohy 				bp->b_resid = bp->b_bcount;
    542  1.1  itohy 				goto done;
    543  1.1  itohy 			}
    544  1.1  itohy 			goto inval;
    545  1.1  itohy 		}
    546  1.1  itohy 		cnt = nblk - off;
    547  1.1  itohy 		bp->b_resid = bp->b_bcount - (cnt * sc->sc_bsize);
    548  1.1  itohy 	}
    549  1.1  itohy 
    550  1.1  itohy 	bp->b_rawblkno = off;
    551  1.1  itohy 
    552  1.1  itohy 	/* queue this transfer */
    553  1.1  itohy 	BUFQ_PUT(&sc->sc_q, bp);
    554  1.1  itohy 
    555  1.1  itohy 	if (sc->sc_stat == MLCD_IDLE)
    556  1.1  itohy 		mlcdstart(sc);
    557  1.1  itohy 
    558  1.1  itohy 	return;
    559  1.1  itohy 
    560  1.1  itohy inval:	bp->b_error = EINVAL;
    561  1.1  itohy 	bp->b_flags |= B_ERROR;
    562  1.1  itohy done:	biodone(bp);
    563  1.1  itohy }
    564  1.1  itohy 
    565  1.1  itohy /*
    566  1.1  itohy  * start I/O operations
    567  1.1  itohy  */
    568  1.1  itohy static void
    569  1.1  itohy mlcdstart(sc)
    570  1.1  itohy 	struct mlcd_softc *sc;
    571  1.1  itohy {
    572  1.1  itohy 	struct buf *bp;
    573  1.1  itohy 
    574  1.1  itohy 	if ((bp = BUFQ_GET(&sc->sc_q)) == NULL) {
    575  1.1  itohy 		sc->sc_stat = MLCD_IDLE;
    576  1.1  itohy 		maple_enable_unit_ping(sc->sc_parent, sc->sc_unit,
    577  1.1  itohy 		    MAPLE_FN_LCD, 1);
    578  1.1  itohy 		return;
    579  1.1  itohy 	}
    580  1.1  itohy 
    581  1.1  itohy 	sc->sc_retry = 0;
    582  1.1  itohy 	mlcdstart_bp(sc, bp);
    583  1.1  itohy }
    584  1.1  itohy 
    585  1.1  itohy /*
    586  1.1  itohy  * start/retry a specified I/O operation
    587  1.1  itohy  */
    588  1.1  itohy static void
    589  1.1  itohy mlcdstart_bp(sc, bp)
    590  1.1  itohy 	struct mlcd_softc *sc;
    591  1.1  itohy 	struct buf *bp;
    592  1.1  itohy {
    593  1.1  itohy 	int part;
    594  1.1  itohy 	struct mlcd_pt *pt;
    595  1.1  itohy 
    596  1.1  itohy 	part = MLCD_PART(bp->b_dev);
    597  1.1  itohy 	pt = &sc->sc_pt[part];
    598  1.1  itohy 
    599  1.1  itohy 	/* handle retry */
    600  1.1  itohy 	if (sc->sc_retry++ > MLCD_MAXRETRY) {
    601  1.1  itohy 		/* retry count exceeded */
    602  1.1  itohy 		bp->b_error = EIO;
    603  1.1  itohy 		bp->b_flags |= B_ERROR;
    604  1.1  itohy 		mlcddone(sc);
    605  1.1  itohy 		return;
    606  1.1  itohy 	}
    607  1.1  itohy 
    608  1.1  itohy 	sc->sc_bp = bp;
    609  1.1  itohy 	/* sc->sc_cnt = cnt; */	/* cnt is always 1 */
    610  1.1  itohy 
    611  1.1  itohy 	/*
    612  1.1  itohy 	 * I/O access will fail if the removal detection (by maple driver)
    613  1.1  itohy 	 * occurs before finishing the I/O, so disable it.
    614  1.1  itohy 	 * We are sending commands, and the removal detection is still alive.
    615  1.1  itohy 	 */
    616  1.1  itohy 	maple_enable_unit_ping(sc->sc_parent, sc->sc_unit, MAPLE_FN_LCD, 0);
    617  1.1  itohy 
    618  1.1  itohy 	/*
    619  1.1  itohy 	 * Start the first phase (phase# = 0).
    620  1.1  itohy 	 */
    621  1.1  itohy 	KASSERT((bp->b_flags & B_READ) == 0);
    622  1.1  itohy 	/* write */
    623  1.1  itohy 	sc->sc_stat = MLCD_WRITE;
    624  1.1  itohy 	sc->sc_reqw.func_code = htonl(MAPLE_FUNC(MAPLE_FN_LCD));
    625  1.1  itohy 	sc->sc_reqw.pt = part;
    626  1.1  itohy 	sc->sc_reqw.block = htons(bp->b_rawblkno);
    627  1.1  itohy 	sc->sc_reqw.phase = 0;		/* first phase */
    628  1.1  itohy 	bcopy(bp->b_data /* + sc->sc_waccsz * phase */,
    629  1.1  itohy 	    sc->sc_reqw.data, sc->sc_waccsz);
    630  1.1  itohy 	maple_command(sc->sc_parent, sc->sc_unit, MAPLE_FN_LCD,
    631  1.1  itohy 	    MAPLE_COMMAND_BWRITE, MLCD_SIZE_REQW(sc) / 4, &sc->sc_reqw, 0);
    632  1.1  itohy }
    633  1.1  itohy 
    634  1.1  itohy static void
    635  1.1  itohy mlcddone(sc)
    636  1.1  itohy 	struct mlcd_softc *sc;
    637  1.1  itohy {
    638  1.1  itohy 	struct buf *bp;
    639  1.1  itohy 
    640  1.1  itohy 	/* terminate current transfer */
    641  1.1  itohy 	bp = sc->sc_bp;
    642  1.1  itohy 	KASSERT(bp);
    643  1.1  itohy 	sc->sc_bp = NULL;
    644  1.1  itohy 	biodone(bp);
    645  1.1  itohy 
    646  1.1  itohy 	/* go next transfer */
    647  1.1  itohy 	mlcdstart(sc);
    648  1.1  itohy }
    649  1.1  itohy 
    650  1.1  itohy static void mlcd_minphys __P((struct buf *));
    651  1.1  itohy 
    652  1.1  itohy static void
    653  1.1  itohy mlcd_minphys(bp)
    654  1.1  itohy 	struct buf *bp;
    655  1.1  itohy {
    656  1.1  itohy 	int unit;
    657  1.1  itohy 	struct mlcd_softc *sc;
    658  1.1  itohy 
    659  1.1  itohy 	unit = MLCD_UNIT(bp->b_dev);
    660  1.1  itohy 	sc = mlcd_cd.cd_devs[unit];
    661  1.1  itohy 
    662  1.1  itohy 	/* XXX one block only */
    663  1.1  itohy 	if (bp->b_bcount > sc->sc_bsize)
    664  1.1  itohy 		bp->b_bcount = sc->sc_bsize;
    665  1.1  itohy }
    666  1.1  itohy 
    667  1.1  itohy int
    668  1.1  itohy mlcdwrite(dev, uio, flags)
    669  1.1  itohy 	dev_t	dev;
    670  1.1  itohy 	struct	uio *uio;
    671  1.1  itohy 	int	flags;
    672  1.1  itohy {
    673  1.1  itohy 
    674  1.1  itohy 	return (physio(mlcdstrategy, NULL, dev, B_WRITE, mlcd_minphys, uio));
    675  1.1  itohy }
    676  1.1  itohy 
    677  1.1  itohy int
    678  1.1  itohy mlcdioctl(dev, cmd, data, flag, p)
    679  1.1  itohy 	dev_t dev;
    680  1.1  itohy 	u_long cmd;
    681  1.1  itohy 	caddr_t data;
    682  1.1  itohy 	int flag;
    683  1.1  itohy 	struct proc *p;
    684  1.1  itohy {
    685  1.1  itohy 	int unit, part;
    686  1.1  itohy 	struct mlcd_softc *sc;
    687  1.1  itohy 	struct mlcd_pt *pt;
    688  1.1  itohy 
    689  1.1  itohy 	unit = MLCD_UNIT(dev);
    690  1.1  itohy 	part = MLCD_PART(dev);
    691  1.1  itohy 	sc = mlcd_cd.cd_devs[unit];
    692  1.1  itohy 	pt = &sc->sc_pt[part];
    693  1.1  itohy 
    694  1.1  itohy 	switch (cmd) {
    695  1.1  itohy 
    696  1.1  itohy 	default:
    697  1.1  itohy 		/* generic maple ioctl */
    698  1.1  itohy 		return maple_unit_ioctl(sc->sc_parent, sc->sc_unit, cmd, data,
    699  1.1  itohy 		    flag, p);
    700  1.1  itohy 	}
    701  1.1  itohy 
    702  1.1  itohy 	return 0;
    703  1.1  itohy }
    704