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