No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / dreamcast / dev / gdrom.c
blob2e3f21e8275801e6dfd79d63090d82e8d4a6e5f7
1 /* $NetBSD: gdrom.c,v 1.25 2008/06/11 14:55:30 tsutsui Exp $ */
3 /*-
4 * Copyright (c) 2001 Marcus Comstedt
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <sys/fcntl.h>
45 #include <sys/disklabel.h>
46 #include <sys/disk.h>
47 #include <sys/cdio.h>
48 #include <sys/proc.h>
49 #include <sys/conf.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,
65 nosize, D_DISK
68 const struct cdevsw gdrom_cdevsw = {
69 gdromopen, gdromclose, gdromread, gdromwrite, gdromioctl,
70 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
73 struct gdrom_softc {
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 */
78 int is_open, is_busy;
79 int openpart_start; /* start sector of currently open partition */
81 int cmd_active;
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;
96 struct gd_toc {
97 unsigned int entry[99];
98 unsigned int first, last;
99 unsigned int leadout;
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)
130 int s1, s2, s3;
132 if (GDROM_BUSY & 0x80)
133 return -1;
134 s1 = GDROM_STAT;
135 s2 = GDROM_STAT;
136 s3 = GDROM_STAT;
137 if (GDROM_BUSY & 0x80)
138 return -1;
139 if (s1 == s2)
140 return s1;
141 else if (s2 == s3)
142 return s2;
143 else
144 return -1;
148 gdrom_intr(void *arg)
150 struct gdrom_softc *sc = arg;
151 int s, cond;
153 s = splbio();
154 cond = GDROM_COND;
155 #ifdef GDROMDEBUG
156 printf("GDROM: cond = %x\n", cond);
157 #endif
158 if (!sc->cmd_active) {
159 #ifdef GDROMDEBUG
160 printf("GDROM: inactive IRQ!?\n");
161 #endif
162 splx(s);
163 return 0;
166 if ((cond & 8)) {
167 int cnt = (GDROM_CNTHI << 8) | GDROM_CNTLO;
168 #ifdef GDROMDEBUG
169 printf("GDROM: cnt = %d\n", cnt);
170 #endif
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) +
177 subcnt;
178 sc->cmd_result_size -= subcnt;
179 cnt -= subcnt;
180 while (subcnt > 0) {
181 *ptr++ = GDROM_DATA;
182 subcnt -= 2;
185 while (cnt > 0) {
186 volatile int16_t tmp;
187 tmp = GDROM_DATA;
188 cnt -= 2;
191 while (GDROM_BUSY & 0x80);
193 if ((cond & 8) == 0) {
194 sc->cmd_cond = cond;
195 sc->cmd_active = 0;
196 wakeup(&sc->cmd_active);
199 splx(s);
200 return 1;
204 int gdrom_do_command(struct gdrom_softc *sc, void *req, void *buf,
205 unsigned int nbyt)
207 int i, s;
208 short *ptr = req;
210 while (GDROM_BUSY & 0x88)
212 if (buf != NULL) {
213 GDROM_CNTLO = nbyt & 0xff;
214 GDROM_CNTHI = (nbyt >> 8) & 0xff;
215 GDROM_REGX = 0;
217 sc->cmd_result_buf = buf;
218 sc->cmd_result_size = nbyt;
220 if (GDSTATSTAT(GDROM_STAT) == 6)
221 return -1;
223 GDROM_COND = 0xa0;
224 for (i = 0; i < 64; i++)
226 while ((GDROM_BUSY & 0x88) != 8)
229 s = splbio();
231 sc->cmd_actual = 0;
232 sc->cmd_active = 1;
234 for (i = 0; i< 6; i++)
235 GDROM_DATA = ptr[i];
237 while (sc->cmd_active)
238 tsleep(&sc->cmd_active, PRIBIO, "gdrom", 0);
240 splx(s);
242 return sc->cmd_cond;
246 int gdrom_command_sense(struct gdrom_softc *sc, void *req, void *buf,
247 unsigned int nbyt)
249 /* 76543210 76543210
250 0 0x13 -
251 2 - bufsz(hi)
252 4 bufsz(lo) -
253 6 - -
254 8 - -
255 10 - - */
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);
262 if (cond < 0) {
263 #ifdef GDROMDEBUG
264 printf("GDROM: not ready (2:58)\n");
265 #endif
266 return EIO;
269 if ((cond & 1) == 0) {
270 #ifdef GDROMDEBUG
271 printf("GDROM: no sense. 0:0\n");
272 #endif
273 return 0;
276 memset(cmd, 0, sizeof(cmd));
278 cmd[0] = 0x13;
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) {
286 #ifdef GDROMDEBUG
287 printf("GDROM: aborted (ignored). 0:0\n");
288 #endif
289 return 0;
292 #ifdef GDROMDEBUG
293 printf("GDROM: SENSE %d:", sense_key);
294 printf("GDROM: %d\n", sense_specific);
295 #endif
297 return sense_key == 0 ? 0 : EIO;
300 int gdrom_read_toc(struct gdrom_softc *sc, struct gd_toc *toc)
302 /* 76543210 76543210
303 0 0x14 -
304 2 - bufsz(hi)
305 4 bufsz(lo) -
306 6 - -
307 8 - -
308 10 - - */
309 unsigned char cmd[12];
311 memset(cmd, 0, sizeof(cmd));
313 cmd[0] = 0x14;
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)
322 /* 76543210 76543210
323 0 0x30 datafmt
324 2 sec(hi) sec(mid)
325 4 sec(lo) -
326 6 - -
327 8 cnt(hi) cnt(mid)
328 10 cnt(lo) - */
329 unsigned char cmd[12];
331 memset(cmd, 0, sizeof(cmd));
333 cmd[0] = 0x30;
334 cmd[1] = 0x20;
335 cmd[2] = sector>>16;
336 cmd[3] = sector>>8;
337 cmd[4] = sector;
338 cmd[8] = cnt>>16;
339 cmd[9] = cnt>>8;
340 cmd[10] = cnt;
342 return gdrom_command_sense(sc, cmd, buf, cnt << 11);
345 int gdrom_mount_disk(struct gdrom_softc *sc)
347 /* 76543210 76543210
348 0 0x70 -
349 2 0x1f -
350 4 - -
351 6 - -
352 8 - -
353 10 - - */
354 unsigned char cmd[12];
356 memset(cmd, 0, sizeof(cmd));
358 cmd[0] = 0x70;
359 cmd[1] = 0x1f;
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. */
370 if (gdrom_matched)
371 return 0;
372 gdrom_matched = 1;
374 return 1;
377 void
378 gdromattach(struct device *parent, struct device *self, void *aux)
380 struct gdrom_softc *sc;
381 uint32_t p, x;
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,
400 gdrom_intr, sc);
404 gdromopen(dev_t dev, int flags, int devtype, struct lwp *l)
406 struct gdrom_softc *sc;
407 int s, error, unit, cnt;
408 struct gd_toc toc;
410 #ifdef GDROMDEBUG
411 printf("GDROM: open\n");
412 #endif
414 unit = DISKUNIT(dev);
416 sc = device_lookup_private(&gdrom_cd, unit);
417 if (sc == NULL)
418 return ENXIO;
420 if (sc->is_open)
421 return EBUSY;
423 s = splbio();
424 while (sc->is_busy)
425 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0);
426 sc->is_busy = 1;
427 splx(s);
429 for (cnt = 0; cnt < 5; cnt++)
430 if ((error = gdrom_mount_disk(sc)) == 0)
431 break;
433 if (!error)
434 error = gdrom_read_toc(sc, &toc);
436 sc->is_busy = 0;
437 wakeup(&sc->is_busy);
439 if (error)
440 return error;
442 sc->is_open = 1;
443 sc->openpart_start = 150;
445 #ifdef GDROMDEBUG
446 printf("GDROM: open OK\n");
447 #endif
448 return 0;
452 gdromclose(dev_t dev, int flags, int devtype, struct lwp *l)
454 struct gdrom_softc *sc;
455 int unit;
456 #ifdef GDROMDEBUG
457 printf("GDROM: close\n");
458 #endif
459 unit = DISKUNIT(dev);
460 sc = device_lookup_private(&gdrom_cd, unit);
462 sc->is_open = 0;
464 return 0;
467 void
468 gdromstrategy(struct buf *bp)
470 struct gdrom_softc *sc;
471 int s, unit, error;
472 #ifdef GDROMDEBUG
473 printf("GDROM: strategy\n");
474 #endif
476 unit = DISKUNIT(bp->b_dev);
477 sc = device_lookup_private(&gdrom_cd, unit);
479 if (bp->b_bcount == 0)
480 goto done;
482 bp->b_rawblkno = bp->b_blkno / (2048 / DEV_BSIZE) + sc->openpart_start;
484 #ifdef GDROMDEBUG
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);
488 #endif
489 s = splbio();
490 while (sc->is_busy)
491 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0);
492 sc->is_busy = 1;
493 splx(s);
495 if ((error = gdrom_read_sectors(sc, bp->b_data, bp->b_rawblkno,
496 bp->b_bcount >> 11)))
497 bp->b_error = error;
499 sc->is_busy = 0;
500 wakeup(&sc->is_busy);
502 done:
503 bp->b_resid = bp->b_bcount;
504 biodone(bp);
508 gdromioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
510 struct gdrom_softc *sc;
511 int unit, error;
512 #ifdef GDROMDEBUG
513 printf("GDROM: ioctl %lx\n", cmd);
514 #endif
516 unit = DISKUNIT(dev);
517 sc = device_lookup_private(&gdrom_cd, unit);
519 switch (cmd) {
520 case CDIOREADMSADDR: {
521 int s, track, sessno = *(int *)addr;
522 struct gd_toc toc;
524 if (sessno != 0)
525 return EINVAL;
527 s = splbio();
528 while (sc->is_busy)
529 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0);
530 sc->is_busy = 1;
531 splx(s);
533 error = gdrom_read_toc(sc, &toc);
535 sc->is_busy = 0;
536 wakeup(&sc->is_busy);
538 if (error)
539 return error;
541 for (track = TOC_TRACK(toc.last);
542 track >= TOC_TRACK(toc.first);
543 --track)
544 if (TOC_CTRL(toc.entry[track-1]))
545 break;
547 if (track < TOC_TRACK(toc.first) || track > 100)
548 return ENXIO;
550 *(int *)addr = htonl(TOC_LBA(toc.entry[track-1])) -
551 sc->openpart_start;
553 return 0;
555 default:
556 return EINVAL;
559 #ifdef DIAGNOSTIC
560 panic("gdromioctl: impossible");
561 #endif
566 gdromread(dev_t dev, struct uio *uio, int flags)
568 #ifdef GDROMDEBUG
569 printf("GDROM: read\n");
570 #endif
571 return physio(gdromstrategy, NULL, dev, B_READ, minphys, uio);
575 gdromwrite(dev_t dev, struct uio *uio, int flags)
578 return EROFS;