1 /* $NetBSD: gdrom.c,v 1.25 2008/06/11 14:55:30 tsutsui Exp $ */
4 * Copyright (c) 2001 Marcus Comstedt
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Marcus Comstedt.
18 * 4. Neither the name of The NetBSD Foundation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
36 __KERNEL_RCSID(0, "$NetBSD: gdrom.c,v 1.25 2008/06/11 14:55:30 tsutsui Exp $");
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
43 #include <sys/ioctl.h>
44 #include <sys/fcntl.h>
45 #include <sys/disklabel.h>
51 #include <machine/sysasicvar.h>
53 int gdrommatch(struct device
*, struct cfdata
*, void *);
54 void gdromattach(struct device
*, struct device
*, void *);
56 dev_type_open(gdromopen
);
57 dev_type_close(gdromclose
);
58 dev_type_read(gdromread
);
59 dev_type_write(gdromwrite
);
60 dev_type_ioctl(gdromioctl
);
61 dev_type_strategy(gdromstrategy
);
63 const struct bdevsw gdrom_bdevsw
= {
64 gdromopen
, gdromclose
, gdromstrategy
, gdromioctl
, nodump
,
68 const struct cdevsw gdrom_cdevsw
= {
69 gdromopen
, gdromclose
, gdromread
, gdromwrite
, gdromioctl
,
70 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
74 struct device sc_dv
; /* generic device info; must come first */
75 struct disk dkdev
; /* generic disk info */
76 struct buf curbuf
; /* state of current I/O operation */
79 int openpart_start
; /* start sector of currently open partition */
82 void *cmd_result_buf
; /* where to store result data (16 bit aligned) */
83 int cmd_result_size
; /* number of bytes allocated for buf */
84 int cmd_actual
; /* number of bytes actually read */
85 int cmd_cond
; /* resulting condition of command */
88 CFATTACH_DECL(gdrom
, sizeof(struct gdrom_softc
),
89 gdrommatch
, gdromattach
, NULL
, NULL
);
91 struct dkdriver gdromdkdriver
= { gdromstrategy
};
93 extern struct cfdriver gdrom_cd
;
97 unsigned int entry
[99];
98 unsigned int first
, last
;
102 #define TOC_LBA(n) ((n) & 0xffffff00)
103 #define TOC_ADR(n) ((n) & 0x0f)
104 #define TOC_CTRL(n) (((n) & 0xf0) >> 4)
105 #define TOC_TRACK(n) (((n) & 0x0000ff00) >> 8)
107 #define GDROM(o) (*(volatile unsigned char *)(0xa05f7000 + (o)))
109 #define GDSTATSTAT(n) ((n) & 0xf)
110 #define GDSTATDISK(n) (((n) >> 4) & 0xf)
112 #define GDROM_BUSY GDROM(0x18)
113 #define GDROM_DATA (*(volatile short *) & GDROM(0x80))
114 #define GDROM_REGX GDROM(0x84)
115 #define GDROM_STAT GDROM(0x8c)
116 #define GDROM_CNTLO GDROM(0x90)
117 #define GDROM_CNTHI GDROM(0x94)
118 #define GDROM_COND GDROM(0x9c)
120 int gdrom_getstat(void);
121 int gdrom_do_command(struct gdrom_softc
*, void *, void *, unsigned int);
122 int gdrom_command_sense(struct gdrom_softc
*, void *, void *, unsigned int);
123 int gdrom_read_toc(struct gdrom_softc
*, struct gd_toc
*);
124 int gdrom_read_sectors(struct gdrom_softc
*, void *, int, int);
125 int gdrom_mount_disk(struct gdrom_softc
*);
126 int gdrom_intr(void *);
128 int gdrom_getstat(void)
132 if (GDROM_BUSY
& 0x80)
137 if (GDROM_BUSY
& 0x80)
148 gdrom_intr(void *arg
)
150 struct gdrom_softc
*sc
= arg
;
156 printf("GDROM: cond = %x\n", cond
);
158 if (!sc
->cmd_active
) {
160 printf("GDROM: inactive IRQ!?\n");
167 int cnt
= (GDROM_CNTHI
<< 8) | GDROM_CNTLO
;
169 printf("GDROM: cnt = %d\n", cnt
);
171 sc
->cmd_actual
+= cnt
;
172 if (cnt
> 0 && sc
->cmd_result_size
> 0) {
173 int subcnt
= (cnt
> sc
->cmd_result_size
?
174 sc
->cmd_result_size
: cnt
);
175 int16_t *ptr
= sc
->cmd_result_buf
;
176 sc
->cmd_result_buf
= ((char *)sc
->cmd_result_buf
) +
178 sc
->cmd_result_size
-= subcnt
;
186 volatile int16_t tmp
;
191 while (GDROM_BUSY
& 0x80);
193 if ((cond
& 8) == 0) {
196 wakeup(&sc
->cmd_active
);
204 int gdrom_do_command(struct gdrom_softc
*sc
, void *req
, void *buf
,
210 while (GDROM_BUSY
& 0x88)
213 GDROM_CNTLO
= nbyt
& 0xff;
214 GDROM_CNTHI
= (nbyt
>> 8) & 0xff;
217 sc
->cmd_result_buf
= buf
;
218 sc
->cmd_result_size
= nbyt
;
220 if (GDSTATSTAT(GDROM_STAT
) == 6)
224 for (i
= 0; i
< 64; i
++)
226 while ((GDROM_BUSY
& 0x88) != 8)
234 for (i
= 0; i
< 6; i
++)
237 while (sc
->cmd_active
)
238 tsleep(&sc
->cmd_active
, PRIBIO
, "gdrom", 0);
246 int gdrom_command_sense(struct gdrom_softc
*sc
, void *req
, void *buf
,
256 unsigned short sense_data
[5];
257 unsigned char cmd
[12];
258 int sense_key
, sense_specific
;
260 int cond
= gdrom_do_command(sc
, req
, buf
, nbyt
);
264 printf("GDROM: not ready (2:58)\n");
269 if ((cond
& 1) == 0) {
271 printf("GDROM: no sense. 0:0\n");
276 memset(cmd
, 0, sizeof(cmd
));
279 cmd
[4] = sizeof(sense_data
);
281 gdrom_do_command(sc
, cmd
, sense_data
, sizeof(sense_data
));
283 sense_key
= sense_data
[1] & 0xf;
284 sense_specific
= sense_data
[4];
285 if (sense_key
== 11 && sense_specific
== 0) {
287 printf("GDROM: aborted (ignored). 0:0\n");
293 printf("GDROM: SENSE %d:", sense_key
);
294 printf("GDROM: %d\n", sense_specific
);
297 return sense_key
== 0 ? 0 : EIO
;
300 int gdrom_read_toc(struct gdrom_softc
*sc
, struct gd_toc
*toc
)
309 unsigned char cmd
[12];
311 memset(cmd
, 0, sizeof(cmd
));
314 cmd
[3] = sizeof(struct gd_toc
) >> 8;
315 cmd
[4] = sizeof(struct gd_toc
) & 0xff;
317 return gdrom_command_sense(sc
, cmd
, toc
, sizeof(struct gd_toc
));
320 int gdrom_read_sectors(struct gdrom_softc
*sc
, void *buf
, int sector
, int cnt
)
329 unsigned char cmd
[12];
331 memset(cmd
, 0, sizeof(cmd
));
342 return gdrom_command_sense(sc
, cmd
, buf
, cnt
<< 11);
345 int gdrom_mount_disk(struct gdrom_softc
*sc
)
354 unsigned char cmd
[12];
356 memset(cmd
, 0, sizeof(cmd
));
361 return gdrom_command_sense(sc
, cmd
, NULL
, 0);
365 gdrommatch(struct device
*parent
, struct cfdata
*cf
, void *aux
)
367 static int gdrom_matched
= 0;
369 /* Allow only once instance. */
378 gdromattach(struct device
*parent
, struct device
*self
, void *aux
)
380 struct gdrom_softc
*sc
;
383 sc
= (struct gdrom_softc
*)self
;
386 * Initialize and attach the disk structure.
388 disk_init(&sc
->dkdev
, sc
->sc_dv
.dv_xname
, &gdromdkdriver
);
389 disk_attach(&sc
->dkdev
);
392 * reenable disabled drive
394 *((volatile uint32_t *)0xa05f74e4) = 0x1fffff;
395 for (p
= 0; p
< 0x200000 / 4; p
++)
396 x
= ((volatile uint32_t *)0xa0000000)[p
];
398 printf(": %s\n", sysasic_intr_string(SYSASIC_IRL9
));
399 sysasic_intr_establish(SYSASIC_EVENT_GDROM
, IPL_BIO
, SYSASIC_IRL9
,
404 gdromopen(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
406 struct gdrom_softc
*sc
;
407 int s
, error
, unit
, cnt
;
411 printf("GDROM: open\n");
414 unit
= DISKUNIT(dev
);
416 sc
= device_lookup_private(&gdrom_cd
, unit
);
425 tsleep(&sc
->is_busy
, PRIBIO
, "gdbusy", 0);
429 for (cnt
= 0; cnt
< 5; cnt
++)
430 if ((error
= gdrom_mount_disk(sc
)) == 0)
434 error
= gdrom_read_toc(sc
, &toc
);
437 wakeup(&sc
->is_busy
);
443 sc
->openpart_start
= 150;
446 printf("GDROM: open OK\n");
452 gdromclose(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
454 struct gdrom_softc
*sc
;
457 printf("GDROM: close\n");
459 unit
= DISKUNIT(dev
);
460 sc
= device_lookup_private(&gdrom_cd
, unit
);
468 gdromstrategy(struct buf
*bp
)
470 struct gdrom_softc
*sc
;
473 printf("GDROM: strategy\n");
476 unit
= DISKUNIT(bp
->b_dev
);
477 sc
= device_lookup_private(&gdrom_cd
, unit
);
479 if (bp
->b_bcount
== 0)
482 bp
->b_rawblkno
= bp
->b_blkno
/ (2048 / DEV_BSIZE
) + sc
->openpart_start
;
485 printf("GDROM: read_sectors(%p, %d, %ld) [%ld bytes]\n",
486 bp
->b_data
, bp
->b_rawblkno
,
487 bp
->b_bcount
>>11, bp
->b_bcount
);
491 tsleep(&sc
->is_busy
, PRIBIO
, "gdbusy", 0);
495 if ((error
= gdrom_read_sectors(sc
, bp
->b_data
, bp
->b_rawblkno
,
496 bp
->b_bcount
>> 11)))
500 wakeup(&sc
->is_busy
);
503 bp
->b_resid
= bp
->b_bcount
;
508 gdromioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
510 struct gdrom_softc
*sc
;
513 printf("GDROM: ioctl %lx\n", cmd
);
516 unit
= DISKUNIT(dev
);
517 sc
= device_lookup_private(&gdrom_cd
, unit
);
520 case CDIOREADMSADDR
: {
521 int s
, track
, sessno
= *(int *)addr
;
529 tsleep(&sc
->is_busy
, PRIBIO
, "gdbusy", 0);
533 error
= gdrom_read_toc(sc
, &toc
);
536 wakeup(&sc
->is_busy
);
541 for (track
= TOC_TRACK(toc
.last
);
542 track
>= TOC_TRACK(toc
.first
);
544 if (TOC_CTRL(toc
.entry
[track
-1]))
547 if (track
< TOC_TRACK(toc
.first
) || track
> 100)
550 *(int *)addr
= htonl(TOC_LBA(toc
.entry
[track
-1])) -
560 panic("gdromioctl: impossible");
566 gdromread(dev_t dev
, struct uio
*uio
, int flags
)
569 printf("GDROM: read\n");
571 return physio(gdromstrategy
, NULL
, dev
, B_READ
, minphys
, uio
);
575 gdromwrite(dev_t dev
, struct uio
*uio
, int flags
)