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