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