1 /* $NetBSD: gdrom.c,v 1.8 2002/03/25 18:59:39 uch Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 Marcus Comstedt 5 * All rights reserved. 6 * 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. 21 * 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. 33 */ 34 35 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 41 #include <sys/buf.h> 42 #include <sys/ioctl.h> 43 #include <sys/fcntl.h> 44 #include <sys/disklabel.h> 45 #include <sys/disk.h> 46 #include <sys/cdio.h> 47 #include <sys/proc.h> 48 49 #include <machine/sysasicvar.h> 50 51 int gdrommatch(struct device *, struct cfdata *, void *); 52 void gdromattach(struct device *, struct device *, void *); 53 int gdromopen(dev_t, int, int, struct proc *); 54 int gdromclose(dev_t, int, int, struct proc *); 55 void gdromstrategy(struct buf *); 56 int gdromioctl(dev_t, u_long, caddr_t, int, struct proc *); 57 int gdromdump(dev_t, daddr_t, caddr_t, size_t); 58 int gdromsize(dev_t); 59 int gdromread(dev_t, struct uio *, int); 60 int gdromwrite(dev_t, struct uio *, int); 61 62 struct gdrom_softc { 63 struct device sc_dv; /* generic device info; must come first */ 64 struct disk dkdev; /* generic disk info */ 65 struct buf_queue bufq; /* queue pending I/O operations */ 66 struct buf curbuf; /* state of current I/O operation */ 67 68 int is_open, is_busy; 69 int openpart_start; /* start sector of currently open partition */ 70 71 int cmd_active; 72 void *cmd_result_buf; /* where to store result data (16 bit aligned) */ 73 int cmd_result_size; /* number of bytes allocated for buf */ 74 int cmd_actual; /* number of bytes actually read */ 75 int cmd_cond; /* resulting condition of command */ 76 }; 77 78 struct cfattach gdrom_ca = { 79 sizeof(struct gdrom_softc), gdrommatch, gdromattach 80 }; 81 82 struct dkdriver gdromdkdriver = { gdromstrategy }; 83 84 extern struct cfdriver gdrom_cd; 85 86 87 struct gd_toc { 88 unsigned int entry[99]; 89 unsigned int first, last; 90 unsigned int leadout; 91 }; 92 93 #define TOC_LBA(n) ((n) & 0xffffff00) 94 #define TOC_ADR(n) ((n) & 0x0f) 95 #define TOC_CTRL(n) (((n) & 0xf0) >> 4) 96 #define TOC_TRACK(n) (((n) & 0x0000ff00) >> 8) 97 98 #define GDROM(o) (*(volatile unsigned char *)(0xa05f7000 + (o))) 99 100 #define GDSTATSTAT(n) ((n) & 0xf) 101 #define GDSTATDISK(n) (((n) >> 4) & 0xf) 102 103 #define GDROM_BUSY GDROM(0x18) 104 #define GDROM_DATA (*(volatile short *) & GDROM(0x80)) 105 #define GDROM_REGX GDROM(0x84) 106 #define GDROM_STAT GDROM(0x8c) 107 #define GDROM_CNTLO GDROM(0x90) 108 #define GDROM_CNTHI GDROM(0x94) 109 #define GDROM_COND GDROM(0x9c) 110 111 int gdrom_getstat(void); 112 int gdrom_do_command(struct gdrom_softc *, void *, void *, unsigned int); 113 int gdrom_command_sense(struct gdrom_softc *, void *, void *, unsigned int); 114 int gdrom_read_toc(struct gdrom_softc *, struct gd_toc *); 115 int gdrom_read_sectors(struct gdrom_softc *, void *, int, int); 116 int gdrom_mount_disk(struct gdrom_softc *); 117 int gdrom_intr(void *); 118 119 int gdrom_getstat() 120 { 121 int s1, s2, s3; 122 123 if (GDROM_BUSY & 0x80) 124 return (-1); 125 s1 = GDROM_STAT; 126 s2 = GDROM_STAT; 127 s3 = GDROM_STAT; 128 if(GDROM_BUSY & 0x80) 129 return (-1); 130 if(s1 == s2) 131 return (s1); 132 else if(s2 == s3) 133 return (s2); 134 else 135 return (-1); 136 } 137 138 int 139 gdrom_intr(void *arg) 140 { 141 struct gdrom_softc *sc = arg; 142 int s, cond; 143 144 s = splbio(); 145 cond = GDROM_COND; 146 #ifdef GDROMDEBUG 147 printf("GDROM: cond = %x\n", cond); 148 #endif 149 if(!sc->cmd_active) { 150 #ifdef GDROMDEBUG 151 printf("GDROM: inactive IRQ!?\n"); 152 #endif 153 splx(s); 154 return (0); 155 } 156 157 if((cond & 8)) { 158 int cnt = (GDROM_CNTHI << 8) | GDROM_CNTLO; 159 #ifdef GDROMDEBUG 160 printf("GDROM: cnt = %d\n", cnt); 161 #endif 162 sc->cmd_actual += cnt; 163 if(cnt > 0 && sc->cmd_result_size > 0) { 164 int subcnt = (cnt > sc->cmd_result_size ? 165 sc->cmd_result_size : cnt); 166 int16_t *ptr = sc->cmd_result_buf; 167 sc->cmd_result_buf = ((char *)sc->cmd_result_buf) + 168 subcnt; 169 sc->cmd_result_size -= subcnt; 170 cnt -= subcnt; 171 while (subcnt > 0) { 172 *ptr++ = GDROM_DATA; 173 subcnt -= 2; 174 } 175 } 176 while (cnt > 0) { 177 __volatile int16_t tmp; 178 tmp = GDROM_DATA; 179 cnt -= 2; 180 } 181 } 182 while (GDROM_BUSY & 0x80); 183 184 if ((cond & 8) == 0) { 185 sc->cmd_cond = cond; 186 sc->cmd_active = 0; 187 wakeup(&sc->cmd_active); 188 } 189 190 splx(s); 191 return (0); 192 } 193 194 195 int gdrom_do_command(struct gdrom_softc *sc, void *req, void *buf, 196 unsigned int nbyt) 197 { 198 int i, s; 199 short *ptr = req; 200 201 while (GDROM_BUSY & 0x88) 202 ; 203 if (buf != NULL) { 204 GDROM_CNTLO = nbyt & 0xff; 205 GDROM_CNTHI = (nbyt >> 8) & 0xff; 206 GDROM_REGX = 0; 207 } 208 sc->cmd_result_buf = buf; 209 sc->cmd_result_size = nbyt; 210 211 if (GDSTATSTAT(GDROM_STAT) == 6) 212 return (-1); 213 214 GDROM_COND = 0xa0; 215 for (i = 0; i < 64; i++) 216 ; 217 while ((GDROM_BUSY & 0x88) != 8) 218 ; 219 220 s = splbio(); 221 222 sc->cmd_actual = 0; 223 sc->cmd_active = 1; 224 225 for (i = 0; i< 6; i++) 226 GDROM_DATA = ptr[i]; 227 228 while (sc->cmd_active) 229 tsleep(&sc->cmd_active, PRIBIO, "gdrom", 0); 230 231 splx(s); 232 233 return (sc->cmd_cond); 234 } 235 236 237 int gdrom_command_sense(struct gdrom_softc *sc, void *req, void *buf, 238 unsigned int nbyt) 239 { 240 /* 76543210 76543210 241 0 0x13 - 242 2 - bufsz(hi) 243 4 bufsz(lo) - 244 6 - - 245 8 - - 246 10 - - */ 247 unsigned short sense_data[5]; 248 unsigned char cmd[12]; 249 int sense_key, sense_specific; 250 251 int cond = gdrom_do_command(sc, req, buf, nbyt); 252 253 if (cond < 0) { 254 #ifdef GDROMDEBUG 255 printf("GDROM: not ready (2:58)\n"); 256 #endif 257 return (EIO); 258 } 259 260 if ((cond & 1) == 0) { 261 #ifdef GDROMDEBUG 262 printf("GDROM: no sense. 0:0\n"); 263 #endif 264 return (0); 265 } 266 267 memset(cmd, 0, sizeof(cmd)); 268 269 cmd[0] = 0x13; 270 cmd[4] = sizeof(sense_data); 271 272 gdrom_do_command(sc, cmd, sense_data, sizeof(sense_data)); 273 274 sense_key = sense_data[1] & 0xf; 275 sense_specific = sense_data[4]; 276 if (sense_key == 11 && sense_specific == 0) { 277 #ifdef GDROMDEBUG 278 printf("GDROM: aborted (ignored). 0:0\n"); 279 #endif 280 return (0); 281 } 282 283 #ifdef GDROMDEBUG 284 printf("GDROM: SENSE %d:", sense_key); 285 printf("GDROM: %d\n", sense_specific); 286 #endif 287 288 return (sense_key == 0 ? 0 : EIO); 289 } 290 291 int gdrom_read_toc(struct gdrom_softc *sc, struct gd_toc *toc) 292 { 293 /* 76543210 76543210 294 0 0x14 - 295 2 - bufsz(hi) 296 4 bufsz(lo) - 297 6 - - 298 8 - - 299 10 - - */ 300 unsigned char cmd[12]; 301 302 memset(cmd, 0, sizeof(cmd)); 303 304 cmd[0] = 0x14; 305 cmd[3] = sizeof(struct gd_toc) >> 8; 306 cmd[4] = sizeof(struct gd_toc) & 0xff; 307 308 return (gdrom_command_sense(sc, cmd, toc, sizeof(struct gd_toc))); 309 } 310 311 int gdrom_read_sectors(struct gdrom_softc *sc, void *buf, int sector, int cnt) 312 { 313 /* 76543210 76543210 314 0 0x30 datafmt 315 2 sec(hi) sec(mid) 316 4 sec(lo) - 317 6 - - 318 8 cnt(hi) cnt(mid) 319 10 cnt(lo) - */ 320 unsigned char cmd[12]; 321 322 memset(cmd, 0, sizeof(cmd)); 323 324 cmd[0] = 0x30; 325 cmd[1] = 0x20; 326 cmd[2] = sector>>16; 327 cmd[3] = sector>>8; 328 cmd[4] = sector; 329 cmd[8] = cnt>>16; 330 cmd[9] = cnt>>8; 331 cmd[10] = cnt; 332 333 return (gdrom_command_sense(sc, cmd, buf, cnt << 11)); 334 } 335 336 int gdrom_mount_disk(struct gdrom_softc *sc) 337 { 338 /* 76543210 76543210 339 0 0x70 - 340 2 0x1f - 341 4 - - 342 6 - - 343 8 - - 344 10 - - */ 345 unsigned char cmd[12]; 346 347 memset(cmd, 0, sizeof(cmd)); 348 349 cmd[0] = 0x70; 350 cmd[1] = 0x1f; 351 352 return (gdrom_command_sense(sc, cmd, NULL, 0)); 353 } 354 355 int 356 gdrommatch(struct device *parent, struct cfdata *cf, void *aux) 357 { 358 static int gdrom_matched = 0; 359 360 /* Allow only once instance. */ 361 if (strcmp("gdrom", cf->cf_driver->cd_name) || gdrom_matched) 362 return (0); 363 gdrom_matched = 1; 364 365 return (1); 366 } 367 368 void 369 gdromattach(struct device *parent, struct device *self, void *aux) 370 { 371 struct gdrom_softc *sc; 372 u_int32_t p, x; 373 374 sc = (struct gdrom_softc *)self; 375 376 BUFQ_INIT(&sc->bufq); 377 378 printf(": SH4 IRL 9\n"); 379 380 /* 381 * Initialize and attach the disk structure. 382 */ 383 sc->dkdev.dk_name = sc->sc_dv.dv_xname; 384 sc->dkdev.dk_driver = &gdromdkdriver; 385 disk_attach(&sc->dkdev); 386 387 /* 388 * reenable disabled drive 389 */ 390 *((__volatile u_int32_t *)0xa05f74e4) = 0x1fffff; 391 for (p = 0; p < 0x200000 / 4; p++) 392 x = ((__volatile u_int32_t *)0xa0000000)[p]; 393 394 sysasic_intr_establish(SYSASIC_EVENT_GDROM, gdrom_intr, sc); 395 } 396 397 int 398 gdromopen(dev_t dev, int flags, int devtype, struct proc *p) 399 { 400 struct gdrom_softc *sc; 401 int s, error, unit, cnt; 402 struct gd_toc toc; 403 404 #ifdef GDROMDEBUG 405 printf("GDROM: open\n"); 406 #endif 407 408 unit = DISKUNIT(dev); 409 if (unit >= gdrom_cd.cd_ndevs) 410 return (ENXIO); 411 412 sc = gdrom_cd.cd_devs[unit]; 413 if (sc == NULL) 414 return (ENXIO); 415 416 if (sc->is_open) 417 return (EBUSY); 418 419 s = splbio(); 420 while(sc->is_busy) 421 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 422 sc->is_busy = 1; 423 splx(s); 424 425 for (cnt = 0; cnt < 5; cnt++) 426 if ((error = gdrom_mount_disk(sc)) == 0) 427 break; 428 429 if (!error) 430 error = gdrom_read_toc(sc, &toc); 431 432 sc->is_busy = 0; 433 wakeup(&sc->is_busy); 434 435 if (error) 436 return error; 437 438 sc->is_open = 1; 439 sc->openpart_start = 150; 440 441 #ifdef GDROMDEBUG 442 printf("GDROM: open OK\n"); 443 #endif 444 return (0); 445 } 446 447 int 448 gdromclose(dev_t dev, int flags, int devtype, struct proc *p) 449 { 450 struct gdrom_softc *sc; 451 int unit; 452 #ifdef GDROMDEBUG 453 printf("GDROM: close\n"); 454 #endif 455 unit = DISKUNIT(dev); 456 sc = gdrom_cd.cd_devs[unit]; 457 458 sc->is_open = 0; 459 460 return (0); 461 } 462 463 void 464 gdromstrategy(struct buf *bp) 465 { 466 struct gdrom_softc *sc; 467 int s, unit, error; 468 #ifdef GDROMDEBUG 469 printf("GDROM: strategy\n"); 470 #endif 471 472 unit = DISKUNIT(bp->b_dev); 473 sc = gdrom_cd.cd_devs[unit]; 474 475 if (bp->b_bcount == 0) 476 goto done; 477 478 bp->b_rawblkno = bp->b_blkno / (2048 / DEV_BSIZE) + sc->openpart_start; 479 480 #ifdef GDROMDEBUG 481 printf("GDROM: read_sectors(%p, %d, %ld) [%ld bytes]\n", 482 bp->b_data, bp->b_rawblkno, 483 bp->b_bcount>>11, bp->b_bcount); 484 #endif 485 s = splbio(); 486 while (sc->is_busy) 487 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 488 sc->is_busy = 1; 489 splx(s); 490 491 if ((error = gdrom_read_sectors(sc, bp->b_data, bp->b_rawblkno, 492 bp->b_bcount >> 11))) { 493 bp->b_error = error; 494 bp->b_flags |= B_ERROR; 495 } 496 497 sc->is_busy = 0; 498 wakeup(&sc->is_busy); 499 500 done: 501 bp->b_resid = bp->b_bcount; 502 biodone(bp); 503 } 504 505 int 506 gdromioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 507 { 508 struct gdrom_softc *sc; 509 int unit, error; 510 #ifdef GDROMDEBUG 511 printf("GDROM: ioctl %lx\n", cmd); 512 #endif 513 514 unit = DISKUNIT(dev); 515 sc = gdrom_cd.cd_devs[unit]; 516 517 switch (cmd) { 518 case CDIOREADMSADDR: { 519 int s, track, sessno = *(int *)addr; 520 struct gd_toc toc; 521 522 if (sessno != 0) 523 return (EINVAL); 524 525 s = splbio(); 526 while (sc->is_busy) 527 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 528 sc->is_busy = 1; 529 splx(s); 530 531 error = gdrom_read_toc(sc, &toc); 532 533 sc->is_busy = 0; 534 wakeup(&sc->is_busy); 535 536 if (error) 537 return error; 538 539 for (track = TOC_TRACK(toc.last); 540 track >= TOC_TRACK(toc.first); 541 --track) 542 if (TOC_CTRL(toc.entry[track-1])) 543 break; 544 545 if (track < TOC_TRACK(toc.first) || track > 100) 546 return (ENXIO); 547 548 *(int *)addr = htonl(TOC_LBA(toc.entry[track-1])) - 549 sc->openpart_start; 550 551 return (0); 552 } 553 default: 554 return (EINVAL); 555 } 556 557 #ifdef DIAGNOSTIC 558 panic("gdromioctl: impossible"); 559 #endif 560 } 561 562 563 /* 564 * Can't dump to CD; read only media... 565 */ 566 int 567 gdromdump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 568 { 569 570 return (EINVAL); 571 } 572 573 int 574 gdromsize(dev_t dev) 575 { 576 577 return (-1); 578 } 579 580 int 581 gdromread(dev_t dev, struct uio *uio, int flags) 582 { 583 #ifdef GDROMDEBUG 584 printf("GDROM: read\n"); 585 #endif 586 return (physio(gdromstrategy, NULL, dev, B_READ, minphys, uio)); 587 } 588 589 int 590 gdromwrite(dev_t dev, struct uio *uio, int flags) 591 { 592 593 return (EROFS); 594 } 595