1 /* $NetBSD: mlcd.c,v 1.10 2008/06/08 16:39:43 tsutsui Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mlcd.c,v 1.10 2008/06/08 16:39:43 tsutsui Exp $");
35 #include <sys/param.h>
36 #include <sys/device.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
40 #include <sys/systm.h>
41 #include <sys/vnode.h>
44 #include <dreamcast/dev/maple/maple.h>
45 #include <dreamcast/dev/maple/mapleconf.h>
47 #define MLCD_MAXACCSIZE 1012 /* (255*4) - 8 = 253*32 / 8 */
49 struct mlcd_funcdef
{ /* XXX assuming little-endian structure packing */
51 bw
: 1, /* 0: normally white, 1: normally black */
52 hv
: 1, /* 0: horizontal, 1: vertical */
54 wa
: 4, /* number of access / write */
55 bb
: 8, /* block size / 32 - 1 */
56 pt
: 8; /* number of partition - 1 */
59 struct mlcd_request_write_data
{
62 uint8_t phase
; /* 0, 1, 2, 3: for each 128 byte */
64 uint8_t data
[MLCD_MAXACCSIZE
];
66 #define MLCD_SIZE_REQW(sc) ((sc)->sc_waccsz + 8)
68 struct mlcd_request_get_media_info
{
70 uint32_t pt
; /* pt (1 byte) and unused 3 bytes */
73 struct mlcd_media_info
{
74 uint8_t width
; /* width - 1 */
75 uint8_t height
; /* height - 1 */
76 uint8_t rsvd
[2]; /* ? 0x10 0x02 */
79 struct mlcd_response_media_info
{
80 uint32_t func_code
; /* function code (big endian) */
81 struct mlcd_media_info info
;
85 SIMPLEQ_ENTRY(mlcd_buf
) lb_q
;
89 uint32_t lb_data
[1]; /* variable length */
91 #define MLCD_BUF_SZ(sc) (offsetof(struct mlcd_buf, lb_data) + (sc)->sc_bsize)
96 struct device
*sc_parent
;
97 struct maple_unit
*sc_unit
;
100 MLCD_INIT
, /* during initialization */
101 MLCD_INIT2
, /* during initialization */
102 MLCD_IDLE
, /* init done, not in I/O */
103 MLCD_WRITE
, /* in write operation */
104 MLCD_DETACH
/* detaching */
107 int sc_npt
; /* number of partitions */
108 int sc_bsize
; /* block size */
109 int sc_wacc
; /* number of write access per block */
110 int sc_waccsz
; /* size of a write access */
114 #define MLCD_PT_OK 1 /* partition is alive */
115 #define MLCD_PT_OPEN 2
116 struct mlcd_media_info pt_info
; /* geometry per part */
117 int pt_size
; /* partition size in byte */
118 int pt_nblk
; /* partition size in block */
120 char pt_name
[16 /* see device.h */ + 4 /* ".255" */];
123 /* write request buffer (only one is used at a time) */
125 struct mlcd_request_write_data req_write
;
126 struct mlcd_request_get_media_info req_minfo
;
128 #define sc_reqw sc_req.req_write
129 #define sc_reqm sc_req.req_minfo
131 /* pending buffers */
132 SIMPLEQ_HEAD(mlcd_bufq
, mlcd_buf
) sc_q
;
134 /* current I/O access */
135 struct mlcd_buf
*sc_bp
;
137 #define MLCD_MAXRETRY 10
141 * minor number layout (mlcddetach() depends on this layout):
143 * 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
144 * |---------------------------------| |---------------------|
147 #define MLCD_PART(dev) (minor(dev) & 0xff)
148 #define MLCD_UNIT(dev) (minor(dev) >> 8)
149 #define MLCD_MINOR(unit, part) (((unit) << 8) | (part))
151 static int mlcdmatch(struct device
*, struct cfdata
*, void *);
152 static void mlcdattach(struct device
*, struct device
*, void *);
153 static int mlcddetach(struct device
*, int);
154 static void mlcd_intr(void *, struct maple_response
*, int, int);
155 static void mlcd_printerror(const char *, uint32_t);
156 static struct mlcd_buf
*mlcd_buf_alloc(int /*dev*/, int /*flags*/);
157 static void mlcd_buf_free(struct mlcd_buf
*);
158 static inline uint32_t reverse_32(uint32_t);
159 static void mlcd_rotate_bitmap(void *, size_t);
160 static void mlcdstart(struct mlcd_softc
*);
161 static void mlcdstart_bp(struct mlcd_softc
*);
162 static void mlcddone(struct mlcd_softc
*);
164 dev_type_open(mlcdopen
);
165 dev_type_close(mlcdclose
);
166 dev_type_write(mlcdwrite
);
167 dev_type_ioctl(mlcdioctl
);
169 const struct cdevsw mlcd_cdevsw
= {
170 mlcdopen
, mlcdclose
, noread
, mlcdwrite
, mlcdioctl
,
171 nostop
, notty
, nopoll
, nommap
, nokqfilter
174 CFATTACH_DECL(mlcd
, sizeof(struct mlcd_softc
),
175 mlcdmatch
, mlcdattach
, mlcddetach
, NULL
);
177 extern struct cfdriver mlcd_cd
;
179 /* initial image "NetBSD dreamcast" */
180 static const char initimg48x32
[192] = {
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184 0x1c, 0x70, 0x00, 0x7e, 0x1c, 0xf0, 0x0c, 0x60, 0x00, 0x33, 0x26, 0x6c,
185 0x0c, 0x60, 0x0c, 0x33, 0x66, 0x66, 0x1e, 0xc7, 0x0c, 0x62, 0x60, 0xc6,
186 0x1a, 0xc9, 0xbe, 0x7c, 0x30, 0xc6, 0x1a, 0xdb, 0x98, 0x66, 0x18, 0xc6,
187 0x1a, 0xdc, 0x18, 0x66, 0x0d, 0x8c, 0x31, 0xb0, 0x32, 0xc6, 0x8d, 0x8c,
188 0x31, 0xb1, 0x36, 0xcd, 0x99, 0x98, 0x71, 0x9e, 0x1d, 0xf9, 0xf3, 0xe0,
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08,
191 0x1d, 0x6c, 0x63, 0xc7, 0x30, 0xde, 0x25, 0x92, 0x12, 0xa8, 0x09, 0x08,
192 0x25, 0x1e, 0x72, 0xa8, 0x38, 0xc8, 0x25, 0x10, 0x92, 0xa8, 0x48, 0x28,
193 0x1d, 0x0e, 0x6a, 0xa7, 0x35, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
201 mlcdmatch(struct device
*parent
, struct cfdata
*cf
, void *aux
)
203 struct maple_attach_args
*ma
= aux
;
205 return (ma
->ma_function
== MAPLE_FN_LCD
? MAPLE_MATCH_FUNC
: 0);
209 mlcdattach(struct device
*parent
, struct device
*self
, void *aux
)
211 struct mlcd_softc
*sc
= (void *) self
;
212 struct maple_attach_args
*ma
= aux
;
216 struct mlcd_funcdef s
;
219 sc
->sc_parent
= parent
;
220 sc
->sc_unit
= ma
->ma_unit
;
221 sc
->sc_direction
= ma
->ma_basedevinfo
->di_connector_direction
;
223 funcdef
.v
= maple_get_function_data(ma
->ma_devinfo
, MAPLE_FN_LCD
);
224 printf(": LCD display\n");
225 printf("%s: %d LCD, %d bytes/block, ",
227 sc
->sc_npt
= funcdef
.s
.pt
+ 1,
228 sc
->sc_bsize
= (funcdef
.s
.bb
+ 1) << 5);
229 if ((sc
->sc_wacc
= funcdef
.s
.wa
) == 0)
232 printf("%d acc/", sc
->sc_wacc
);
233 printf("write, %s, norm %s%s\n",
234 funcdef
.s
.hv
? "vert" : "horiz",
235 funcdef
.s
.bw
? "black" : "white",
236 sc
->sc_direction
== MAPLE_CONN_TOP
? ", upside-down" : "");
239 * start init sequence
241 sc
->sc_stat
= MLCD_INIT
;
242 SIMPLEQ_INIT(&sc
->sc_q
);
244 /* check consistency */
245 if (sc
->sc_wacc
!= 0) {
246 sc
->sc_waccsz
= sc
->sc_bsize
/ sc
->sc_wacc
;
247 if (sc
->sc_bsize
!= sc
->sc_waccsz
* sc
->sc_wacc
) {
248 printf("%s: write access isn't equally divided\n",
249 sc
->sc_dev
.dv_xname
);
250 sc
->sc_wacc
= 0; /* no write */
251 } else if (sc
->sc_waccsz
> MLCD_MAXACCSIZE
) {
252 printf("%s: write access size is too large\n",
253 sc
->sc_dev
.dv_xname
);
254 sc
->sc_wacc
= 0; /* no write */
257 if (sc
->sc_wacc
== 0) {
258 printf("%s: device doesn't support write\n",
259 sc
->sc_dev
.dv_xname
);
263 /* per-part structure */
264 sc
->sc_pt
= malloc(sizeof(struct mlcd_pt
) * sc
->sc_npt
, M_DEVBUF
,
267 for (i
= 0; i
< sc
->sc_npt
; i
++) {
268 sprintf(sc
->sc_pt
[i
].pt_name
, "%s.%d", sc
->sc_dev
.dv_xname
, i
);
271 maple_set_callback(parent
, sc
->sc_unit
, MAPLE_FN_LCD
,
275 * get size (start from partition 0)
277 sc
->sc_reqm
.func_code
= htobe32(MAPLE_FUNC(MAPLE_FN_LCD
));
279 maple_command(sc
->sc_parent
, sc
->sc_unit
, MAPLE_FN_LCD
,
280 MAPLE_COMMAND_GETMINFO
, sizeof sc
->sc_reqm
/ 4, &sc
->sc_reqm
, 0);
285 mlcddetach(struct device
*self
, int flags
)
287 struct mlcd_softc
*sc
= (struct mlcd_softc
*) self
;
289 int minor_l
, minor_h
;
291 sc
->sc_stat
= MLCD_DETACH
; /* just in case */
296 if ((bp
= sc
->sc_bp
) != NULL
) {
300 while ((bp
= SIMPLEQ_FIRST(&sc
->sc_q
)) != NULL
) {
301 SIMPLEQ_REMOVE_HEAD(&sc
->sc_q
, lb_q
);
309 minor_l
= MLCD_MINOR(device_unit(self
), 0);
310 minor_h
= MLCD_MINOR(device_unit(self
), sc
->sc_npt
- 1);
311 vdevgone(cdevsw_lookup_major(&mlcd_cdevsw
), minor_l
, minor_h
, VCHR
);
314 * free per-partition structure
317 free(sc
->sc_pt
, M_DEVBUF
);
323 * called back from maple bus driver
327 mlcd_intr(void *dev
, struct maple_response
*response
, int sz
, int flags
)
329 struct mlcd_softc
*sc
= dev
;
330 struct mlcd_response_media_info
*rm
= (void *) response
->data
;
335 switch (sc
->sc_stat
) {
337 /* checking part geometry */
338 part
= sc
->sc_reqm
.pt
;
339 pt
= &sc
->sc_pt
[part
];
340 switch ((maple_response_t
) response
->response_code
) {
341 case MAPLE_RESPONSE_DATATRF
:
342 pt
->pt_info
= rm
->info
;
343 pt
->pt_size
= ((pt
->pt_info
.width
+ 1) *
344 (pt
->pt_info
.height
+ 1) + 7) / 8;
345 pt
->pt_nblk
= pt
->pt_size
/ sc
->sc_bsize
;
346 printf("%s: %dx%d display, %d bytes\n",
348 pt
->pt_info
.width
+ 1, pt
->pt_info
.height
+ 1,
351 /* this partition is active */
352 pt
->pt_flags
= MLCD_PT_OK
;
356 printf("%s: init: unexpected response %#x, sz %d\n",
357 pt
->pt_name
, be32toh(response
->response_code
), sz
);
360 if (++part
== sc
->sc_npt
) {
363 /* XXX initial image for Visual Memory */
364 if (sc
->sc_pt
[0].pt_size
== sizeof initimg48x32
&&
365 sc
->sc_waccsz
== sizeof initimg48x32
&&
367 sc
->sc_stat
= MLCD_INIT2
;
368 sc
->sc_reqw
.func_code
=
369 htobe32(MAPLE_FUNC(MAPLE_FN_LCD
));
370 sc
->sc_reqw
.pt
= 0; /* part 0 */
371 sc
->sc_reqw
.block
= 0;
372 sc
->sc_reqw
.phase
= 0;
373 memcpy(sc
->sc_reqw
.data
, initimg48x32
,
374 sizeof initimg48x32
);
375 if (sc
->sc_direction
== MAPLE_CONN_TOP
) {
376 /* the LCD is upside-down */
377 mlcd_rotate_bitmap(sc
->sc_reqw
.data
,
378 sizeof initimg48x32
);
380 maple_command(sc
->sc_parent
, sc
->sc_unit
,
381 MAPLE_FN_LCD
, MAPLE_COMMAND_BWRITE
,
382 MLCD_SIZE_REQW(sc
) / 4, &sc
->sc_reqw
, 0);
384 sc
->sc_stat
= MLCD_IDLE
; /* init done */
386 sc
->sc_reqm
.pt
= part
;
387 maple_command(sc
->sc_parent
, sc
->sc_unit
,
388 MAPLE_FN_LCD
, MAPLE_COMMAND_GETMINFO
,
389 sizeof sc
->sc_reqm
/ 4, &sc
->sc_reqm
, 0);
394 sc
->sc_stat
= MLCD_IDLE
; /* init done */
400 switch ((maple_response_t
) response
->response_code
) {
401 case MAPLE_RESPONSE_OK
: /* write done */
402 if (++sc
->sc_reqw
.phase
== sc
->sc_wacc
) {
407 memcpy(sc
->sc_reqw
.data
,
408 (char *)bp
->lb_data
+
409 sc
->sc_waccsz
* sc
->sc_reqw
.phase
,
411 maple_command(sc
->sc_parent
, sc
->sc_unit
,
412 MAPLE_FN_LCD
, MAPLE_COMMAND_BWRITE
,
413 MLCD_SIZE_REQW(sc
) / 4, &sc
->sc_reqw
, 0);
416 case MAPLE_RESPONSE_LCDERR
:
417 mlcd_printerror(sc
->sc_pt
[sc
->sc_reqw
.pt
].pt_name
,
418 rm
->func_code
/* XXX */);
419 mlcdstart_bp(sc
); /* retry */
422 printf("%s: write: unexpected response %#x, %#x, sz %d\n",
423 sc
->sc_pt
[sc
->sc_reqw
.pt
].pt_name
,
424 be32toh(response
->response_code
),
425 be32toh(rm
->func_code
), sz
);
426 mlcdstart_bp(sc
); /* retry */
437 mlcd_printerror(const char *head
, uint32_t code
)
445 printf(" Phase error");
447 printf(" Block error");
449 printf(" Write error");
451 printf(" Length error");
453 printf(" Unknown error %#x", code
& ~037);
459 mlcdopen(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
462 struct mlcd_softc
*sc
;
465 unit
= MLCD_UNIT(dev
);
466 part
= MLCD_PART(dev
);
467 if ((sc
= device_lookup_private(&mlcd_cd
, unit
)) == NULL
468 || sc
->sc_stat
== MLCD_INIT
469 || sc
->sc_stat
== MLCD_INIT2
470 || part
>= sc
->sc_npt
|| (pt
= &sc
->sc_pt
[part
])->pt_flags
== 0)
473 if (pt
->pt_flags
& MLCD_PT_OPEN
)
476 pt
->pt_flags
|= MLCD_PT_OPEN
;
483 mlcdclose(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
486 struct mlcd_softc
*sc
;
489 unit
= MLCD_UNIT(dev
);
490 part
= MLCD_PART(dev
);
491 sc
= device_lookup_private(&mlcd_cd
, unit
);
492 pt
= &sc
->sc_pt
[part
];
494 pt
->pt_flags
&= ~MLCD_PT_OPEN
;
500 * start I/O operations
503 mlcdstart(struct mlcd_softc
*sc
)
507 if ((bp
= SIMPLEQ_FIRST(&sc
->sc_q
)) == NULL
) {
508 sc
->sc_stat
= MLCD_IDLE
;
509 maple_enable_unit_ping(sc
->sc_parent
, sc
->sc_unit
,
514 SIMPLEQ_REMOVE_HEAD(&sc
->sc_q
, lb_q
);
522 * start/retry a specified I/O operation
525 mlcdstart_bp(struct mlcd_softc
*sc
)
531 pt
= &sc
->sc_pt
[bp
->lb_partno
];
534 if (sc
->sc_retry
++ > MLCD_MAXRETRY
) {
535 /* retry count exceeded */
542 * I/O access will fail if the removal detection (by maple driver)
543 * occurs before finishing the I/O, so disable it.
544 * We are sending commands, and the removal detection is still alive.
546 maple_enable_unit_ping(sc
->sc_parent
, sc
->sc_unit
, MAPLE_FN_LCD
, 0);
549 * Start the first phase (phase# = 0).
552 sc
->sc_stat
= MLCD_WRITE
;
553 sc
->sc_reqw
.func_code
= htobe32(MAPLE_FUNC(MAPLE_FN_LCD
));
554 sc
->sc_reqw
.pt
= bp
->lb_partno
;
555 sc
->sc_reqw
.block
= htobe16(bp
->lb_blkno
);
556 sc
->sc_reqw
.phase
= 0; /* first phase */
557 memcpy(sc
->sc_reqw
.data
,
558 (char *) bp
->lb_data
/* + sc->sc_waccsz * phase */, sc
->sc_waccsz
);
559 maple_command(sc
->sc_parent
, sc
->sc_unit
, MAPLE_FN_LCD
,
560 MAPLE_COMMAND_BWRITE
, MLCD_SIZE_REQW(sc
) / 4, &sc
->sc_reqw
, 0);
564 mlcddone(struct mlcd_softc
*sc
)
568 /* terminate current transfer */
574 /* go next transfer */
579 * allocate a buffer for one block
582 * [flags == M_NOWAIT] out of buffer space
583 * [flags == M_WAITOK] device detach detected
585 static struct mlcd_buf
*
586 mlcd_buf_alloc(int dev
, int flags
)
588 struct mlcd_softc
*sc
;
593 unit
= MLCD_UNIT(dev
);
594 part
= MLCD_PART(dev
);
595 sc
= device_lookup_private(&mlcd_cd
, unit
);
597 pt
= &sc
->sc_pt
[part
];
600 if ((bp
= malloc(MLCD_BUF_SZ(sc
), M_DEVBUF
, flags
)) == NULL
)
604 * malloc() may sleep, and the device may be detached during sleep.
605 * XXX this check is not complete.
607 if (sc
!= device_lookup_private(&mlcd_cd
, unit
)
608 || sc
->sc_stat
== MLCD_INIT
609 || sc
->sc_stat
== MLCD_INIT2
610 || part
>= sc
->sc_npt
|| pt
!= &sc
->sc_pt
[part
]
611 || pt
->pt_flags
== 0) {
622 mlcd_buf_free(struct mlcd_buf
*bp
)
628 /* invert order of bits */
629 static inline uint32_t
630 reverse_32(uint32_t b
)
634 /* invert every 8bit */
635 b1
= (b
& 0x55555555) << 1; b
= (b
>> 1) & 0x55555555; b
|= b1
;
636 b1
= (b
& 0x33333333) << 2; b
= (b
>> 2) & 0x33333333; b
|= b1
;
637 b1
= (b
& 0x0f0f0f0f) << 4; b
= (b
>> 4) & 0x0f0f0f0f; b
|= b1
;
639 /* invert byte order */
644 mlcd_rotate_bitmap(void *ptr
, size_t size
)
646 uint32_t *p
, *q
, tmp
;
648 KDASSERT(size
% sizeof(uint32_t) == 0);
649 for (p
= ptr
, q
= (void *)((char *)ptr
+ size
); p
< q
; ) {
650 tmp
= reverse_32(*p
);
651 *p
++ = reverse_32(*--q
);
658 mlcdwrite(dev_t dev
, struct uio
*uio
, int flags
)
660 struct mlcd_softc
*sc
;
667 part
= MLCD_PART(dev
);
668 sc
= device_lookup_private(&mlcd_cd
, MLCD_UNIT(dev
));
669 pt
= &sc
->sc_pt
[part
];
672 printf("%s: mlcdwrite: offset %ld, size %d\n",
673 pt
->pt_name
, (long) uio
->uio_offset
, uio
->uio_resid
);
676 devsize
= pt
->pt_nblk
* sc
->sc_bsize
;
677 if (uio
->uio_offset
% sc
->sc_bsize
|| uio
->uio_offset
> devsize
)
680 if ((bp
= mlcd_buf_alloc(dev
, M_WAITOK
)) == NULL
)
681 return EIO
; /* device is detached during allocation */
683 bp
->lb_partno
= part
;
685 while (uio
->uio_offset
< devsize
686 && uio
->uio_resid
>= (size_t) sc
->sc_bsize
) {
687 /* invert block number if upside-down */
688 bp
->lb_blkno
= (sc
->sc_direction
== MAPLE_CONN_TOP
) ?
689 pt
->pt_nblk
- uio
->uio_offset
/ sc
->sc_bsize
- 1 :
690 uio
->uio_offset
/ sc
->sc_bsize
;
692 if ((error
= uiomove(bp
->lb_data
, sc
->sc_bsize
, uio
)) != 0)
695 if (sc
->sc_direction
== MAPLE_CONN_TOP
) {
696 /* the LCD is upside-down */
697 mlcd_rotate_bitmap(bp
->lb_data
, sc
->sc_bsize
);
700 /* queue this transfer */
701 SIMPLEQ_INSERT_TAIL(&sc
->sc_q
, bp
, lb_q
);
703 if (sc
->sc_stat
== MLCD_IDLE
)
706 tsleep(bp
, PRIBIO
+ 1, "mlcdbuf", 0);
708 if ((error
= bp
->lb_error
) != 0) {
709 uio
->uio_resid
+= sc
->sc_bsize
;
720 mlcdioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
723 struct mlcd_softc
*sc
;
726 unit
= MLCD_UNIT(dev
);
727 part
= MLCD_PART(dev
);
728 sc
= device_lookup_private(&mlcd_cd
, unit
);
729 pt
= &sc
->sc_pt
[part
];
734 /* generic maple ioctl */
735 return maple_unit_ioctl(sc
->sc_parent
, sc
->sc_unit
, cmd
, data
,