1 /* $NetBSD: gdrom.c,v 1.10 2002/09/06 13:18:43 gehenna 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 #include <sys/conf.h> 49 50 #include <machine/sysasicvar.h> 51 52 int gdrommatch(struct device *, struct cfdata *, void *); 53 void gdromattach(struct device *, struct device *, void *); 54 55 dev_type_open(gdromopen); 56 dev_type_close(gdromclose); 57 dev_type_read(gdromread); 58 dev_type_write(gdromwrite); 59 dev_type_ioctl(gdromioctl); 60 dev_type_strategy(gdromstrategy); 61 62 const struct bdevsw gdrom_bdevsw = { 63 gdromopen, gdromclose, gdromstrategy, gdromioctl, nodump, 64 nosize, D_DISK 65 }; 66 67 const struct cdevsw gdrom_cdevsw = { 68 gdromopen, gdromclose, gdromread, gdromwrite, gdromioctl, 69 nostop, notty, nopoll, nommap, D_DISK 70 }; 71 72 struct gdrom_softc { 73 struct device sc_dv; /* generic device info; must come first */ 74 struct disk dkdev; /* generic disk info */ 75 struct buf curbuf; /* state of current I/O operation */ 76 77 int is_open, is_busy; 78 int openpart_start; /* start sector of currently open partition */ 79 80 int cmd_active; 81 void *cmd_result_buf; /* where to store result data (16 bit aligned) */ 82 int cmd_result_size; /* number of bytes allocated for buf */ 83 int cmd_actual; /* number of bytes actually read */ 84 int cmd_cond; /* resulting condition of command */ 85 }; 86 87 struct cfattach gdrom_ca = { 88 sizeof(struct gdrom_softc), gdrommatch, gdromattach 89 }; 90 91 struct dkdriver gdromdkdriver = { gdromstrategy }; 92 93 extern struct cfdriver gdrom_cd; 94 95 96 struct gd_toc { 97 unsigned int entry[99]; 98 unsigned int first, last; 99 unsigned int leadout; 100 }; 101 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) 106 107 #define GDROM(o) (*(volatile unsigned char *)(0xa05f7000 + (o))) 108 109 #define GDSTATSTAT(n) ((n) & 0xf) 110 #define GDSTATDISK(n) (((n) >> 4) & 0xf) 111 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) 119 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 *); 127 128 int gdrom_getstat() 129 { 130 int s1, s2, s3; 131 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); 145 } 146 147 int 148 gdrom_intr(void *arg) 149 { 150 struct gdrom_softc *sc = arg; 151 int s, cond; 152 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); 164 } 165 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; 183 } 184 } 185 while (cnt > 0) { 186 __volatile int16_t tmp; 187 tmp = GDROM_DATA; 188 cnt -= 2; 189 } 190 } 191 while (GDROM_BUSY & 0x80); 192 193 if ((cond & 8) == 0) { 194 sc->cmd_cond = cond; 195 sc->cmd_active = 0; 196 wakeup(&sc->cmd_active); 197 } 198 199 splx(s); 200 return (0); 201 } 202 203 204 int gdrom_do_command(struct gdrom_softc *sc, void *req, void *buf, 205 unsigned int nbyt) 206 { 207 int i, s; 208 short *ptr = req; 209 210 while (GDROM_BUSY & 0x88) 211 ; 212 if (buf != NULL) { 213 GDROM_CNTLO = nbyt & 0xff; 214 GDROM_CNTHI = (nbyt >> 8) & 0xff; 215 GDROM_REGX = 0; 216 } 217 sc->cmd_result_buf = buf; 218 sc->cmd_result_size = nbyt; 219 220 if (GDSTATSTAT(GDROM_STAT) == 6) 221 return (-1); 222 223 GDROM_COND = 0xa0; 224 for (i = 0; i < 64; i++) 225 ; 226 while ((GDROM_BUSY & 0x88) != 8) 227 ; 228 229 s = splbio(); 230 231 sc->cmd_actual = 0; 232 sc->cmd_active = 1; 233 234 for (i = 0; i< 6; i++) 235 GDROM_DATA = ptr[i]; 236 237 while (sc->cmd_active) 238 tsleep(&sc->cmd_active, PRIBIO, "gdrom", 0); 239 240 splx(s); 241 242 return (sc->cmd_cond); 243 } 244 245 246 int gdrom_command_sense(struct gdrom_softc *sc, void *req, void *buf, 247 unsigned int nbyt) 248 { 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; 259 260 int cond = gdrom_do_command(sc, req, buf, nbyt); 261 262 if (cond < 0) { 263 #ifdef GDROMDEBUG 264 printf("GDROM: not ready (2:58)\n"); 265 #endif 266 return (EIO); 267 } 268 269 if ((cond & 1) == 0) { 270 #ifdef GDROMDEBUG 271 printf("GDROM: no sense. 0:0\n"); 272 #endif 273 return (0); 274 } 275 276 memset(cmd, 0, sizeof(cmd)); 277 278 cmd[0] = 0x13; 279 cmd[4] = sizeof(sense_data); 280 281 gdrom_do_command(sc, cmd, sense_data, sizeof(sense_data)); 282 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); 290 } 291 292 #ifdef GDROMDEBUG 293 printf("GDROM: SENSE %d:", sense_key); 294 printf("GDROM: %d\n", sense_specific); 295 #endif 296 297 return (sense_key == 0 ? 0 : EIO); 298 } 299 300 int gdrom_read_toc(struct gdrom_softc *sc, struct gd_toc *toc) 301 { 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]; 310 311 memset(cmd, 0, sizeof(cmd)); 312 313 cmd[0] = 0x14; 314 cmd[3] = sizeof(struct gd_toc) >> 8; 315 cmd[4] = sizeof(struct gd_toc) & 0xff; 316 317 return (gdrom_command_sense(sc, cmd, toc, sizeof(struct gd_toc))); 318 } 319 320 int gdrom_read_sectors(struct gdrom_softc *sc, void *buf, int sector, int cnt) 321 { 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]; 330 331 memset(cmd, 0, sizeof(cmd)); 332 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; 341 342 return (gdrom_command_sense(sc, cmd, buf, cnt << 11)); 343 } 344 345 int gdrom_mount_disk(struct gdrom_softc *sc) 346 { 347 /* 76543210 76543210 348 0 0x70 - 349 2 0x1f - 350 4 - - 351 6 - - 352 8 - - 353 10 - - */ 354 unsigned char cmd[12]; 355 356 memset(cmd, 0, sizeof(cmd)); 357 358 cmd[0] = 0x70; 359 cmd[1] = 0x1f; 360 361 return (gdrom_command_sense(sc, cmd, NULL, 0)); 362 } 363 364 int 365 gdrommatch(struct device *parent, struct cfdata *cf, void *aux) 366 { 367 static int gdrom_matched = 0; 368 369 /* Allow only once instance. */ 370 if (strcmp("gdrom", cf->cf_driver->cd_name) || gdrom_matched) 371 return (0); 372 gdrom_matched = 1; 373 374 return (1); 375 } 376 377 void 378 gdromattach(struct device *parent, struct device *self, void *aux) 379 { 380 struct gdrom_softc *sc; 381 u_int32_t p, x; 382 383 sc = (struct gdrom_softc *)self; 384 385 printf(": SH4 IRL 9\n"); 386 387 /* 388 * Initialize and attach the disk structure. 389 */ 390 sc->dkdev.dk_name = sc->sc_dv.dv_xname; 391 sc->dkdev.dk_driver = &gdromdkdriver; 392 disk_attach(&sc->dkdev); 393 394 /* 395 * reenable disabled drive 396 */ 397 *((__volatile u_int32_t *)0xa05f74e4) = 0x1fffff; 398 for (p = 0; p < 0x200000 / 4; p++) 399 x = ((__volatile u_int32_t *)0xa0000000)[p]; 400 401 sysasic_intr_establish(SYSASIC_EVENT_GDROM, gdrom_intr, sc); 402 } 403 404 int 405 gdromopen(dev_t dev, int flags, int devtype, struct proc *p) 406 { 407 struct gdrom_softc *sc; 408 int s, error, unit, cnt; 409 struct gd_toc toc; 410 411 #ifdef GDROMDEBUG 412 printf("GDROM: open\n"); 413 #endif 414 415 unit = DISKUNIT(dev); 416 if (unit >= gdrom_cd.cd_ndevs) 417 return (ENXIO); 418 419 sc = gdrom_cd.cd_devs[unit]; 420 if (sc == NULL) 421 return (ENXIO); 422 423 if (sc->is_open) 424 return (EBUSY); 425 426 s = splbio(); 427 while(sc->is_busy) 428 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 429 sc->is_busy = 1; 430 splx(s); 431 432 for (cnt = 0; cnt < 5; cnt++) 433 if ((error = gdrom_mount_disk(sc)) == 0) 434 break; 435 436 if (!error) 437 error = gdrom_read_toc(sc, &toc); 438 439 sc->is_busy = 0; 440 wakeup(&sc->is_busy); 441 442 if (error) 443 return error; 444 445 sc->is_open = 1; 446 sc->openpart_start = 150; 447 448 #ifdef GDROMDEBUG 449 printf("GDROM: open OK\n"); 450 #endif 451 return (0); 452 } 453 454 int 455 gdromclose(dev_t dev, int flags, int devtype, struct proc *p) 456 { 457 struct gdrom_softc *sc; 458 int unit; 459 #ifdef GDROMDEBUG 460 printf("GDROM: close\n"); 461 #endif 462 unit = DISKUNIT(dev); 463 sc = gdrom_cd.cd_devs[unit]; 464 465 sc->is_open = 0; 466 467 return (0); 468 } 469 470 void 471 gdromstrategy(struct buf *bp) 472 { 473 struct gdrom_softc *sc; 474 int s, unit, error; 475 #ifdef GDROMDEBUG 476 printf("GDROM: strategy\n"); 477 #endif 478 479 unit = DISKUNIT(bp->b_dev); 480 sc = gdrom_cd.cd_devs[unit]; 481 482 if (bp->b_bcount == 0) 483 goto done; 484 485 bp->b_rawblkno = bp->b_blkno / (2048 / DEV_BSIZE) + sc->openpart_start; 486 487 #ifdef GDROMDEBUG 488 printf("GDROM: read_sectors(%p, %d, %ld) [%ld bytes]\n", 489 bp->b_data, bp->b_rawblkno, 490 bp->b_bcount>>11, bp->b_bcount); 491 #endif 492 s = splbio(); 493 while (sc->is_busy) 494 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 495 sc->is_busy = 1; 496 splx(s); 497 498 if ((error = gdrom_read_sectors(sc, bp->b_data, bp->b_rawblkno, 499 bp->b_bcount >> 11))) { 500 bp->b_error = error; 501 bp->b_flags |= B_ERROR; 502 } 503 504 sc->is_busy = 0; 505 wakeup(&sc->is_busy); 506 507 done: 508 bp->b_resid = bp->b_bcount; 509 biodone(bp); 510 } 511 512 int 513 gdromioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 514 { 515 struct gdrom_softc *sc; 516 int unit, error; 517 #ifdef GDROMDEBUG 518 printf("GDROM: ioctl %lx\n", cmd); 519 #endif 520 521 unit = DISKUNIT(dev); 522 sc = gdrom_cd.cd_devs[unit]; 523 524 switch (cmd) { 525 case CDIOREADMSADDR: { 526 int s, track, sessno = *(int *)addr; 527 struct gd_toc toc; 528 529 if (sessno != 0) 530 return (EINVAL); 531 532 s = splbio(); 533 while (sc->is_busy) 534 tsleep(&sc->is_busy, PRIBIO, "gdbusy", 0); 535 sc->is_busy = 1; 536 splx(s); 537 538 error = gdrom_read_toc(sc, &toc); 539 540 sc->is_busy = 0; 541 wakeup(&sc->is_busy); 542 543 if (error) 544 return error; 545 546 for (track = TOC_TRACK(toc.last); 547 track >= TOC_TRACK(toc.first); 548 --track) 549 if (TOC_CTRL(toc.entry[track-1])) 550 break; 551 552 if (track < TOC_TRACK(toc.first) || track > 100) 553 return (ENXIO); 554 555 *(int *)addr = htonl(TOC_LBA(toc.entry[track-1])) - 556 sc->openpart_start; 557 558 return (0); 559 } 560 default: 561 return (EINVAL); 562 } 563 564 #ifdef DIAGNOSTIC 565 panic("gdromioctl: impossible"); 566 #endif 567 } 568 569 570 int 571 gdromread(dev_t dev, struct uio *uio, int flags) 572 { 573 #ifdef GDROMDEBUG 574 printf("GDROM: read\n"); 575 #endif 576 return (physio(gdromstrategy, NULL, dev, B_READ, minphys, uio)); 577 } 578 579 int 580 gdromwrite(dev_t dev, struct uio *uio, int flags) 581 { 582 583 return (EROFS); 584 } 585