This source file includes following definitions.
- debug
 
- flag_low
 
- sleep_timer
 
- sleep_flag_low
 
- send_cmd
 
- send_params
 
- send_seek_params
 
- get_exec_status
 
- get_data
 
- reset_drive
 
- stdt_flags
 
- fetch_status
 
- fetch_data
 
- flush_data
 
- exec_cmd
 
- exec_read_cmd
 
- exec_seek_cmd
 
- exec_long_cmd
 
- single_bin2bcd
 
- bin2bcd
 
- lba2msf
 
- bcd2bin
 
- msf2lba
 
- msf_bcd2bin
 
- drive_status
 
- get_q_channel
 
- toc_debug_info
 
- read_toc
 
- get_multi_disk_info
 
- update_toc
 
- opt_invalidate_buffers
 
- transfer
 
- poll
 
- do_optcd_request
 
- cdrompause
 
- cdromresume
 
- cdromplaymsf
 
- cdromplaytrkind
 
- cdromreadtochdr
 
- cdromreadtocentry
 
- cdromvolctrl
 
- cdromsubchnl
 
- cdromread
 
- cdromseek
 
- cdrommultisession
 
- cdromreset
 
- opt_ioctl
 
- opt_open
 
- opt_release
 
- opt_media_change
 
- version_ok
 
- optcd_setup
 
- optcd_init
 
- init_module
 
- cleanup_module
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 
  43 
  44 
  45 
  46 
  47 
  48 
  49 
  50 
  51 
  52 
  53 
  54 
  55 
  56 
  57 
  58 
  59 
  60 
  61 #include <linux/module.h>
  62 #include <linux/mm.h>
  63 #include <linux/ioport.h>
  64 #include <asm/io.h>
  65 
  66 #define MAJOR_NR OPTICS_CDROM_MAJOR
  67 #include <linux/blk.h>
  68 
  69 #include <linux/cdrom.h>
  70 #include <linux/optcd.h>
  71 
  72 
  73 
  74 
  75 
  76 
  77 #if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
  78     DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
  79 #define DEBUG(x) debug x
  80 static void debug(int debug_this, const char* fmt, ...)
     
  81 {
  82         char s[1024];
  83         va_list args;
  84 
  85         if (!debug_this)
  86                 return;
  87 
  88         va_start(args, fmt);
  89         vsprintf(s, fmt, args);
  90         printk("optcd: %s\n", s);
  91         va_end(args);
  92 }
  93 #else
  94 #define DEBUG(x)
  95 #endif
  96 
  97 
  98 
  99 
 100 
 101 #define optcd_port optcd                        
 102 static short optcd_port = OPTCD_PORTBASE;       
 103 
 104 
 105 #define DATA_PORT       optcd_port      
 106 #define STATUS_PORT     optcd_port+1    
 107 
 108 
 109 #define COMIN_PORT      optcd_port      
 110 #define RESET_PORT      optcd_port+1    
 111 #define HCON_PORT       optcd_port+2    
 112 
 113 
 114 
 115 #define ST_DRVERR               0x80
 116 #define ST_DOOR_OPEN            0x40
 117 #define ST_MIXEDMODE_DISK       0x20
 118 #define ST_MODE_BITS            0x1c
 119 #define ST_M_STOP               0x00
 120 #define ST_M_READ               0x04
 121 #define ST_M_AUDIO              0x04
 122 #define ST_M_PAUSE              0x08
 123 #define ST_M_INITIAL            0x0c
 124 #define ST_M_ERROR              0x10
 125 #define ST_M_OTHERS             0x14
 126 #define ST_MODE2TRACK           0x02
 127 #define ST_DSK_CHG              0x01
 128 #define ST_L_LOCK               0x01
 129 #define ST_CMD_OK               0x00
 130 #define ST_OP_OK                0x01
 131 #define ST_PA_OK                0x02
 132 #define ST_OP_ERROR             0x05
 133 #define ST_PA_ERROR             0x06
 134 
 135 
 136 
 137 
 138 #define ERR_ILLCMD      0x11    
 139 #define ERR_ILLPARM     0x12    
 140 #define ERR_SLEDGE      0x13
 141 #define ERR_FOCUS       0x14
 142 #define ERR_MOTOR       0x15
 143 #define ERR_RADIAL      0x16
 144 #define ERR_PLL         0x17    
 145 #define ERR_SUB_TIM     0x18    
 146 #define ERR_SUB_NF      0x19    
 147 #define ERR_TRAY        0x1a
 148 #define ERR_TOC         0x1b    
 149 #define ERR_JUMP        0x1c
 150 
 151 #define ERR_MODE        0x21
 152 #define ERR_FORM        0x22
 153 #define ERR_HEADADDR    0x23    
 154 #define ERR_CRC         0x24
 155 #define ERR_ECC         0x25    
 156 #define ERR_CRC_UNC     0x26    
 157 #define ERR_ILLBSYNC    0x27    
 158 #define ERR_VDST        0x28    
 159 
 160 #define ERR_READ_TIM    0x31    
 161 #define ERR_DEC_STP     0x32    
 162 #define ERR_DEC_TIM     0x33    
 163 
 164 #define ERR_KEY         0x41    
 165 #define ERR_READ_FINISH 0x42    
 166 
 167 #define ERR_NOBSYNC     0x01    
 168 #define ERR_SHORTB      0x02    
 169 #define ERR_LONGB       0x03    
 170 #define ERR_SHORTDSP    0x04    
 171 #define ERR_LONGDSP     0x05    
 172 
 173 
 174 
 175 #define FL_EJECT        0x20
 176 #define FL_WAIT         0x10    
 177 #define FL_EOP          0x08    
 178 #define FL_STEN         0x04    
 179 #define FL_DTEN         0x02    
 180 #define FL_DRQ          0x01    
 181 #define FL_RESET        0xde    
 182 #define FL_STDT         (FL_STEN|FL_DTEN)
 183 
 184 
 185 
 186 #define HCON_DTS        0x08
 187 #define HCON_SDRQB      0x04
 188 #define HCON_LOHI       0x02
 189 #define HCON_DMA16      0x01
 190 
 191 
 192 
 193 
 194 #define COMDRVST        0x20    
 195 #define COMERRST        0x21    
 196 #define COMIOCTLISTAT   0x22    
 197 #define COMINITSINGLE   0x28    
 198 #define COMINITDOUBLE   0x29    
 199 #define COMUNLOCK       0x30    
 200 #define COMLOCK         0x31    
 201 #define COMLOCKST       0x32    
 202 #define COMVERSION      0x40    
 203 #define COMVOIDREADMODE 0x50    
 204 
 205 #define COMFETCH        0x60    
 206 #define COMREAD         0x61    
 207 #define COMREADRAW      0x62    
 208 #define COMREADALL      0x63    
 209 
 210 #define COMLEADIN       0x70    
 211 #define COMSEEK         0x71    
 212 #define COMPAUSEON      0x80    
 213 #define COMPAUSEOFF     0x81    
 214 #define COMSTOP         0x82    
 215 #define COMOPEN         0x90    
 216 #define COMCLOSE        0x91    
 217 #define COMPLAY         0xa0    
 218 #define COMPLAY_TNO     0xa2    
 219 #define COMSUBQ         0xb0    
 220 #define COMLOCATION     0xb1    
 221 
 222 #define COMCHCTRL       0xc0    
 223 
 224 #define COMDRVTEST      0xd0    
 225 #define COMTEST         0xd1    
 226 
 227 
 228 
 229 
 230 
 231 
 232 inline static int flag_low(int flag, unsigned long timeout)
     
 233 {
 234         int flag_high;
 235         unsigned long count = 0;
 236 
 237         while ((flag_high = (inb(STATUS_PORT) & flag)))
 238                 if (++count >= timeout)
 239                         break;
 240 
 241         DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
 242                 flag, count, flag_high ? " timeout" : ""));
 243         return !flag_high;
 244 }
 245 
 246 
 247 
 248 static int sleep_timeout;       
 249 static struct wait_queue *waitq = NULL;
 250 static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL};
 251 
 252 #define SET_TIMER(func, jifs) \
 253         delay_timer.expires = jiffies+(jifs); \
 254         delay_timer.function = (void *) (func); \
 255         add_timer(&delay_timer);
 256 #define CLEAR_TIMER     del_timer(&delay_timer)
 257 
 258 
 259 
 260 
 261 static void sleep_timer(void)
     
 262 {
 263         int flags = inb(STATUS_PORT) & FL_STDT;
 264 
 265         if (flags == FL_STDT && --sleep_timeout > 0) {
 266                 SET_TIMER(sleep_timer, HZ/100); 
 267         } else
 268                 wake_up(&waitq);
 269 }
 270 
 271 
 272 
 273 static int sleep_flag_low(int flag, unsigned long timeout)
     
 274 {
 275         int flag_high;
 276 
 277         DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
 278 
 279         sleep_timeout = timeout;
 280         flag_high = inb(STATUS_PORT) & flag;
 281         if (flag_high && sleep_timeout > 0) {
 282                 SET_TIMER(sleep_timer, HZ/100);
 283                 sleep_on(&waitq);
 284                 flag_high = inb(STATUS_PORT) & flag;
 285         }
 286 
 287         DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
 288                 flag, timeout, flag_high ? " timeout" : ""));
 289         return !flag_high;
 290 }
 291 
 292 
 293 
 294 
 295 
 296 
 297 #define ERR_IF_CMD_TIMEOUT      0x100
 298 #define ERR_IF_ERR_TIMEOUT      0x101
 299 #define ERR_IF_RESP_TIMEOUT     0x102
 300 #define ERR_IF_DATA_TIMEOUT     0x103
 301 #define ERR_IF_NOSTAT           0x104
 302 
 303 
 304 
 305 static int send_cmd(int cmd)
     
 306 {
 307         unsigned char ack;
 308 
 309         DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
 310 
 311         outb(HCON_DTS, HCON_PORT);      
 312         outb(cmd, COMIN_PORT);          
 313         if (!flag_low(FL_STEN, BUSY_TIMEOUT))   
 314                 return -ERR_IF_CMD_TIMEOUT;
 315         ack = inb(DATA_PORT);           
 316         outb(HCON_SDRQB, HCON_PORT);    
 317         return ack==ST_OP_OK ? 0 : -ack;
 318 }
 319 
 320 
 321 
 322 static int send_params(struct cdrom_msf *params)
     
 323 {
 324         unsigned char ack;
 325 
 326         DEBUG((DEBUG_DRIVE_IF, "sending parameters"
 327                 " %02x:%02x:%02x"
 328                 " %02x:%02x:%02x",
 329                 params->cdmsf_min0,
 330                 params->cdmsf_sec0,
 331                 params->cdmsf_frame0,
 332                 params->cdmsf_min1,
 333                 params->cdmsf_sec1,
 334                 params->cdmsf_frame1));
 335 
 336         outb(params->cdmsf_min0, COMIN_PORT);
 337         outb(params->cdmsf_sec0, COMIN_PORT);
 338         outb(params->cdmsf_frame0, COMIN_PORT);
 339         outb(params->cdmsf_min1, COMIN_PORT);
 340         outb(params->cdmsf_sec1, COMIN_PORT);
 341         outb(params->cdmsf_frame1, COMIN_PORT);
 342         if (!flag_low(FL_STEN, BUSY_TIMEOUT))   
 343                 return -ERR_IF_CMD_TIMEOUT;
 344         ack = inb(DATA_PORT);           
 345         return ack==ST_PA_OK ? 0 : -ack;
 346 }
 347 
 348 
 349 
 350 static int send_seek_params(struct cdrom_msf *params)
     
 351 {
 352         unsigned char ack;
 353 
 354         DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
 355                 " %02x:%02x:%02x",
 356                 params->cdmsf_min0,
 357                 params->cdmsf_sec0,
 358                 params->cdmsf_frame0));
 359 
 360         outb(params->cdmsf_min0, COMIN_PORT);
 361         outb(params->cdmsf_sec0, COMIN_PORT);
 362         outb(params->cdmsf_frame0, COMIN_PORT);
 363         if (!flag_low(FL_STEN, BUSY_TIMEOUT))   
 364                 return -ERR_IF_CMD_TIMEOUT;
 365         ack = inb(DATA_PORT);           
 366         return ack==ST_PA_OK ? 0 : -ack;
 367 }
 368 
 369 
 370 
 371 
 372 inline static int get_exec_status(int busy_waiting)
     
 373 {
 374         unsigned char exec_status;
 375 
 376         if (busy_waiting
 377             ? !flag_low(FL_STEN, BUSY_TIMEOUT)
 378             : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
 379                 return -ERR_IF_CMD_TIMEOUT;
 380 
 381         exec_status = inb(DATA_PORT);
 382         DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
 383         return exec_status;
 384 }
 385 
 386 
 387 
 388 
 389 inline static int get_data(int short_timeout)
     
 390 {
 391         unsigned char data;
 392 
 393         if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
 394                 return -ERR_IF_DATA_TIMEOUT;
 395 
 396         data = inb(DATA_PORT);
 397         DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
 398         return data;
 399 }
 400 
 401 
 402 
 403 static int reset_drive(void)
     
 404 {
 405         unsigned long count = 0;
 406         int flags;
 407 
 408         DEBUG((DEBUG_DRIVE_IF, "reset drive"));
 409 
 410         outb(0, RESET_PORT);
 411         while (++count < RESET_WAIT)
 412                 inb(DATA_PORT);
 413 
 414         count = 0;
 415         while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
 416                 if (++count >= BUSY_TIMEOUT)
 417                         break;
 418 
 419         DEBUG((DEBUG_DRIVE_IF, "reset %s",
 420                 flags == FL_RESET ? "succeeded" : "failed"));
 421 
 422         if (flags != FL_RESET)
 423                 return 0;               
 424         outb(HCON_SDRQB, HCON_PORT);    
 425         return 1;                       
 426 }
 427 
 428 
 429 
 430 
 431 
 432 inline static int stdt_flags(void)
     
 433 {
 434         return inb(STATUS_PORT) & FL_STDT;
 435 }
 436 
 437 
 438 
 439 inline static int fetch_status(void)
     
 440 {
 441         unsigned char status;
 442 
 443         if (inb(STATUS_PORT) & FL_STEN)
 444                 return -ERR_IF_NOSTAT;
 445 
 446         status = inb(DATA_PORT);
 447         DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
 448         return status;
 449 }
 450 
 451 
 452 
 453 inline static void fetch_data(char *buf, int n)
     
 454 {
 455         insb(DATA_PORT, buf, n);
 456         DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
 457 }
 458 
 459 
 460 
 461 inline static void flush_data(void)
     
 462 {
 463         while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
 464                 inb(DATA_PORT);
 465         DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
 466 }
 467 
 468 
 469 
 470 
 471 
 472 
 473 inline static int exec_cmd(int cmd)
     
 474 {
 475         int ack = send_cmd(cmd);
 476         if (ack < 0)
 477                 return ack;
 478         return get_exec_status(cmd < COMFETCH);
 479 }
 480 
 481 
 482 
 483 
 484 inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
     
 485 {
 486         int ack = send_cmd(cmd);
 487         if (ack < 0)
 488                 return ack;
 489         return send_params(params);
 490 }
 491 
 492 
 493 
 494 inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
     
 495 {
 496         int ack = send_cmd(cmd);
 497         if (ack < 0)
 498                 return ack;
 499         ack = send_seek_params(params);
 500         if (ack < 0)
 501                 return ack;
 502         return 0;
 503 }
 504 
 505 
 506 
 507 inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
     
 508 {
 509         int ack = exec_read_cmd(cmd, params);
 510         if (ack < 0)
 511                 return ack;
 512         return get_exec_status(0);
 513 }
 514 
 515 
 516 
 517 
 518 
 519 inline static void single_bin2bcd(u_char *p)
     
 520 {
 521         DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
 522         *p = (*p % 10) | ((*p / 10) << 4);
 523 }
 524 
 525 
 526 
 527 static void bin2bcd(struct cdrom_msf *msf)
     
 528 {
 529         single_bin2bcd(&msf->cdmsf_min0);
 530         single_bin2bcd(&msf->cdmsf_sec0);
 531         single_bin2bcd(&msf->cdmsf_frame0);
 532         single_bin2bcd(&msf->cdmsf_min1);
 533         single_bin2bcd(&msf->cdmsf_sec1);
 534         single_bin2bcd(&msf->cdmsf_frame1);
 535 }
 536 
 537 
 538 
 539 #define CD_FPM  (CD_SECS * CD_FRAMES)   
 540 
 541 static void lba2msf(int lba, struct cdrom_msf *msf)
     
 542 {
 543         DEBUG((DEBUG_CONV, "lba2msf %d", lba));
 544         lba += CD_MSF_OFFSET;
 545         msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
 546         msf->cdmsf_sec0 = lba / CD_FRAMES;
 547         msf->cdmsf_frame0 = lba % CD_FRAMES;
 548         msf->cdmsf_min1 = 0;
 549         msf->cdmsf_sec1 = 0;
 550         msf->cdmsf_frame1 = 0;
 551         bin2bcd(msf);
 552 }
 553 
 554 
 555 
 556 inline static u_char bcd2bin(u_char bcd)
     
 557 {
 558         DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
 559         return (bcd >> 4) * 10 + (bcd & 0x0f);
 560 }
 561 
 562 
 563 static void msf2lba(union cdrom_addr *addr)
     
 564 {
 565         addr->lba = addr->msf.minute * CD_FPM
 566                     + addr->msf.second * CD_FRAMES
 567                     + addr->msf.frame - CD_MSF_OFFSET;
 568 }
 569 
 570 
 571 
 572 
 573 static void msf_bcd2bin(union cdrom_addr *addr)
     
 574 {
 575         addr->msf.minute = bcd2bin(addr->msf.minute);
 576         addr->msf.second = bcd2bin(addr->msf.second);
 577         addr->msf.frame = bcd2bin(addr->msf.frame);
 578 }
 579 
 580 
 581 
 582 
 583 static int audio_status = CDROM_AUDIO_NO_STATUS;
 584 static char toc_uptodate = 0;
 585 static char disk_changed = 1;
 586 
 587 
 588 static int drive_status(void)
     
 589 {
 590         int status;
 591 
 592         status = exec_cmd(COMIOCTLISTAT);
 593         DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
 594         if (status < 0)
 595                 return status;
 596         if (status == 0xff)     
 597                 return -ERR_IF_NOSTAT;
 598 
 599         if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
 600                 (audio_status == CDROM_AUDIO_PLAY)) {
 601                 audio_status = CDROM_AUDIO_COMPLETED;
 602         }
 603 
 604         if (status & ST_DSK_CHG) {
 605                 toc_uptodate = 0;
 606                 disk_changed = 1;
 607                 audio_status = CDROM_AUDIO_NO_STATUS;
 608         }
 609 
 610         return status;
 611 }
 612 
 613 
 614 
 615 
 616 
 617 static int get_q_channel(struct cdrom_subchnl *qp)
     
 618 {
 619         int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
 620 
 621         status = drive_status();
 622         if (status < 0)
 623                 return status;
 624         qp->cdsc_audiostatus = audio_status;
 625 
 626         status = exec_cmd(COMSUBQ);
 627         if (status < 0)
 628                 return status;
 629 
 630         d1 = get_data(0);
 631         if (d1 < 0)
 632                 return d1;
 633         qp->cdsc_adr = d1;
 634         qp->cdsc_ctrl = d1 >> 4;
 635 
 636         d2 = get_data(0);
 637         if (d2 < 0)
 638                 return d2;
 639         qp->cdsc_trk = bcd2bin(d2);
 640 
 641         d3 = get_data(0);
 642         if (d3 < 0)
 643                 return d3;
 644         qp->cdsc_ind = bcd2bin(d3);
 645 
 646         d4 = get_data(0);
 647         if (d4 < 0)
 648                 return d4;
 649         qp->cdsc_reladdr.msf.minute = d4;
 650 
 651         d5 = get_data(0);
 652         if (d5 < 0)
 653                 return d5;
 654         qp->cdsc_reladdr.msf.second = d5;
 655 
 656         d6 = get_data(0);
 657         if (d6 < 0)
 658                 return d6;
 659         qp->cdsc_reladdr.msf.frame = d6;
 660 
 661         d7 = get_data(0);
 662         if (d7 < 0)
 663                 return d7;
 664         
 665 
 666         d8 = get_data(0);
 667         if (d8 < 0)
 668                 return d8;
 669         qp->cdsc_absaddr.msf.minute = d8;
 670 
 671         d9 = get_data(0);
 672         if (d9 < 0)
 673                 return d9;
 674         qp->cdsc_absaddr.msf.second = d9;
 675 
 676         d10 = get_data(0);
 677         if (d10 < 0)
 678                 return d10;
 679         qp->cdsc_absaddr.msf.frame = d10;
 680 
 681         DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
 682                 d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
 683 
 684         msf_bcd2bin(&qp->cdsc_absaddr);
 685         msf_bcd2bin(&qp->cdsc_reladdr);
 686         if (qp->cdsc_format == CDROM_LBA) {
 687                 msf2lba(&qp->cdsc_absaddr);
 688                 msf2lba(&qp->cdsc_reladdr);
 689         }
 690 
 691         return 0;
 692 }
 693 
 694 
 695 
 696 
 697 
 698 #define ERR_TOC_MISSINGINFO     0x120
 699 #define ERR_TOC_MISSINGENTRY    0x121
 700 
 701 
 702 struct cdrom_disk_info {
 703         unsigned char           first;
 704         unsigned char           last;
 705         struct cdrom_msf0       disk_length;
 706         struct cdrom_msf0       first_track;
 707         
 708         unsigned char           next;
 709         struct cdrom_msf0       next_session;
 710         struct cdrom_msf0       last_session;
 711         unsigned char           multi;
 712         unsigned char           xa;
 713         unsigned char           audio;
 714 };
 715 static struct cdrom_disk_info disk_info;
 716 
 717 #define MAX_TRACKS              111
 718 static struct cdrom_subchnl toc[MAX_TRACKS];
 719 
 720 #define QINFO_FIRSTTRACK        100 
 721 #define QINFO_LASTTRACK         101 
 722 #define QINFO_DISKLENGTH        102 
 723 #define QINFO_NEXTSESSION       110 
 724 
 725 #define I_FIRSTTRACK    0x01
 726 #define I_LASTTRACK     0x02
 727 #define I_DISKLENGTH    0x04
 728 #define I_NEXTSESSION   0x08
 729 #define I_ALL   (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
 730 
 731 
 732 #if DEBUG_TOC
 733 void toc_debug_info(int i)
     
 734 {
 735         printk("#%3d ctl %1x, adr %1x, track %2d index %3d"
 736                 "  %2d:%02d.%02d %2d:%02d.%02d\n",
 737                 i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
 738                 toc[i].cdsc_trk, toc[i].cdsc_ind,
 739                 toc[i].cdsc_reladdr.msf.minute,
 740                 toc[i].cdsc_reladdr.msf.second,
 741                 toc[i].cdsc_reladdr.msf.frame,
 742                 toc[i].cdsc_absaddr.msf.minute,
 743                 toc[i].cdsc_absaddr.msf.second,
 744                 toc[i].cdsc_absaddr.msf.frame);
 745 }
 746 #endif
 747 
 748 
 749 static int read_toc(void)
     
 750 {
 751         int status, limit, count;
 752         unsigned char got_info = 0;
 753         struct cdrom_subchnl q_info;
 754 #if DEBUG_TOC
 755         int i;
 756 #endif
 757 
 758         DEBUG((DEBUG_TOC, "starting read_toc"));
 759 
 760         count = 0;
 761         for (limit = 60; limit > 0; limit--) {
 762                 int index;
 763 
 764                 q_info.cdsc_format = CDROM_MSF;
 765                 status = get_q_channel(&q_info);
 766                 if (status < 0)
 767                         return status;
 768 
 769                 index = q_info.cdsc_ind;
 770                 if (index > 0 && index < MAX_TRACKS
 771                     && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
 772                         toc[index] = q_info;
 773                         DEBUG((DEBUG_TOC, "got %d", index));
 774                         if (index < 100)
 775                                 count++;
 776 
 777                         switch (q_info.cdsc_ind) {
 778                         case QINFO_FIRSTTRACK:
 779                                 got_info |= I_FIRSTTRACK;
 780                                 break;
 781                         case QINFO_LASTTRACK:
 782                                 got_info |= I_LASTTRACK;
 783                                 break;
 784                         case QINFO_DISKLENGTH:
 785                                 got_info |= I_DISKLENGTH;
 786                                 break;
 787                         case QINFO_NEXTSESSION:
 788                                 got_info |= I_NEXTSESSION;
 789                                 break;
 790                         }
 791                 }
 792 
 793                 if ((got_info & I_ALL) == I_ALL
 794                     && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
 795                        >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
 796                         break;
 797         }
 798 
 799         
 800         if (disk_info.first == 0) {
 801                 disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
 802                 disk_info.first_track.minute =
 803                         toc[disk_info.first].cdsc_absaddr.msf.minute;
 804                 disk_info.first_track.second =
 805                         toc[disk_info.first].cdsc_absaddr.msf.second;
 806                 disk_info.first_track.frame =
 807                         toc[disk_info.first].cdsc_absaddr.msf.frame;
 808         }
 809         disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
 810         disk_info.disk_length.minute =
 811                         toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
 812         disk_info.disk_length.second =
 813                         toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
 814         disk_info.disk_length.frame =
 815                         toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
 816         disk_info.next_session.minute =
 817                         toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
 818         disk_info.next_session.second =
 819                         toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
 820         disk_info.next_session.frame =
 821                         toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
 822         disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
 823         disk_info.last_session.minute =
 824                         toc[disk_info.next].cdsc_absaddr.msf.minute;
 825         disk_info.last_session.second =
 826                         toc[disk_info.next].cdsc_absaddr.msf.second;
 827         disk_info.last_session.frame =
 828                         toc[disk_info.next].cdsc_absaddr.msf.frame;
 829         toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
 830                         disk_info.disk_length.minute;
 831         toc[disk_info.last + 1].cdsc_absaddr.msf.second =
 832                         disk_info.disk_length.second;
 833         toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
 834                         disk_info.disk_length.frame;
 835 #if DEBUG_TOC
 836         for (i = 1; i <= disk_info.last + 1; i++)
 837                 toc_debug_info(i);
 838         toc_debug_info(QINFO_FIRSTTRACK);
 839         toc_debug_info(QINFO_LASTTRACK);
 840         toc_debug_info(QINFO_DISKLENGTH);
 841         toc_debug_info(QINFO_NEXTSESSION);
 842 #endif
 843 
 844         DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
 845                 got_info, count));
 846         if ((got_info & I_ALL) != I_ALL
 847             || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
 848                < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
 849                 return -ERR_TOC_MISSINGINFO;
 850         return 0;
 851 }
 852 
 853 
 854 #ifdef MULTISESSION
 855 static int get_multi_disk_info(void)
     
 856 {
 857         int sessions, status;
 858         struct cdrom_msf multi_index;
 859 
 860 
 861         for (sessions = 2; sessions < 10 ; sessions++) {
 862                 int count;
 863 
 864                 for (count = 100; count < MAX_TRACKS; count++) 
 865                         toc[count].cdsc_ind = 0;
 866 
 867                 multi_index.cdmsf_min0 = disk_info.next_session.minute;
 868                 multi_index.cdmsf_sec0 = disk_info.next_session.second;
 869                 multi_index.cdmsf_frame0 = disk_info.next_session.frame;
 870                 if (multi_index.cdmsf_sec0 >= 20)
 871                         multi_index.cdmsf_sec0 -= 20;
 872                 else {
 873                         multi_index.cdmsf_sec0 += 40;
 874                         multi_index.cdmsf_min0--;
 875                 }
 876                 DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
 877                         multi_index.cdmsf_min0,
 878                         multi_index.cdmsf_sec0,
 879                         multi_index.cdmsf_frame0));
 880                 bin2bcd(&multi_index);
 881                 multi_index.cdmsf_min1 = 0;
 882                 multi_index.cdmsf_sec1 = 0;
 883                 multi_index.cdmsf_frame1 = 1;
 884 
 885                 status = exec_read_cmd(COMREAD, &multi_index);
 886                 if (status < 0) {
 887                         DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
 888                                 -status));
 889                         break;
 890                 }
 891                 status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
 892                                 0 : -ERR_TOC_MISSINGINFO;
 893                 flush_data();
 894                 if (status < 0) {
 895                         DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
 896                         break;
 897                 }
 898 
 899                 status = read_toc();
 900                 if (status < 0) {
 901                         DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
 902                         break;
 903                 }
 904 
 905                 disk_info.multi = 1;
 906         }
 907 
 908         exec_cmd(COMSTOP);
 909 
 910         if (status < 0)
 911                 return -EIO;
 912         return 0;
 913 }
 914 #endif MULTISESSION
 915 
 916 
 917 static int update_toc(void)
     
 918 {
 919         int status, count;
 920 
 921         if (toc_uptodate)
 922                 return 0;
 923 
 924         DEBUG((DEBUG_TOC, "starting update_toc"));
 925 
 926         disk_info.first = 0;
 927         for (count = 0; count < MAX_TRACKS; count++) 
 928                 toc[count].cdsc_ind = 0;
 929 
 930         status = exec_cmd(COMLEADIN);
 931         if (status < 0)
 932                 return -EIO;
 933 
 934         status = read_toc();
 935         if (status < 0) {
 936                 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
 937                 return -EIO;
 938         }
 939 
 940         
 941         disk_info.audio =
 942                 (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
 943 
 944         
 945         disk_info.xa = drive_status() & ST_MODE2TRACK;
 946 
 947         
 948         disk_info.multi = 0;
 949 #ifdef MULTISESSION
 950         if (disk_info.xa)
 951                 get_multi_disk_info();  
 952 #endif MULTISESSION
 953         if (disk_info.multi)
 954                 printk("optcd: Multisession support experimental, "
 955                         "see linux/Documentation/cdrom/optcd\n");
 956 
 957         DEBUG((DEBUG_TOC, "exiting update_toc"));
 958 
 959         toc_uptodate = 1;
 960         return 0;
 961 }
 962 
 963 
 964 
 965 
 966 #define CURRENT_VALID \
 967         (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
 968          && CURRENT -> cmd == READ && CURRENT -> sector != -1)
 969 
 970 
 971 
 972 #define NOBUF           -1
 973 
 974 static char buf[CD_FRAMESIZE * N_BUFS];
 975 static volatile int buf_bn[N_BUFS], next_bn;
 976 static volatile int buf_in = 0, buf_out = NOBUF;
 977 
 978 inline static void opt_invalidate_buffers(void)
     
 979 {
 980         int i;
 981 
 982         DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
 983 
 984         for (i = 0; i < N_BUFS; i++)
 985                 buf_bn[i] = NOBUF;
 986         buf_out = NOBUF;
 987 }
 988 
 989 
 990 
 991 
 992 static void transfer(void)
     
 993 {
 994 #if DEBUG_BUFFERS | DEBUG_REQUEST
 995         printk("optcd: executing transfer\n");
 996 #endif
 997 
 998         if (!CURRENT_VALID)
 999                 return;
1000         while (CURRENT -> nr_sectors) {
1001                 int bn = CURRENT -> sector / 4;
1002                 int i, offs, nr_sectors;
1003                 for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
1004 
1005                 DEBUG((DEBUG_REQUEST, "found %d", i));
1006 
1007                 if (i >= N_BUFS) {
1008                         buf_out = NOBUF;
1009                         break;
1010                 }
1011 
1012                 offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
1013                 nr_sectors = 4 - (CURRENT -> sector & 3);
1014 
1015                 if (buf_out != i) {
1016                         buf_out = i;
1017                         if (buf_bn[i] != bn) {
1018                                 buf_out = NOBUF;
1019                                 continue;
1020                         }
1021                 }
1022 
1023                 if (nr_sectors > CURRENT -> nr_sectors)
1024                         nr_sectors = CURRENT -> nr_sectors;
1025                 memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512);
1026                 CURRENT -> nr_sectors -= nr_sectors;
1027                 CURRENT -> sector += nr_sectors;
1028                 CURRENT -> buffer += nr_sectors * 512;
1029         }
1030 }
1031 
1032 
1033 
1034 
1035 enum state_e {
1036         S_IDLE,         
1037         S_START,        
1038         S_READ,         
1039         S_DATA,         
1040         S_STOP,         
1041         S_STOPPING      
1042 };
1043 
1044 static volatile enum state_e state = S_IDLE;
1045 #if DEBUG_STATE
1046 static volatile enum state_e state_old = S_STOP;
1047 static volatile int flags_old = 0;
1048 static volatile long state_n = 0;
1049 #endif
1050 
1051 
1052 
1053 
1054 
1055 
1056 static int in_vfs = 0;
1057 
1058 
1059 static volatile int transfer_is_active = 0;
1060 static volatile int error = 0;  
1061 static int tries;               
1062 static int timeout = 0;
1063 
1064 static struct timer_list req_timer = {NULL, NULL, 0, 0, NULL};
1065 
1066 #define SET_REQ_TIMER(func, jifs) \
1067         req_timer.expires = jiffies+(jifs); \
1068         req_timer.function = (void *) (func); \
1069         add_timer(&req_timer);
1070 #define CLEAR_REQ_TIMER del_timer(&req_timer)
1071 
1072 static void poll(void)
     
1073 {
1074         static volatile int read_count = 1;
1075         int flags;
1076         int loop_again = 1;
1077         int status = 0;
1078         int skip = 0;
1079 
1080         if (error) {
1081                 printk("optcd: I/O error 0x%02x\n", error);
1082                 opt_invalidate_buffers();
1083                 if (!tries--) {
1084                         printk("optcd: read block %d failed; Giving up\n",
1085                                next_bn);
1086                         if (transfer_is_active)
1087                                 loop_again = 0;
1088                         if (CURRENT_VALID)
1089                                 end_request(0);
1090                         tries = 5;
1091                 }
1092                 error = 0;
1093                 state = S_STOP;
1094         }
1095 
1096         while (loop_again)
1097         {
1098                 loop_again = 0; 
1099 
1100 
1101 #if DEBUG_STATE
1102                 if (state == state_old)
1103                         state_n++;
1104                 else {
1105                         state_old = state;
1106                         if (++state_n > 1)
1107                                 printk("optcd: %ld times in previous state\n",
1108                                         state_n);
1109                         printk("optcd: state %d\n", state);
1110                         state_n = 0;
1111                 }
1112 #endif
1113 
1114                 switch (state) {
1115                 case S_IDLE:
1116                         return;
1117                 case S_START:
1118                         if (in_vfs)
1119                                 break;
1120                         if (send_cmd(COMDRVST)) {
1121                                 state = S_IDLE;
1122                                 while (CURRENT_VALID)
1123                                         end_request(0);
1124                                 return;
1125                         }
1126                         state = S_READ;
1127                         timeout = READ_TIMEOUT;
1128                         break;
1129                 case S_READ: {
1130                         struct cdrom_msf msf;
1131                         if (!skip) {
1132                                 status = fetch_status();
1133                                 if (status < 0)
1134                                         break;
1135                                 if (status & ST_DSK_CHG) {
1136                                         toc_uptodate = 0;
1137                                         opt_invalidate_buffers();
1138                                 }
1139                         }
1140                         skip = 0;
1141                         if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1142                                 toc_uptodate = 0;
1143                                 opt_invalidate_buffers();
1144                                 printk((status & ST_DOOR_OPEN)
1145                                        ? "optcd: door open\n"
1146                                        : "optcd: disk removed\n");
1147                                 state = S_IDLE;
1148                                 while (CURRENT_VALID)
1149                                         end_request(0);
1150                                 return;
1151                         }
1152                         if (!CURRENT_VALID) {
1153                                 state = S_STOP;
1154                                 loop_again = 1;
1155                                 break;
1156                         }
1157                         next_bn = CURRENT -> sector / 4;
1158                         lba2msf(next_bn, &msf);
1159                         read_count = N_BUFS;
1160                         msf.cdmsf_frame1 = read_count; 
1161 
1162                         DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x",
1163                                 msf.cdmsf_min0,
1164                                 msf.cdmsf_sec0,
1165                                 msf.cdmsf_frame0,
1166                                 msf.cdmsf_min1,
1167                                 msf.cdmsf_sec1,
1168                                 msf.cdmsf_frame1));
1169                         DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"
1170                                 " buf_out:%d buf_bn:%d",
1171                                 next_bn,
1172                                 buf_in,
1173                                 buf_out,
1174                                 buf_bn[buf_in]));
1175 
1176                         exec_read_cmd(COMREAD, &msf);
1177                         state = S_DATA;
1178                         timeout = READ_TIMEOUT;
1179                         break;
1180                 }
1181                 case S_DATA:
1182                         flags = stdt_flags() & (FL_STEN|FL_DTEN);
1183 
1184 #if DEBUG_STATE
1185                         if (flags != flags_old) {
1186                                 flags_old = flags;
1187                                 printk("optcd: flags:%x\n", flags);
1188                         }
1189                         if (flags == FL_STEN)
1190                                 printk("timeout cnt: %d\n", timeout);
1191 #endif
1192 
1193                         switch (flags) {
1194                         case FL_DTEN:           
1195                                 if (!tries--) {
1196                                         printk("optcd: read block %d failed; "
1197                                                 "Giving up\n", next_bn);
1198                                         if (transfer_is_active) {
1199                                                 tries = 0;
1200                                                 break;
1201                                         }
1202                                         if (CURRENT_VALID)
1203                                                 end_request(0);
1204                                         tries = 5;
1205                                 }
1206                                 state = S_START;
1207                                 timeout = READ_TIMEOUT;
1208                                 loop_again = 1;
1209                         case (FL_STEN|FL_DTEN):  
1210                                 break;
1211                         default:        
1212                                 tries = 5;
1213                                 if (!CURRENT_VALID && buf_in == buf_out) {
1214                                         state = S_STOP;
1215                                         loop_again = 1;
1216                                         break;
1217                                 }
1218                                 if (read_count<=0)
1219                                         printk("optcd: warning - try to read"
1220                                                 " 0 frames\n");
1221                                 while (read_count) {
1222                                         buf_bn[buf_in] = NOBUF;
1223                                         if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {
1224                                         
1225                                                 printk("read_count:%d "
1226                                                    "CURRENT->nr_sectors:%ld "
1227                                                    "buf_in:%d\n",
1228                                                         read_count,
1229                                                         CURRENT->nr_sectors,
1230                                                         buf_in);
1231                                                 printk("transfer active: %x\n",
1232                                                         transfer_is_active);
1233                                                 read_count = 0;
1234                                                 state = S_STOP;
1235                                                 loop_again = 1;
1236                                                 end_request(0);
1237                                                 break;
1238                                         }
1239                                         fetch_data(buf+
1240                                             CD_FRAMESIZE*buf_in,
1241                                             CD_FRAMESIZE);
1242                                         read_count--;
1243 
1244                                         DEBUG((DEBUG_REQUEST,
1245                                                 "S_DATA; ---I've read data- "
1246                                                 "read_count: %d",
1247                                                 read_count));
1248                                         DEBUG((DEBUG_REQUEST,
1249                                                 "next_bn:%d  buf_in:%d "
1250                                                 "buf_out:%d  buf_bn:%d",
1251                                                 next_bn,
1252                                                 buf_in,
1253                                                 buf_out,
1254                                                 buf_bn[buf_in]));
1255 
1256                                         buf_bn[buf_in] = next_bn++;
1257                                         if (buf_out == NOBUF)
1258                                                 buf_out = buf_in;
1259                                         buf_in = buf_in + 1 ==
1260                                                 N_BUFS ? 0 : buf_in + 1;
1261                                 }
1262                                 if (!transfer_is_active) {
1263                                         while (CURRENT_VALID) {
1264                                                 transfer();
1265                                                 if (CURRENT -> nr_sectors == 0)
1266                                                         end_request(1);
1267                                                 else
1268                                                         break;
1269                                         }
1270                                 }
1271 
1272                                 if (CURRENT_VALID
1273                                     && (CURRENT -> sector / 4 < next_bn ||
1274                                     CURRENT -> sector / 4 >
1275                                      next_bn + N_BUFS)) {
1276                                         state = S_STOP;
1277                                         loop_again = 1;
1278                                         break;
1279                                 }
1280                                 timeout = READ_TIMEOUT;
1281                                 if (read_count == 0) {
1282                                         state = S_STOP;
1283                                         loop_again = 1;
1284                                         break;
1285                                 }
1286                         }
1287                         break;
1288                 case S_STOP:
1289                         if (read_count != 0)
1290                                 printk("optcd: discard data=%x frames\n",
1291                                         read_count);
1292                         flush_data();
1293                         if (send_cmd(COMDRVST)) {
1294                                 state = S_IDLE;
1295                                 while (CURRENT_VALID)
1296                                         end_request(0);
1297                                 return;
1298                         }
1299                         state = S_STOPPING;
1300                         timeout = STOP_TIMEOUT;
1301                         break;
1302                 case S_STOPPING:
1303                         status = fetch_status();
1304                         if (status < 0 && timeout)
1305                                         break;
1306                         if ((status >= 0) && (status & ST_DSK_CHG)) {
1307                                 toc_uptodate = 0;
1308                                 opt_invalidate_buffers();
1309                         }
1310                         if (CURRENT_VALID) {
1311                                 if (status >= 0) {
1312                                         state = S_READ;
1313                                         loop_again = 1;
1314                                         skip = 1;
1315                                         break;
1316                                 } else {
1317                                         state = S_START;
1318                                         timeout = 1;
1319                                 }
1320                         } else {
1321                                 state = S_IDLE;
1322                                 return;
1323                         }
1324                         break;
1325                 default:
1326                         printk("optcd: invalid state %d\n", state);
1327                         return;
1328                 } 
1329         } 
1330 
1331         if (!timeout--) {
1332                 printk("optcd: timeout in state %d\n", state);
1333                 state = S_STOP;
1334                 if (exec_cmd(COMSTOP) < 0) {
1335                         state = S_IDLE;
1336                         while (CURRENT_VALID)
1337                                 end_request(0);
1338                         return;
1339                 }
1340         }
1341 
1342         SET_REQ_TIMER(poll, HZ/100);
1343 }
1344 
1345 
1346 static void do_optcd_request(void)
     
1347 {
1348         DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
1349                CURRENT -> sector, CURRENT -> nr_sectors));
1350 
1351         if (disk_info.audio) {
1352                 printk("optcd: Error: tried to mount an Audio CD\n");
1353                 end_request(0);
1354                 return;
1355         }
1356 
1357         transfer_is_active = 1;
1358         while (CURRENT_VALID) {
1359                 if (CURRENT->bh) {
1360                         if (!buffer_locked(CURRENT->bh))
1361                                 panic(DEVICE_NAME ": block not locked");
1362                 }
1363                 transfer();     
1364                 if (CURRENT -> nr_sectors == 0) {
1365                         end_request(1);
1366                 } else {        
1367                         buf_out = NOBUF;
1368                         if (state == S_IDLE) {
1369                                 
1370                                 if (update_toc() < 0) {
1371                                         while (CURRENT_VALID)
1372                                                 end_request(0);
1373                                         break;
1374                                 }
1375                                 
1376                                 state = S_START;
1377                                 timeout = READ_TIMEOUT;
1378                                 tries = 5;
1379                                 
1380                                 SET_REQ_TIMER(poll, HZ/100);
1381                         }
1382                         break;
1383                 }
1384         }
1385         transfer_is_active = 0;
1386 
1387         DEBUG((DEBUG_REQUEST, "next_bn:%d  buf_in:%d buf_out:%d  buf_bn:%d",
1388                next_bn, buf_in, buf_out, buf_bn[buf_in]));
1389         DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1390 }
1391 
1392 
1393 
1394 
1395 static char auto_eject = 0;
1396 
1397 static int cdrompause(void)
     
1398 {
1399         int status;
1400 
1401         if (audio_status != CDROM_AUDIO_PLAY)
1402                 return -EINVAL;
1403 
1404         status = exec_cmd(COMPAUSEON);
1405         if (status < 0) {
1406                 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1407                 return -EIO;
1408         }
1409         audio_status = CDROM_AUDIO_PAUSED;
1410         return 0;
1411 }
1412 
1413 
1414 static int cdromresume(void)
     
1415 {
1416         int status;
1417 
1418         if (audio_status != CDROM_AUDIO_PAUSED)
1419                 return -EINVAL;
1420 
1421         status = exec_cmd(COMPAUSEOFF);
1422         if (status < 0) {
1423                 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1424                 audio_status = CDROM_AUDIO_ERROR;
1425                 return -EIO;
1426         }
1427         audio_status = CDROM_AUDIO_PLAY;
1428         return 0;
1429 }
1430 
1431 
1432 static int cdromplaymsf(unsigned long arg)
     
1433 {
1434         int status;
1435         struct cdrom_msf msf;
1436 
1437         status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1438         if (status)
1439                 return status;
1440         memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1441 
1442         bin2bcd(&msf);
1443         status = exec_long_cmd(COMPLAY, &msf);
1444         if (status < 0) {
1445                 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1446                 audio_status = CDROM_AUDIO_ERROR;
1447                 return -EIO;
1448         }
1449 
1450         audio_status = CDROM_AUDIO_PLAY;
1451         return 0;
1452 }
1453 
1454 
1455 static int cdromplaytrkind(unsigned long arg)
     
1456 {
1457         int status;
1458         struct cdrom_ti ti;
1459         struct cdrom_msf msf;
1460 
1461         status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
1462         if (status)
1463                 return status;
1464         memcpy_fromfs(&ti, (void *) arg, sizeof ti);
1465 
1466         if (ti.cdti_trk0 < disk_info.first
1467             || ti.cdti_trk0 > disk_info.last
1468             || ti.cdti_trk1 < ti.cdti_trk0)
1469                 return -EINVAL;
1470         if (ti.cdti_trk1 > disk_info.last)
1471                 ti.cdti_trk1 = disk_info.last;
1472 
1473         msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1474         msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1475         msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1476         msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1477         msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1478         msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1479 
1480         DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1481                 msf.cdmsf_min0,
1482                 msf.cdmsf_sec0,
1483                 msf.cdmsf_frame0,
1484                 msf.cdmsf_min1,
1485                 msf.cdmsf_sec1,
1486                 msf.cdmsf_frame1));
1487 
1488         bin2bcd(&msf);
1489         status = exec_long_cmd(COMPLAY, &msf);
1490         if (status < 0) {
1491                 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1492                 audio_status = CDROM_AUDIO_ERROR;
1493                 return -EIO;
1494         }
1495 
1496         audio_status = CDROM_AUDIO_PLAY;
1497         return 0;
1498 }
1499 
1500 
1501 static int cdromreadtochdr(unsigned long arg)
     
1502 {
1503         int status;
1504         struct cdrom_tochdr tochdr;
1505 
1506         status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
1507         if (status)
1508                 return status;
1509 
1510         tochdr.cdth_trk0 = disk_info.first;
1511         tochdr.cdth_trk1 = disk_info.last;
1512 
1513         memcpy_tofs((void *) arg, &tochdr, sizeof tochdr);
1514         return 0;
1515 }
1516 
1517 
1518 static int cdromreadtocentry(unsigned long arg)
     
1519 {
1520         int status;
1521         struct cdrom_tocentry entry;
1522         struct cdrom_subchnl *tocptr;
1523 
1524         status = verify_area(VERIFY_READ, (void *) arg, sizeof entry);
1525         if (status)
1526                 return status;
1527         status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
1528         if (status)
1529                 return status;
1530         memcpy_fromfs(&entry, (void *) arg, sizeof entry);
1531 
1532         if (entry.cdte_track == CDROM_LEADOUT)
1533                 tocptr = &toc[disk_info.last + 1];
1534         else if (entry.cdte_track > disk_info.last
1535                 || entry.cdte_track < disk_info.first)
1536                 return -EINVAL;
1537         else
1538                 tocptr = &toc[entry.cdte_track];
1539 
1540         entry.cdte_adr = tocptr->cdsc_adr;
1541         entry.cdte_ctrl = tocptr->cdsc_ctrl;
1542         entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1543         entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1544         entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1545         
1546 
1547         if (entry.cdte_format == CDROM_LBA)
1548                 msf2lba(&entry.cdte_addr);
1549         else if (entry.cdte_format != CDROM_MSF)
1550                 return -EINVAL;
1551 
1552         memcpy_tofs((void *) arg, &entry, sizeof entry);
1553         return 0;
1554 }
1555 
1556 
1557 static int cdromvolctrl(unsigned long arg)
     
1558 {
1559         int status;
1560         struct cdrom_volctrl volctrl;
1561         struct cdrom_msf msf;
1562 
1563         status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
1564         if (status)
1565                 return status;
1566         memcpy_fromfs(&volctrl, (char *) arg, sizeof volctrl);
1567 
1568         msf.cdmsf_min0 = 0x10;
1569         msf.cdmsf_sec0 = 0x32;
1570         msf.cdmsf_frame0 = volctrl.channel0;
1571         msf.cdmsf_min1 = volctrl.channel1;
1572         msf.cdmsf_sec1 = volctrl.channel2;
1573         msf.cdmsf_frame1 = volctrl.channel3;
1574 
1575         status = exec_long_cmd(COMCHCTRL, &msf);
1576         if (status < 0) {
1577                 DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1578                 return -EIO;
1579         }
1580         return 0;
1581 }
1582 
1583 
1584 static int cdromsubchnl(unsigned long arg)
     
1585 {
1586         int status;
1587         struct cdrom_subchnl subchnl;
1588 
1589         status = verify_area(VERIFY_READ, (void *) arg, sizeof subchnl);
1590         if (status)
1591                 return status;
1592         status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
1593         if (status)
1594                 return status;
1595         memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
1596 
1597         if (subchnl.cdsc_format != CDROM_LBA
1598             && subchnl.cdsc_format != CDROM_MSF)
1599                 return -EINVAL;
1600 
1601         status = get_q_channel(&subchnl);
1602         if (status < 0) {
1603                 DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1604                 return -EIO;
1605         }
1606 
1607         memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
1608         return 0;
1609 }
1610 
1611 
1612 static int cdromread(unsigned long arg, int blocksize, int cmd)
     
1613 {
1614         int status;
1615         struct cdrom_msf msf;
1616         char buf[CD_FRAMESIZE_RAWER];
1617 
1618         status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1619         if (status)
1620                 return status;
1621         status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
1622         if (status)
1623                 return status;
1624         memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1625 
1626         bin2bcd(&msf);
1627         msf.cdmsf_min1 = 0;
1628         msf.cdmsf_sec1 = 0;
1629         msf.cdmsf_frame1 = 1;   
1630         status = exec_read_cmd(cmd, &msf);
1631 
1632         DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1633 
1634         if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1635                 return -EIO;
1636         fetch_data(buf, blocksize);
1637 
1638         memcpy_tofs((void *) arg, &buf, blocksize);
1639         return 0;
1640 }
1641 
1642 
1643 static int cdromseek(unsigned long arg)
     
1644 {
1645         int status;
1646         struct cdrom_msf msf;
1647 
1648         status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1649         if (status)
1650                 return status;
1651         memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1652 
1653         bin2bcd(&msf);
1654         status = exec_seek_cmd(COMSEEK, &msf);
1655 
1656         DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1657 
1658         if (status < 0)
1659                 return -EIO;
1660         return 0;
1661 }
1662 
1663 
1664 #ifdef MULTISESSION
1665 static int cdrommultisession(unsigned long arg)
     
1666 {
1667         int status;
1668         struct cdrom_multisession ms;
1669 
1670         status = verify_area(VERIFY_READ, (void*) arg, sizeof ms);
1671         if (status)
1672                 return status;
1673         status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);
1674         if (status)
1675                 return status;
1676         memcpy_fromfs(&ms, (void*) arg, sizeof ms);
1677 
1678         ms.addr.msf.minute = disk_info.last_session.minute;
1679         ms.addr.msf.second = disk_info.last_session.second;
1680         ms.addr.msf.frame = disk_info.last_session.frame;
1681 
1682         if (ms.addr_format != CDROM_LBA
1683            && ms.addr_format != CDROM_MSF)
1684                 return -EINVAL;
1685         if (ms.addr_format == CDROM_LBA)
1686                 msf2lba(&ms.addr);
1687 
1688         ms.xa_flag = disk_info.xa;
1689 
1690         memcpy_tofs((void*) arg, &ms,
1691                 sizeof(struct cdrom_multisession));
1692 
1693 #if DEBUG_MULTIS
1694         if (ms.addr_format == CDROM_MSF)
1695                 printk("optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1696                         ms.xa_flag,
1697                         ms.addr.msf.minute,
1698                         ms.addr.msf.second,
1699                         ms.addr.msf.frame);
1700         else
1701                 printk("optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1702                         ms.xa_flag,
1703                         ms.addr.lba,
1704                         disk_info.last_session.minute,
1705                         disk_info.last_session.second,
1706                         disk_info.last_session.frame);
1707 #endif DEBUG_MULTIS
1708 
1709         return 0;
1710 }
1711 #endif MULTISESSION
1712 
1713 
1714 static int cdromreset(void)
     
1715 {
1716         if (state != S_IDLE) {
1717                 error = 1;
1718                 tries = 0;
1719         }
1720 
1721         toc_uptodate = 0;
1722         disk_changed = 1;
1723         opt_invalidate_buffers();
1724         audio_status = CDROM_AUDIO_NO_STATUS;
1725 
1726         if (!reset_drive())
1727                 return -EIO;
1728         return 0;
1729 }
1730 
1731 
1732 
1733 
1734 static int opt_ioctl(struct inode *ip, struct file *fp,
     
1735                      unsigned int cmd, unsigned long arg)
1736 {
1737         int status, err, retval = 0;
1738 
1739         DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1740 
1741         if (!ip)
1742                 return -EINVAL;
1743 
1744         if (cmd == CDROMRESET)
1745                 return cdromreset();
1746 
1747         
1748         if (state != S_IDLE || in_vfs)
1749                 return -EBUSY;
1750 
1751         in_vfs = 1;
1752 
1753         status = drive_status();
1754         if (status < 0) {
1755                 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1756                 in_vfs = 0;
1757                 return -EIO;
1758         }
1759 
1760         if (status & ST_DOOR_OPEN)
1761                 switch (cmd) {  
1762                 case CDROMCLOSETRAY:
1763                         
1764                         err = exec_cmd(COMCLOSE);
1765                         if (err < 0) {
1766                                 DEBUG((DEBUG_VFS,
1767                                        "exec_cmd COMCLOSE: %02x", -err));
1768                                 in_vfs = 0;
1769                                 return -EIO;
1770                         }
1771                         break;
1772                 default:        in_vfs = 0;
1773                                 return -EBUSY;
1774                 }
1775 
1776         err = update_toc();
1777         if (err < 0) {
1778                 DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1779                 in_vfs = 0;
1780                 return -EIO;
1781         }
1782 
1783         DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1784 
1785         switch (cmd) {
1786         case CDROMPAUSE:        retval = cdrompause(); break;
1787         case CDROMRESUME:       retval = cdromresume(); break;
1788         case CDROMPLAYMSF:      retval = cdromplaymsf(arg); break;
1789         case CDROMPLAYTRKIND:   retval = cdromplaytrkind(arg); break;
1790         case CDROMREADTOCHDR:   retval = cdromreadtochdr(arg); break;
1791         case CDROMREADTOCENTRY: retval = cdromreadtocentry(arg); break;
1792 
1793         case CDROMSTOP:         err = exec_cmd(COMSTOP);
1794                                 if (err < 0) {
1795                                         DEBUG((DEBUG_VFS,
1796                                                 "exec_cmd COMSTOP: %02x",
1797                                                 -err));
1798                                         retval = -EIO;
1799                                 } else
1800                                         audio_status = CDROM_AUDIO_NO_STATUS;
1801                                 break;
1802         case CDROMSTART:        break;  
1803         case CDROMEJECT:        err = exec_cmd(COMUNLOCK);
1804                                 if (err < 0) {
1805                                         DEBUG((DEBUG_VFS,
1806                                                 "exec_cmd COMUNLOCK: %02x",
1807                                                 -err));
1808                                         retval = -EIO;
1809                                         break;
1810                                 }
1811                                 err = exec_cmd(COMOPEN);
1812                                 if (err < 0) {
1813                                         DEBUG((DEBUG_VFS,
1814                                                 "exec_cmd COMOPEN: %02x",
1815                                                 -err));
1816                                         retval = -EIO;
1817                                 }
1818                                 break;
1819 
1820         case CDROMVOLCTRL:      retval = cdromvolctrl(arg); break;
1821         case CDROMSUBCHNL:      retval = cdromsubchnl(arg); break;
1822 
1823         
1824 
1825         case CDROMREADMODE2:    retval = -EINVAL; break;
1826         case CDROMREADMODE1:    retval = -EINVAL; break;
1827 
1828         
1829         case CDROMREADAUDIO:    retval = -EINVAL; break;
1830 
1831         case CDROMEJECT_SW:     auto_eject = (char) arg;
1832                                 break;
1833 
1834 #ifdef MULTISESSION
1835         case CDROMMULTISESSION: retval = cdrommultisession(arg); break;
1836 #endif
1837 
1838         case CDROM_GET_UPC:     retval = -EINVAL; break; 
1839         case CDROMVOLREAD:      retval = -EINVAL; break; 
1840 
1841         case CDROMREADRAW:
1842                         
1843                         retval = cdromread(arg, CD_FRAMESIZE_RAW1, COMREADRAW);
1844                         break;
1845         case CDROMREADCOOKED:
1846                         retval = cdromread(arg, CD_FRAMESIZE, COMREAD);
1847                         break;
1848         case CDROMREADALL:
1849                         retval = cdromread(arg, CD_FRAMESIZE_RAWER, COMREADALL);
1850                         break;
1851 
1852         case CDROMSEEK:         retval = cdromseek(arg); break;
1853         case CDROMPLAYBLK:      retval = -EINVAL; break; 
1854         case CDROMCLOSETRAY:    break;  
1855         default:                retval = -EINVAL;
1856         }
1857         in_vfs = 0;
1858         return retval;
1859 }
1860 
1861 
1862 static int open_count = 0;
1863 
1864 
1865 static int opt_open(struct inode *ip, struct file *fp)
     
1866 {
1867         DEBUG((DEBUG_VFS, "starting opt_open"));
1868 
1869         if (!open_count && state == S_IDLE) {
1870                 int status;
1871 
1872                 toc_uptodate = 0;
1873                 opt_invalidate_buffers();
1874 
1875                 status = exec_cmd(COMCLOSE);    
1876                 if (status < 0) {
1877                         DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1878                 }
1879 
1880                 status = drive_status();
1881                 if (status < 0) {
1882                         DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1883                         return -EIO;
1884                 }
1885                 DEBUG((DEBUG_VFS, "status: %02x", status));
1886                 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1887                         printk("optcd: no disk or door open\n");
1888                         return -EIO;
1889                 }
1890                 status = exec_cmd(COMLOCK);             
1891                 if (status < 0) {
1892                         DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1893                 }
1894                 status = update_toc();  
1895                 if (status < 0) {
1896                         DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1897                         status = exec_cmd(COMUNLOCK);   
1898                         if (status < 0) {
1899                                 DEBUG((DEBUG_VFS,
1900                                        "exec_cmd COMUNLOCK: %02x", -status));
1901                         }
1902                         return -EIO;
1903                 }
1904                 open_count++;
1905         }
1906         MOD_INC_USE_COUNT;
1907 
1908         DEBUG((DEBUG_VFS, "exiting opt_open"));
1909 
1910         return 0;
1911 }
1912 
1913 
1914 
1915 static void opt_release(struct inode *ip, struct file *fp)
     
1916 {
1917         int status;
1918 
1919         DEBUG((DEBUG_VFS, "executing opt_release"));
1920         DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1921                 ip, ip -> i_rdev, fp));
1922 
1923         if (!--open_count) {
1924                 toc_uptodate = 0;
1925                 opt_invalidate_buffers();
1926                 sync_dev(ip -> i_rdev);
1927                 invalidate_buffers(ip -> i_rdev);
1928                 status = exec_cmd(COMUNLOCK);   
1929                 if (status < 0) {
1930                         DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1931                 }
1932                 if (auto_eject) {
1933                         status = exec_cmd(COMOPEN);
1934                         DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1935                 }
1936                 CLEAR_TIMER;
1937                 CLEAR_REQ_TIMER;
1938         }
1939         MOD_DEC_USE_COUNT;
1940 }
1941 
1942 
1943 
1944 static int opt_media_change(kdev_t dev)
     
1945 {
1946         DEBUG((DEBUG_VFS, "executing opt_media_change"));
1947         DEBUG((DEBUG_VFS, "dev: 0x%x; disk_changed = %d\n", dev, disk_changed));
1948 
1949         if (disk_changed) {
1950                 disk_changed = 0;
1951                 return 1;
1952         }
1953         return 0;
1954 }
1955 
1956 
1957 
1958 
1959 
1960 
1961 static int version_ok(void)
     
1962 {
1963         char devname[100];
1964         int count, i, ch, status;
1965 
1966         status = exec_cmd(COMVERSION);
1967         if (status < 0) {
1968                 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1969                 return 0;
1970         }
1971         if ((count = get_data(1)) < 0) {
1972                 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1973                 return 0;
1974         }
1975         for (i = 0, ch = -1; count > 0; count--) {
1976                 if ((ch = get_data(1)) < 0) {
1977                         DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1978                         break;
1979                 }
1980                 if (i < 99)
1981                         devname[i++] = ch;
1982         }
1983         devname[i] = '\0';
1984         if (ch < 0)
1985                 return 0;
1986 
1987         printk("optcd: Device %s detected\n", devname);
1988         return ((devname[0] == 'D')
1989              && (devname[1] == 'O')
1990              && (devname[2] == 'L')
1991              && (devname[3] == 'P')
1992              && (devname[4] == 'H')
1993              && (devname[5] == 'I')
1994              && (devname[6] == 'N'));
1995 }
1996 
1997 
1998 static struct file_operations opt_fops = {
1999         NULL,                   
2000         block_read,             
2001         block_write,            
2002         NULL,                   
2003         NULL,                   
2004         opt_ioctl,              
2005         NULL,                   
2006         opt_open,               
2007         opt_release,            
2008         NULL,                   
2009         NULL,                   
2010         opt_media_change,       
2011         NULL                    
2012 };
2013 
2014 
2015 
2016 void optcd_setup(char *str, int *ints)
     
2017 {
2018         if (ints[0] > 0)
2019                 optcd_port = ints[1];
2020 }
2021 
2022 
2023 
2024 int optcd_init(void)
     
2025 {
2026         int status;
2027 
2028         if (optcd_port <= 0) {
2029                 printk("optcd: no Optics Storage CDROM Initialization\n");
2030                 return -EIO;
2031         }
2032         if (check_region(optcd_port, 4)) {
2033                 printk("optcd: conflict, I/O port 0x%x already used\n",
2034                         optcd_port);
2035                 return -EIO;
2036         }
2037 
2038         if (!reset_drive()) {
2039                 printk("optcd: drive at 0x%x not ready\n", optcd_port);
2040                 return -EIO;
2041         }
2042         if (!version_ok()) {
2043                 printk("optcd: unknown drive detected; aborting\n");
2044                 return -EIO;
2045         }
2046         status = exec_cmd(COMINITDOUBLE);
2047         if (status < 0) {
2048                 printk("optcd: cannot init double speed mode\n");
2049                 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2050                 return -EIO;
2051         }
2052         if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
2053         {
2054                 printk("optcd: unable to get major %d\n", MAJOR_NR);
2055                 return -EIO;
2056         }
2057 
2058         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
2059         read_ahead[MAJOR_NR] = 4;
2060         request_region(optcd_port, 4, "optcd");
2061 
2062         printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2063         return 0;
2064 }
2065 
2066 
2067 #ifdef MODULE
2068 int init_module(void)
     
2069 {
2070         return optcd_init();
2071 }
2072 
2073 
2074 void cleanup_module(void)
     
2075 {
2076         if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2077                 printk("optcd: what's that: can't unregister\n");
2078                 return;
2079         }
2080         release_region(optcd_port, 4);
2081         printk(KERN_INFO "optcd: module released.\n");
2082 }
2083 #endif MODULE