root/drivers/cdrom/sjcd.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sjcd_setup
  2. bin2bcd
  3. bcd2bin
  4. msf2hsg
  5. hsg2msf
  6. sjcd_send_cmd
  7. sjcd_send_1_cmd
  8. sjcd_send_4_cmd
  9. sjcd_send_6_cmd
  10. sjcd_load_response
  11. sjcd_load_status
  12. sjcd_check_status
  13. sjcd_status_timer
  14. sjcd_wait_for_status
  15. sjcd_receive_status
  16. sjcd_get_status
  17. sjcd_disk_change
  18. sjcd_update_toc
  19. sjcd_get_q_info
  20. sjcd_play
  21. sjcd_tray_close
  22. sjcd_tray_lock
  23. sjcd_tray_unlock
  24. sjcd_tray_open
  25. sjcd_ioctl
  26. sjcd_invalidate_buffers
  27. sjcd_transfer
  28. sjcd_poll
  29. do_sjcd_request
  30. sjcd_open
  31. sjcd_release
  32. sjcd_init
  33. sjcd_cleanup
  34. init_module
  35. cleanup_module

   1 /* -- sjcd.c
   2  *
   3  *   Sanyo CD-ROM device driver implementation, Version 1.6
   4  *   Copyright (C) 1995  Vadim V. Model
   5  *
   6  *   model@cecmow.enet.dec.com
   7  *   vadim@rbrf.ru
   8  *   vadim@ipsun.ras.ru
   9  *
  10  *
  11  *  This driver is based on pre-works by Eberhard Moenkeberg (emoenke@gwdg.de);
  12  *  it was developed under use of mcd.c from Martin Harriss, with help of
  13  *  Eric van der Maarel (H.T.M.v.d.Maarel@marin.nl).
  14  *
  15  *  It is planned to include these routines into sbpcd.c later - to make
  16  *  a "mixed use" on one cable possible for all kinds of drives which use
  17  *  the SoundBlaster/Panasonic style CDROM interface. But today, the
  18  *  ability to install directly from CDROM is more important than flexibility.
  19  *
  20  *  This program is free software; you can redistribute it and/or modify
  21  *  it under the terms of the GNU General Public License as published by
  22  *  the Free Software Foundation; either version 2 of the License, or
  23  *  (at your option) any later version.
  24  *
  25  *  This program is distributed in the hope that it will be useful,
  26  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  27  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  28  *  GNU General Public License for more details.
  29  *
  30  *  You should have received a copy of the GNU General Public License
  31  *  along with this program; if not, write to the Free Software
  32  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  33  *
  34  *  History:
  35  *  1.1 First public release with kernel version 1.3.7.
  36  *      Written by Vadim Model.
  37  *  1.2 Added detection and configuration of cdrom interface
  38  *      on ISP16 soundcard.
  39  *      Allow for command line options: sjcd=<io_base>,<irq>,<dma>
  40  *  1.3 Some minor changes to README.sjcd.
  41  *  1.4 MSS Sound support!! Listen to a CD through the speakers.
  42  *  1.5 Module support and bugfixes.
  43  *      Tray locking.
  44  *  1.6 Removed ISP16 code from this driver.
  45  *      Allow only to set io base address on comand line: sjcd=<io_base>
  46  *      Changes to Documentation/cdrom/sjcd
  47  *      Added cleanup after any error in the initialisation.
  48  *
  49  */
  50 
  51 #define SJCD_VERSION_MAJOR 1
  52 #define SJCD_VERSION_MINOR 6
  53 
  54 #ifdef MODULE
  55 #include <linux/module.h>
  56 #endif /* MODULE */
  57 
  58 #include <linux/errno.h>
  59 #include <linux/sched.h>
  60 #include <linux/mm.h>
  61 #include <linux/timer.h>
  62 #include <linux/fs.h>
  63 #include <linux/kernel.h>
  64 #include <linux/cdrom.h>
  65 #include <linux/ioport.h>
  66 #include <linux/string.h>
  67 #include <linux/major.h>
  68 
  69 #include <asm/system.h>
  70 #include <asm/io.h>
  71 #include <asm/segment.h>
  72 
  73 #define MAJOR_NR SANYO_CDROM_MAJOR
  74 #include <linux/blk.h>
  75 #include <linux/sjcd.h>
  76 
  77 static int sjcd_present = 0;
  78 
  79 #define SJCD_BUF_SIZ 32 /* cdr-h94a has internal 64K buffer */
  80 
  81 /*
  82  * buffer for block size conversion
  83  */
  84 static char sjcd_buf[ 2048 * SJCD_BUF_SIZ ];
  85 static volatile int sjcd_buf_bn[ SJCD_BUF_SIZ ], sjcd_next_bn;
  86 static volatile int sjcd_buf_in, sjcd_buf_out = -1;
  87 
  88 /*
  89  * Status.
  90  */
  91 static unsigned short sjcd_status_valid = 0;
  92 static unsigned short sjcd_door_closed;
  93 static unsigned short sjcd_door_was_open;
  94 static unsigned short sjcd_media_is_available;
  95 static unsigned short sjcd_media_is_changed;
  96 static unsigned short sjcd_toc_uptodate = 0;
  97 static unsigned short sjcd_command_failed;
  98 static volatile unsigned char sjcd_completion_status = 0;
  99 static volatile unsigned char sjcd_completion_error = 0;
 100 static unsigned short sjcd_command_is_in_progress = 0;
 101 static unsigned short sjcd_error_reported = 0;
 102 
 103 static int sjcd_open_count;
 104 
 105 static int sjcd_audio_status;
 106 static struct sjcd_play_msf sjcd_playing;
 107 
 108 static int sjcd_base = SJCD_BASE_ADDR;
 109 
 110 static struct wait_queue *sjcd_waitq = NULL;
 111 
 112 /*
 113  * Data transfer.
 114  */
 115 static volatile unsigned short sjcd_transfer_is_active = 0;
 116 
 117 enum sjcd_transfer_state {
 118   SJCD_S_IDLE     = 0,
 119   SJCD_S_START    = 1,
 120   SJCD_S_MODE     = 2,
 121   SJCD_S_READ     = 3,
 122   SJCD_S_DATA     = 4,
 123   SJCD_S_STOP     = 5,
 124   SJCD_S_STOPPING = 6
 125 };
 126 static enum sjcd_transfer_state sjcd_transfer_state = SJCD_S_IDLE;
 127 static long sjcd_transfer_timeout = 0;
 128 static int sjcd_read_count = 0;
 129 static unsigned char sjcd_mode = 0;
 130 
 131 #define SJCD_READ_TIMEOUT 5000
 132 
 133 #if defined( SJCD_GATHER_STAT )
 134 /*
 135  * Statistic.
 136  */
 137 static struct sjcd_stat statistic;
 138 #endif
 139 
 140 /*
 141  * Timer.
 142  */
 143 static struct timer_list sjcd_delay_timer = { NULL, NULL, 0, 0, NULL };
 144 
 145 #define SJCD_SET_TIMER( func, tmout )           \
 146     ( sjcd_delay_timer.expires = jiffies+tmout,         \
 147       sjcd_delay_timer.function = ( void * )func, \
 148       add_timer( &sjcd_delay_timer ) )
 149 
 150 #define CLEAR_TIMER del_timer( &sjcd_delay_timer )
 151 
 152 static int sjcd_cleanup(void);
 153 
 154 /*
 155  * Set up device, i.e., use command line data to set
 156  * base address.
 157  */
 158 void sjcd_setup( char *str, int *ints )
     /* [previous][next][first][last][top][bottom][index][help] */
 159 {
 160    if (ints[0] > 0)
 161       sjcd_base = ints[1];
 162 }
 163 
 164 /*
 165  * Special converters.
 166  */
 167 static unsigned char bin2bcd( int bin ){
     /* [previous][next][first][last][top][bottom][index][help] */
 168   int u, v;
 169 
 170   u = bin % 10; v = bin / 10;
 171   return( u | ( v << 4 ) );
 172 }
 173 
 174 static int bcd2bin( unsigned char bcd ){
     /* [previous][next][first][last][top][bottom][index][help] */
 175     return( ( bcd >> 4 ) * 10 + ( bcd & 0x0F ) );
 176 }
 177 
 178 static long msf2hsg( struct msf *mp ){
     /* [previous][next][first][last][top][bottom][index][help] */
 179   return( bcd2bin( mp->frame ) + bcd2bin( mp->sec ) * 75
 180          + bcd2bin( mp->min ) * 4500 - 150 );
 181 }
 182 
 183 static void hsg2msf( long hsg, struct msf *msf ){
     /* [previous][next][first][last][top][bottom][index][help] */
 184   hsg += 150; msf->min = hsg / 4500;
 185   hsg %= 4500; msf->sec = hsg / 75; msf->frame = hsg % 75;
 186   msf->min = bin2bcd( msf->min );       /* convert to BCD */
 187   msf->sec = bin2bcd( msf->sec );
 188   msf->frame = bin2bcd( msf->frame );
 189 }
 190 
 191 /*
 192  * Send a command to cdrom. Invalidate status.
 193  */
 194 static void sjcd_send_cmd( unsigned char cmd ){
     /* [previous][next][first][last][top][bottom][index][help] */
 195 #if defined( SJCD_TRACE )
 196   printk( "SJCD: send_cmd( 0x%x )\n", cmd );
 197 #endif
 198   outb( cmd, SJCDPORT( 0 ) );
 199   sjcd_command_is_in_progress = 1;
 200   sjcd_status_valid = 0;
 201   sjcd_command_failed = 0;
 202 }
 203 
 204 /*
 205  * Send a command with one arg to cdrom. Invalidate status.
 206  */
 207 static void sjcd_send_1_cmd( unsigned char cmd, unsigned char a ){
     /* [previous][next][first][last][top][bottom][index][help] */
 208 #if defined( SJCD_TRACE )
 209   printk( "SJCD: send_1_cmd( 0x%x, 0x%x )\n", cmd, a );
 210 #endif
 211   outb( cmd, SJCDPORT( 0 ) );
 212   outb( a, SJCDPORT( 0 ) );
 213   sjcd_command_is_in_progress = 1;
 214   sjcd_status_valid = 0;
 215   sjcd_command_failed = 0;
 216 }
 217 
 218 /*
 219  * Send a command with four args to cdrom. Invalidate status.
 220  */
 221 static void sjcd_send_4_cmd( unsigned char cmd, unsigned char a,
     /* [previous][next][first][last][top][bottom][index][help] */
 222             unsigned char b, unsigned char c, unsigned char d ){
 223 #if defined( SJCD_TRACE )
 224   printk( "SJCD: send_4_cmd( 0x%x )\n", cmd );
 225 #endif
 226   outb( cmd, SJCDPORT( 0 ) );
 227   outb( a, SJCDPORT( 0 ) );
 228   outb( b, SJCDPORT( 0 ) );
 229   outb( c, SJCDPORT( 0 ) );
 230   outb( d, SJCDPORT( 0 ) );
 231   sjcd_command_is_in_progress = 1;
 232   sjcd_status_valid = 0;
 233   sjcd_command_failed = 0;
 234 }
 235 
 236 /*
 237  * Send a play or read command to cdrom. Invalidate Status.
 238  */
 239 static void sjcd_send_6_cmd( unsigned char cmd, struct sjcd_play_msf *pms ){
     /* [previous][next][first][last][top][bottom][index][help] */
 240 #if defined( SJCD_TRACE )
 241   printk( "SJCD: send_long_cmd( 0x%x )\n", cmd );
 242 #endif
 243   outb( cmd, SJCDPORT( 0 ) );
 244   outb( pms->start.min,   SJCDPORT( 0 ) );
 245   outb( pms->start.sec,   SJCDPORT( 0 ) );
 246   outb( pms->start.frame, SJCDPORT( 0 ) );
 247   outb( pms->end.min,     SJCDPORT( 0 ) );
 248   outb( pms->end.sec,     SJCDPORT( 0 ) );
 249   outb( pms->end.frame,   SJCDPORT( 0 ) );
 250   sjcd_command_is_in_progress = 1;
 251   sjcd_status_valid = 0;
 252   sjcd_command_failed = 0;
 253 }
 254 
 255 /*
 256  * Get a value from the data port. Should not block, so we use a little
 257  * wait for a while. Returns 0 if OK.
 258  */
 259 static int sjcd_load_response( void *buf, int len ){
     /* [previous][next][first][last][top][bottom][index][help] */
 260   unsigned char *resp = ( unsigned char * )buf;
 261 
 262   for( ; len; --len ){ 
 263     int i;
 264     for( i = 200; i-- && !SJCD_STATUS_AVAILABLE( inb( SJCDPORT( 1 ) ) ); );
 265     if( i > 0 ) *resp++ = ( unsigned char )inb( SJCDPORT( 0 ) );
 266     else break;
 267   }
 268   return( len );
 269 }
 270 
 271 /*
 272  * Load and parse command completion status (drive info byte and maybe error).
 273  * Sorry, no error classification yet.
 274  */
 275 static void sjcd_load_status( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 276   sjcd_media_is_changed = 0;
 277   sjcd_completion_error = 0;
 278   sjcd_completion_status = inb( SJCDPORT( 0 ) );
 279   if( sjcd_completion_status & SST_DOOR_OPENED ){
 280     sjcd_door_closed = sjcd_media_is_available = 0;
 281   } else {
 282     sjcd_door_closed = 1;
 283     if( sjcd_completion_status & SST_MEDIA_CHANGED )
 284       sjcd_media_is_available = sjcd_media_is_changed = 1;
 285     else if( sjcd_completion_status & 0x0F ){
 286       /*
 287        * OK, we seem to catch an error ...
 288        */
 289       while( !SJCD_STATUS_AVAILABLE( inb( SJCDPORT( 1 ) ) ) );
 290       sjcd_completion_error = inb( SJCDPORT( 0 ) );
 291       if( ( sjcd_completion_status & 0x08 ) &&
 292          ( sjcd_completion_error & 0x40 ) )
 293         sjcd_media_is_available = 0;
 294       else sjcd_command_failed = 1;
 295     } else sjcd_media_is_available = 1;
 296   }
 297   /*
 298    * Ok, status loaded successfully.
 299    */
 300   sjcd_status_valid = 1, sjcd_error_reported = 0;
 301   sjcd_command_is_in_progress = 0;
 302 
 303   /*
 304    * If the disk is changed, the TOC is not valid.
 305    */
 306   if( sjcd_media_is_changed ) sjcd_toc_uptodate = 0;
 307 #if defined( SJCD_TRACE )
 308   printk( "SJCD: status %02x.%02x loaded.\n",
 309          ( int )sjcd_completion_status, ( int )sjcd_completion_error );
 310 #endif
 311 }
 312 
 313 /*
 314  * Read status from cdrom. Check to see if the status is available.
 315  */
 316 static int sjcd_check_status( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 317   /*
 318    * Try to load the response from cdrom into buffer.
 319    */
 320   if( SJCD_STATUS_AVAILABLE( inb( SJCDPORT( 1 ) ) ) ){
 321     sjcd_load_status();
 322     return( 1 );
 323   } else {
 324     /*
 325      * No status is available.
 326      */
 327     return( 0 );
 328   }
 329 }
 330 
 331 /*
 332  * This is just timout counter, and nothing more. Surprized ? :-)
 333  */
 334 static volatile long sjcd_status_timeout;
 335 
 336 /*
 337  * We need about 10 seconds to wait. The longest command takes about 5 seconds
 338  * to probe the disk (usually after tray closed or drive reset). Other values
 339  * should be thought of for other commands.
 340  */
 341 #define SJCD_WAIT_FOR_STATUS_TIMEOUT 1000
 342 
 343 static void sjcd_status_timer( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 344   if( sjcd_check_status() ){
 345     /*
 346      * The command completed and status is loaded, stop waiting.
 347      */
 348     wake_up( &sjcd_waitq );
 349   } else if( --sjcd_status_timeout <= 0 ){
 350     /*
 351      * We are timed out. 
 352      */
 353     wake_up( &sjcd_waitq );
 354   } else {
 355     /*
 356      * We have still some time to wait. Try again.
 357      */
 358     SJCD_SET_TIMER( sjcd_status_timer, 1 );
 359   }
 360 }
 361 
 362 /*
 363  * Wait for status for 10 sec approx. Returns non-positive when timed out.
 364  * Should not be used while reading data CDs.
 365  */
 366 static int sjcd_wait_for_status( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 367   sjcd_status_timeout = SJCD_WAIT_FOR_STATUS_TIMEOUT;
 368   SJCD_SET_TIMER( sjcd_status_timer, 1 ); 
 369   sleep_on( &sjcd_waitq );    
 370 #if defined( SJCD_DIAGNOSTIC ) || defined ( SJCD_TRACE )
 371   if( sjcd_status_timeout <= 0 )
 372     printk( "SJCD: Error Wait For Status.\n" );
 373 #endif
 374   return( sjcd_status_timeout );
 375 }
 376 
 377 static int sjcd_receive_status( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 378   int i;
 379 #if defined( SJCD_TRACE )
 380   printk( "SJCD: receive_status\n" );
 381 #endif
 382   /*
 383    * Wait a bit for status available.
 384    */
 385   for( i = 200; i-- && ( sjcd_check_status() == 0 ); );
 386   if( i < 0 ){
 387 #if defined( SJCD_TRACE )
 388     printk( "SJCD: long wait for status\n" );
 389 #endif
 390     if( sjcd_wait_for_status() <= 0 )
 391       printk( "SJCD: Timeout when read status.\n" );
 392     else i = 0;
 393   }
 394   return( i );
 395 }
 396 
 397 /*
 398  * Load the status. Issue get status command and wait for status available.
 399  */
 400 static void sjcd_get_status( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 401 #if defined( SJCD_TRACE )
 402   printk( "SJCD: get_status\n" );
 403 #endif
 404   sjcd_send_cmd( SCMD_GET_STATUS );
 405   sjcd_receive_status();
 406 }
 407 
 408 /*
 409  * Check the drive if the disk is changed. Should be revised.
 410  */
 411 static int sjcd_disk_change( kdev_t full_dev ){
     /* [previous][next][first][last][top][bottom][index][help] */
 412 #if 0
 413   printk( "SJCD: sjcd_disk_change( 0x%x )\n", full_dev );
 414 #endif
 415   if( MINOR( full_dev ) > 0 ){
 416     printk( "SJCD: request error: invalid device minor.\n" );
 417     return 0;
 418   }
 419   if( !sjcd_command_is_in_progress )
 420     sjcd_get_status();
 421   return( sjcd_status_valid ? sjcd_media_is_changed : 0 );
 422 }
 423 
 424 /*
 425  * Read the table of contents (TOC) and TOC header if necessary.
 426  * We assume that the drive contains no more than 99 toc entries.
 427  */
 428 static struct sjcd_hw_disk_info sjcd_table_of_contents[ SJCD_MAX_TRACKS ];
 429 static unsigned char sjcd_first_track_no, sjcd_last_track_no;
 430 #define sjcd_disk_length  sjcd_table_of_contents[0].un.track_msf
 431 
 432 static int sjcd_update_toc( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 433   struct sjcd_hw_disk_info info;
 434   int i;
 435 #if defined( SJCD_TRACE )
 436   printk( "SJCD: update toc:\n" );
 437 #endif
 438   /*
 439    * check to see if we need to do anything
 440    */
 441   if( sjcd_toc_uptodate ) return( 0 );
 442 
 443   /*
 444    * Get the TOC start information.
 445    */
 446   sjcd_send_1_cmd( SCMD_GET_DISK_INFO, SCMD_GET_1_TRACK );
 447   sjcd_receive_status();
 448 
 449   if( !sjcd_status_valid ){
 450     printk( "SJCD: cannot load status.\n" );
 451     return( -1 );
 452   }
 453 
 454   if( !sjcd_media_is_available ){
 455     printk( "SJCD: no disk in drive\n" );
 456     return( -1 );
 457   }
 458 
 459   if( !sjcd_command_failed ){
 460     if( sjcd_load_response( &info, sizeof( info ) ) != 0 ){
 461       printk( "SJCD: cannot load response about TOC start.\n" );
 462       return( -1 );
 463     }
 464     sjcd_first_track_no = bcd2bin( info.un.track_no );
 465   } else {
 466     printk( "SJCD: get first failed\n" );
 467     return( -1 );
 468   }
 469 #if defined( SJCD_TRACE )
 470   printk( "SJCD: TOC start 0x%02x ", sjcd_first_track_no );
 471 #endif
 472   /*
 473    * Get the TOC finish information.
 474    */
 475   sjcd_send_1_cmd( SCMD_GET_DISK_INFO, SCMD_GET_L_TRACK );
 476   sjcd_receive_status();
 477 
 478   if( !sjcd_status_valid ){
 479     printk( "SJCD: cannot load status.\n" );
 480     return( -1 );
 481   }
 482 
 483   if( !sjcd_media_is_available ){
 484     printk( "SJCD: no disk in drive\n" );
 485     return( -1 );
 486   }
 487 
 488   if( !sjcd_command_failed ){
 489     if( sjcd_load_response( &info, sizeof( info ) ) != 0 ){
 490       printk( "SJCD: cannot load response about TOC finish.\n" );
 491       return( -1 );
 492     }
 493     sjcd_last_track_no = bcd2bin( info.un.track_no );
 494   } else {
 495     printk( "SJCD: get last failed\n" );
 496     return( -1 );
 497   }
 498 #if defined( SJCD_TRACE )
 499   printk( "SJCD: TOC finish 0x%02x ", sjcd_last_track_no );
 500 #endif
 501   for( i = sjcd_first_track_no; i <= sjcd_last_track_no; i++ ){
 502     /*
 503      * Get the first track information.
 504      */
 505     sjcd_send_1_cmd( SCMD_GET_DISK_INFO, bin2bcd( i ) );
 506     sjcd_receive_status();
 507 
 508     if( !sjcd_status_valid ){
 509       printk( "SJCD: cannot load status.\n" );
 510       return( -1 );
 511     }
 512 
 513     if( !sjcd_media_is_available ){
 514       printk( "SJCD: no disk in drive\n" );
 515       return( -1 );
 516     }
 517 
 518     if( !sjcd_command_failed ){
 519       if( sjcd_load_response( &sjcd_table_of_contents[ i ],
 520                              sizeof( struct sjcd_hw_disk_info ) ) != 0 ){
 521         printk( "SJCD: cannot load info for %d track\n", i );
 522         return( -1 );
 523       }
 524     } else {
 525       printk( "SJCD: get info %d failed\n", i );
 526       return( -1 );
 527     }
 528   }
 529 
 530   /*
 531    * Get the disk lenght info.
 532    */
 533   sjcd_send_1_cmd( SCMD_GET_DISK_INFO, SCMD_GET_D_SIZE );
 534   sjcd_receive_status();
 535 
 536   if( !sjcd_status_valid ){
 537     printk( "SJCD: cannot load status.\n" );
 538     return( -1 );
 539   }
 540 
 541   if( !sjcd_media_is_available ){
 542     printk( "SJCD: no disk in drive\n" );
 543     return( -1 );
 544   }
 545 
 546   if( !sjcd_command_failed ){
 547     if( sjcd_load_response( &info, sizeof( info ) ) != 0 ){
 548       printk( "SJCD: cannot load response about disk size.\n" );
 549       return( -1 );
 550     }
 551     sjcd_disk_length.min = info.un.track_msf.min;
 552     sjcd_disk_length.sec = info.un.track_msf.sec;
 553     sjcd_disk_length.frame = info.un.track_msf.frame;
 554   } else {
 555     printk( "SJCD: get size failed\n" );
 556     return( 1 );
 557   }
 558 #if defined( SJCD_TRACE )
 559   printk( "SJCD: (%02x:%02x.%02x)\n", sjcd_disk_length.min,
 560          sjcd_disk_length.sec, sjcd_disk_length.frame );
 561 #endif
 562   return( 0 );
 563 }
 564 
 565 /*
 566  * Load subchannel information.
 567  */
 568 static int sjcd_get_q_info( struct sjcd_hw_qinfo *qp ){
     /* [previous][next][first][last][top][bottom][index][help] */
 569   int s;
 570 #if defined( SJCD_TRACE )
 571   printk( "SJCD: load sub q\n" );
 572 #endif
 573   sjcd_send_cmd( SCMD_GET_QINFO );
 574   s = sjcd_receive_status();
 575   if( s < 0 || sjcd_command_failed || !sjcd_status_valid ){
 576     sjcd_send_cmd( 0xF2 );
 577     s = sjcd_receive_status();
 578     if( s < 0 || sjcd_command_failed || !sjcd_status_valid ) return( -1 );
 579     sjcd_send_cmd( SCMD_GET_QINFO );
 580     s = sjcd_receive_status();
 581     if( s < 0 || sjcd_command_failed || !sjcd_status_valid ) return( -1 );
 582   }
 583   if( sjcd_media_is_available )
 584     if( sjcd_load_response( qp, sizeof( *qp ) ) == 0 ) return( 0 );
 585   return( -1 );
 586 }
 587 
 588 /*
 589  * Start playing from the specified position.
 590  */
 591 static int sjcd_play( struct sjcd_play_msf *mp ){
     /* [previous][next][first][last][top][bottom][index][help] */
 592   struct sjcd_play_msf msf;
 593 
 594   /*
 595    * Turn the device to play mode.
 596    */
 597   sjcd_send_1_cmd( SCMD_SET_MODE, SCMD_MODE_PLAY );
 598   if( sjcd_receive_status() < 0 ) return( -1 );
 599 
 600   /*
 601    * Seek to the starting point.
 602    */
 603   msf.start = mp->start;
 604   msf.end.min = msf.end.sec = msf.end.frame = 0x00;
 605   sjcd_send_6_cmd( SCMD_SEEK, &msf );
 606   if( sjcd_receive_status() < 0 ) return( -1 );
 607 
 608   /*
 609    * Start playing.
 610    */
 611   sjcd_send_6_cmd( SCMD_PLAY, mp );
 612   return( sjcd_receive_status() );
 613 }
 614 
 615 /*
 616  * Tray control functions.
 617  */
 618 static int sjcd_tray_close( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 619 #if defined( SJCD_TRACE )
 620   printk( "SJCD: tray_close\n" );
 621 #endif
 622   sjcd_send_cmd( SCMD_CLOSE_TRAY );
 623   return( sjcd_receive_status() );
 624 }
 625 
 626 static int sjcd_tray_lock( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 627 #if defined( SJCD_TRACE )
 628   printk( "SJCD: tray_lock\n" );
 629 #endif
 630   sjcd_send_cmd( SCMD_LOCK_TRAY );
 631   return( sjcd_receive_status() );
 632 }
 633 
 634 static int sjcd_tray_unlock( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 635 #if defined( SJCD_TRACE )
 636   printk( "SJCD: tray_unlock\n" );
 637 #endif
 638   sjcd_send_cmd( SCMD_UNLOCK_TRAY );
 639   return( sjcd_receive_status() );
 640 }
 641 
 642 static int sjcd_tray_open( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 643 #if defined( SJCD_TRACE )
 644   printk( "SJCD: tray_open\n" );
 645 #endif
 646   sjcd_send_cmd( SCMD_EJECT_TRAY );
 647   return( sjcd_receive_status() );
 648 }
 649 
 650 /*
 651  * Do some user commands.
 652  */
 653 static int sjcd_ioctl( struct inode *ip, struct file *fp,
     /* [previous][next][first][last][top][bottom][index][help] */
 654                        unsigned int cmd, unsigned long arg ){
 655 #if defined( SJCD_TRACE )
 656   printk( "SJCD:ioctl\n" );
 657 #endif
 658 
 659   if( ip == NULL ) return( -EINVAL );
 660 
 661   sjcd_get_status();
 662   if( !sjcd_status_valid ) return( -EIO );
 663   if( sjcd_update_toc() < 0 ) return( -EIO );
 664 
 665   switch( cmd ){
 666   case CDROMSTART:{
 667 #if defined( SJCD_TRACE )
 668     printk( "SJCD: ioctl: start\n" );
 669 #endif
 670     return( 0 );
 671   }
 672 
 673   case CDROMSTOP:{
 674 #if defined( SJCD_TRACE )
 675     printk( "SJCD: ioctl: stop\n" );
 676 #endif
 677     sjcd_send_cmd( SCMD_PAUSE );
 678     ( void )sjcd_receive_status();
 679     sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
 680     return( 0 );
 681   }
 682 
 683   case CDROMPAUSE:{
 684     struct sjcd_hw_qinfo q_info;
 685 #if defined( SJCD_TRACE )
 686     printk( "SJCD: ioctl: pause\n" );
 687 #endif
 688     if( sjcd_audio_status == CDROM_AUDIO_PLAY ){
 689       sjcd_send_cmd( SCMD_PAUSE );
 690       ( void )sjcd_receive_status();
 691       if( sjcd_get_q_info( &q_info ) < 0 ){
 692         sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
 693       } else {
 694         sjcd_audio_status = CDROM_AUDIO_PAUSED;
 695         sjcd_playing.start = q_info.abs;
 696       }
 697       return( 0 );
 698     } else return( -EINVAL );
 699   }
 700 
 701   case CDROMRESUME:{
 702 #if defined( SJCD_TRACE )
 703     printk( "SJCD: ioctl: resume\n" );
 704 #endif
 705     if( sjcd_audio_status == CDROM_AUDIO_PAUSED ){
 706       /*
 707        * continue play starting at saved location
 708        */
 709       if( sjcd_play( &sjcd_playing ) < 0 ){
 710         sjcd_audio_status = CDROM_AUDIO_ERROR;
 711         return( -EIO );
 712       } else {
 713         sjcd_audio_status = CDROM_AUDIO_PLAY;
 714         return( 0 );
 715       }
 716     } else return( -EINVAL );
 717   }
 718 
 719   case CDROMPLAYTRKIND:{
 720     struct cdrom_ti ti; int s;
 721 #if defined( SJCD_TRACE )
 722     printk( "SJCD: ioctl: playtrkind\n" );
 723 #endif
 724     if( ( s = verify_area( VERIFY_READ, (void *)arg, sizeof( ti ) ) ) == 0 ){
 725       memcpy_fromfs( &ti, (void *)arg, sizeof( ti ) );
 726 
 727       if( ti.cdti_trk0 < sjcd_first_track_no ) return( -EINVAL );
 728       if( ti.cdti_trk1 > sjcd_last_track_no )
 729         ti.cdti_trk1 = sjcd_last_track_no;
 730       if( ti.cdti_trk0 > ti.cdti_trk1 ) return( -EINVAL );
 731 
 732       sjcd_playing.start = sjcd_table_of_contents[ ti.cdti_trk0 ].un.track_msf;
 733       sjcd_playing.end = ( ti.cdti_trk1 < sjcd_last_track_no ) ?
 734         sjcd_table_of_contents[ ti.cdti_trk1 + 1 ].un.track_msf :
 735           sjcd_table_of_contents[ 0 ].un.track_msf;
 736       
 737       if( sjcd_play( &sjcd_playing ) < 0 ){
 738         sjcd_audio_status = CDROM_AUDIO_ERROR;
 739         return( -EIO );
 740       } else sjcd_audio_status = CDROM_AUDIO_PLAY;
 741     }
 742     return( s );
 743   }
 744 
 745   case CDROMPLAYMSF:{
 746     struct cdrom_msf sjcd_msf; int s;
 747 #if defined( SJCD_TRACE )
 748     printk( "SJCD: ioctl: playmsf\n" );
 749 #endif
 750     if( ( s = verify_area( VERIFY_READ, (void *)arg, sizeof( sjcd_msf ) ) ) == 0 ){
 751       if( sjcd_audio_status == CDROM_AUDIO_PLAY ){
 752         sjcd_send_cmd( SCMD_PAUSE );
 753         ( void )sjcd_receive_status();
 754         sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
 755       }
 756 
 757       memcpy_fromfs( &sjcd_msf, (void *)arg, sizeof( sjcd_msf ) );
 758 
 759       sjcd_playing.start.min = bin2bcd( sjcd_msf.cdmsf_min0 );
 760       sjcd_playing.start.sec = bin2bcd( sjcd_msf.cdmsf_sec0 );
 761       sjcd_playing.start.frame = bin2bcd( sjcd_msf.cdmsf_frame0 );
 762       sjcd_playing.end.min = bin2bcd( sjcd_msf.cdmsf_min1 );
 763       sjcd_playing.end.sec = bin2bcd( sjcd_msf.cdmsf_sec1 );
 764       sjcd_playing.end.frame = bin2bcd( sjcd_msf.cdmsf_frame1 );
 765 
 766       if( sjcd_play( &sjcd_playing ) < 0 ){
 767         sjcd_audio_status = CDROM_AUDIO_ERROR;
 768         return( -EIO );
 769       } else sjcd_audio_status = CDROM_AUDIO_PLAY;
 770     }
 771     return( s );
 772   }
 773 
 774   case CDROMREADTOCHDR:{
 775     struct cdrom_tochdr toc_header; int s;
 776 #if defined (SJCD_TRACE )
 777     printk( "SJCD: ioctl: readtocheader\n" );
 778 #endif
 779     if( ( s = verify_area( VERIFY_WRITE, (void *)arg, sizeof( toc_header ) ) ) == 0 ){
 780       toc_header.cdth_trk0 = sjcd_first_track_no;
 781       toc_header.cdth_trk1 = sjcd_last_track_no;
 782       memcpy_tofs( (void *)arg, &toc_header, sizeof( toc_header ) );
 783     }
 784     return( s );
 785   }
 786 
 787   case CDROMREADTOCENTRY:{
 788     struct cdrom_tocentry toc_entry; int s;
 789 #if defined( SJCD_TRACE )
 790     printk( "SJCD: ioctl: readtocentry\n" );
 791 #endif
 792     if( ( s = verify_area( VERIFY_WRITE, (void *)arg, sizeof( toc_entry ) ) ) == 0 ){
 793       struct sjcd_hw_disk_info *tp;
 794 
 795       memcpy_fromfs( &toc_entry, (void *)arg, sizeof( toc_entry ) );
 796 
 797       if( toc_entry.cdte_track == CDROM_LEADOUT )
 798         tp = &sjcd_table_of_contents[ 0 ];
 799       else if( toc_entry.cdte_track < sjcd_first_track_no ) return( -EINVAL );
 800       else if( toc_entry.cdte_track > sjcd_last_track_no ) return( -EINVAL );
 801       else tp = &sjcd_table_of_contents[ toc_entry.cdte_track ];
 802 
 803       toc_entry.cdte_adr = tp->track_control & 0x0F;
 804       toc_entry.cdte_ctrl = tp->track_control >> 4;
 805 
 806       switch( toc_entry.cdte_format ){
 807       case CDROM_LBA:
 808         toc_entry.cdte_addr.lba = msf2hsg( &( tp->un.track_msf ) );
 809         break;
 810       case CDROM_MSF:
 811         toc_entry.cdte_addr.msf.minute = bcd2bin( tp->un.track_msf.min );
 812         toc_entry.cdte_addr.msf.second = bcd2bin( tp->un.track_msf.sec );
 813         toc_entry.cdte_addr.msf.frame = bcd2bin( tp->un.track_msf.frame );
 814         break;
 815       default: return( -EINVAL );
 816       }
 817       memcpy_tofs( (void *)arg, &toc_entry, sizeof( toc_entry ) );
 818     }
 819     return( s );
 820   }
 821 
 822   case CDROMSUBCHNL:{
 823     struct cdrom_subchnl subchnl; int s;
 824 #if defined( SJCD_TRACE )
 825     printk( "SJCD: ioctl: subchnl\n" );
 826 #endif
 827     if( ( s = verify_area( VERIFY_WRITE, (void *)arg, sizeof( subchnl ) ) ) == 0 ){
 828       struct sjcd_hw_qinfo q_info;
 829 
 830       memcpy_fromfs( &subchnl, (void *)arg, sizeof( subchnl ) );
 831       if( sjcd_get_q_info( &q_info ) < 0 ) return( -EIO );
 832 
 833       subchnl.cdsc_audiostatus = sjcd_audio_status;
 834       subchnl.cdsc_adr = q_info.track_control & 0x0F;
 835       subchnl.cdsc_ctrl = q_info.track_control >> 4;
 836       subchnl.cdsc_trk = bcd2bin( q_info.track_no );
 837       subchnl.cdsc_ind = bcd2bin( q_info.x );
 838 
 839       switch( subchnl.cdsc_format ){
 840       case CDROM_LBA:
 841         subchnl.cdsc_absaddr.lba = msf2hsg( &( q_info.abs ) );
 842         subchnl.cdsc_reladdr.lba = msf2hsg( &( q_info.rel ) );
 843         break;
 844       case CDROM_MSF:
 845         subchnl.cdsc_absaddr.msf.minute = bcd2bin( q_info.abs.min );
 846         subchnl.cdsc_absaddr.msf.second = bcd2bin( q_info.abs.sec );
 847         subchnl.cdsc_absaddr.msf.frame = bcd2bin( q_info.abs.frame );
 848         subchnl.cdsc_reladdr.msf.minute = bcd2bin( q_info.rel.min );
 849         subchnl.cdsc_reladdr.msf.second = bcd2bin( q_info.rel.sec );
 850         subchnl.cdsc_reladdr.msf.frame = bcd2bin( q_info.rel.frame );
 851         break;
 852       default: return( -EINVAL );
 853       }
 854       memcpy_tofs( (void *)arg, &subchnl, sizeof( subchnl ) );
 855     }
 856     return( s );
 857   }
 858 
 859   case CDROMVOLCTRL:{
 860     struct cdrom_volctrl vol_ctrl; int s;
 861 #if defined( SJCD_TRACE )
 862     printk( "SJCD: ioctl: volctrl\n" );
 863 #endif
 864     if( ( s = verify_area( VERIFY_READ, (void *)arg, sizeof( vol_ctrl ) ) ) == 0 ){
 865       unsigned char dummy[ 4 ];
 866 
 867       memcpy_fromfs( &vol_ctrl, (void *)arg, sizeof( vol_ctrl ) );
 868       sjcd_send_4_cmd( SCMD_SET_VOLUME, vol_ctrl.channel0, 0xFF,
 869                       vol_ctrl.channel1, 0xFF );
 870       if( sjcd_receive_status() < 0 ) return( -EIO );
 871       ( void )sjcd_load_response( dummy, 4 );
 872     }
 873     return( s );
 874   }
 875 
 876   case CDROMEJECT:{
 877 #if defined( SJCD_TRACE )
 878     printk( "SJCD: ioctl: eject\n" );
 879 #endif
 880     if( !sjcd_command_is_in_progress ){
 881       sjcd_tray_unlock();
 882       sjcd_send_cmd( SCMD_EJECT_TRAY );
 883       ( void )sjcd_receive_status();
 884     }
 885     return( 0 );
 886   }
 887 
 888 #if defined( SJCD_GATHER_STAT )
 889   case 0xABCD:{
 890     int s;
 891 #if defined( SJCD_TRACE )
 892     printk( "SJCD: ioctl: statistic\n" );
 893 #endif
 894     if( ( s = verify_area( VERIFY_WRITE, (void *)arg, sizeof( statistic ) ) ) == 0 )
 895       memcpy_tofs( (void *)arg, &statistic, sizeof( statistic ) );
 896     return( s );
 897   }
 898 #endif
 899 
 900   default:
 901     return( -EINVAL );
 902   }
 903 }
 904 
 905 /*
 906  * Invalidate internal buffers of the driver.
 907  */
 908 static void sjcd_invalidate_buffers( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 909   int i;
 910   for( i = 0; i < SJCD_BUF_SIZ; sjcd_buf_bn[ i++ ] = -1 );
 911   sjcd_buf_out = -1;
 912 }
 913 
 914 /*
 915  * Take care of the different block sizes between cdrom and Linux.
 916  * When Linux gets variable block sizes this will probably go away.
 917  */
 918 
 919 #define CURRENT_IS_VALID                                      \
 920     ( CURRENT != NULL && MAJOR( CURRENT->rq_dev ) == MAJOR_NR && \
 921       CURRENT->cmd == READ && CURRENT->sector != -1 )
 922 
 923 static void sjcd_transfer( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 924 #if defined( SJCD_TRACE )
 925   printk( "SJCD: transfer:\n" );
 926 #endif
 927   if( CURRENT_IS_VALID ){
 928     while( CURRENT->nr_sectors ){
 929       int i, bn = CURRENT->sector / 4;
 930       for( i = 0; i < SJCD_BUF_SIZ && sjcd_buf_bn[ i ] != bn; i++ );
 931       if( i < SJCD_BUF_SIZ ){
 932         int offs = ( i * 4 + ( CURRENT->sector & 3 ) ) * 512;
 933         int nr_sectors = 4 - ( CURRENT->sector & 3 );
 934         if( sjcd_buf_out != i ){
 935           sjcd_buf_out = i;
 936           if( sjcd_buf_bn[ i ] != bn ){
 937             sjcd_buf_out = -1;
 938             continue;
 939           }
 940         }
 941         if( nr_sectors > CURRENT->nr_sectors )
 942           nr_sectors = CURRENT->nr_sectors;
 943 #if defined( SJCD_TRACE )
 944         printk( "SJCD: copy out\n" );
 945 #endif
 946         memcpy( CURRENT->buffer, sjcd_buf + offs, nr_sectors * 512 );
 947         CURRENT->nr_sectors -= nr_sectors;
 948         CURRENT->sector += nr_sectors;
 949         CURRENT->buffer += nr_sectors * 512;
 950       } else {
 951         sjcd_buf_out = -1;
 952         break;
 953       }
 954     }
 955   }
 956 #if defined( SJCD_TRACE )
 957   printk( "SJCD: transfer: done\n" );
 958 #endif
 959 }
 960 
 961 static void sjcd_poll( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
 962 #if defined( SJCD_GATHER_STAT )
 963   /*
 964    * Update total number of ticks.
 965    */
 966   statistic.ticks++;
 967   statistic.tticks[ sjcd_transfer_state ]++;
 968 #endif
 969 
 970  ReSwitch: switch( sjcd_transfer_state ){
 971       
 972   case SJCD_S_IDLE:{
 973 #if defined( SJCD_GATHER_STAT )
 974     statistic.idle_ticks++;
 975 #endif
 976 #if defined( SJCD_TRACE )
 977     printk( "SJCD_S_IDLE\n" );
 978 #endif
 979     return;
 980   }
 981 
 982   case SJCD_S_START:{
 983 #if defined( SJCD_GATHER_STAT )
 984     statistic.start_ticks++;
 985 #endif
 986     sjcd_send_cmd( SCMD_GET_STATUS );
 987     sjcd_transfer_state =
 988       sjcd_mode == SCMD_MODE_COOKED ? SJCD_S_READ : SJCD_S_MODE;
 989     sjcd_transfer_timeout = 500;
 990 #if defined( SJCD_TRACE )
 991     printk( "SJCD_S_START: goto SJCD_S_%s mode\n",
 992            sjcd_transfer_state == SJCD_S_READ ? "READ" : "MODE" );
 993 #endif
 994     break;
 995   }
 996     
 997   case SJCD_S_MODE:{
 998     if( sjcd_check_status() ){
 999       /*
1000        * Previous command is completed.
1001        */
1002       if( !sjcd_status_valid || sjcd_command_failed ){
1003 #if defined( SJCD_TRACE )
1004         printk( "SJCD_S_MODE: pre-cmd failed: goto to SJCD_S_STOP mode\n" );
1005 #endif
1006         sjcd_transfer_state = SJCD_S_STOP;
1007         goto ReSwitch;
1008       }
1009 
1010       sjcd_mode = 0; /* unknown mode; should not be valid when failed */
1011       sjcd_send_1_cmd( SCMD_SET_MODE, SCMD_MODE_COOKED );
1012       sjcd_transfer_state = SJCD_S_READ; sjcd_transfer_timeout = 1000;
1013 #if defined( SJCD_TRACE )
1014       printk( "SJCD_S_MODE: goto SJCD_S_READ mode\n" );
1015 #endif
1016     }
1017 #if defined( SJCD_GATHER_STAT )
1018     else statistic.mode_ticks++;
1019 #endif
1020     break;
1021   }
1022 
1023   case SJCD_S_READ:{
1024     if( sjcd_status_valid ? 1 : sjcd_check_status() ){
1025       /*
1026        * Previos command is completed.
1027        */
1028       if( !sjcd_status_valid || sjcd_command_failed ){
1029 #if defined( SJCD_TRACE )
1030         printk( "SJCD_S_READ: pre-cmd failed: goto to SJCD_S_STOP mode\n" );
1031 #endif
1032         sjcd_transfer_state = SJCD_S_STOP;
1033         goto ReSwitch;
1034       }
1035       if( !sjcd_media_is_available ){
1036 #if defined( SJCD_TRACE )
1037         printk( "SJCD_S_READ: no disk: goto to SJCD_S_STOP mode\n" );
1038 #endif
1039         sjcd_transfer_state = SJCD_S_STOP;
1040         goto ReSwitch;
1041       }
1042       if( sjcd_mode != SCMD_MODE_COOKED ){
1043         /*
1044          * We seem to come from set mode. So discard one byte of result.
1045          */
1046         if( sjcd_load_response( &sjcd_mode, 1 ) != 0 ){
1047 #if defined( SJCD_TRACE )
1048           printk( "SJCD_S_READ: load failed: goto to SJCD_S_STOP mode\n" );
1049 #endif
1050           sjcd_transfer_state = SJCD_S_STOP;
1051           goto ReSwitch;
1052         }
1053         if( sjcd_mode != SCMD_MODE_COOKED ){
1054 #if defined( SJCD_TRACE )
1055           printk( "SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n" );
1056 #endif
1057           sjcd_transfer_state = SJCD_S_STOP;
1058           goto ReSwitch;
1059         }
1060       }
1061 
1062       if( CURRENT_IS_VALID ){
1063         struct sjcd_play_msf msf;
1064 
1065         sjcd_next_bn = CURRENT->sector / 4;
1066         hsg2msf( sjcd_next_bn, &msf.start );
1067         msf.end.min = 0; msf.end.sec = 0;            
1068         msf.end.frame = sjcd_read_count = SJCD_BUF_SIZ;
1069 #if defined( SJCD_TRACE )
1070         printk( "SJCD: ---reading msf-address %x:%x:%x  %x:%x:%x\n",
1071                msf.start.min, msf.start.sec, msf.start.frame,
1072                msf.end.min,   msf.end.sec,   msf.end.frame );
1073         printk( "sjcd_next_bn:%x buf_in:%x buf_out:%x buf_bn:%x\n", \
1074              sjcd_next_bn, sjcd_buf_in, sjcd_buf_out,
1075              sjcd_buf_bn[ sjcd_buf_in ] );
1076 #endif  
1077         sjcd_send_6_cmd( SCMD_DATA_READ, &msf );
1078         sjcd_transfer_state = SJCD_S_DATA;
1079         sjcd_transfer_timeout = 500;
1080 #if defined( SJCD_TRACE )
1081         printk( "SJCD_S_READ: go to SJCD_S_DATA mode\n" );
1082 #endif
1083       } else {
1084 #if defined( SJCD_TRACE )
1085         printk( "SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n" );
1086 #endif
1087         sjcd_transfer_state = SJCD_S_STOP;
1088         goto ReSwitch;
1089       }
1090     }
1091 #if defined( SJCD_GATHER_STAT )
1092     else statistic.read_ticks++;
1093 #endif
1094     break;
1095   }
1096 
1097   case SJCD_S_DATA:{
1098     unsigned char stat;
1099 
1100   sjcd_s_data: stat = inb( SJCDPORT( 1 ) );
1101 #if defined( SJCD_TRACE )
1102     printk( "SJCD_S_DATA: status = 0x%02x\n", stat );
1103 #endif
1104     if( SJCD_STATUS_AVAILABLE( stat ) ){
1105       /*
1106        * No data is waiting for us in the drive buffer. Status of operation
1107        * completion is available. Read and parse it.
1108        */
1109       sjcd_load_status();
1110 
1111       if( !sjcd_status_valid || sjcd_command_failed ){
1112 #if defined( SJCD_TRACE )
1113         printk( "SJCD: read block %d failed, maybe audio disk? Giving up\n",
1114                sjcd_next_bn );
1115 #endif
1116         if( CURRENT_IS_VALID ) end_request( 0 );
1117 #if defined( SJCD_TRACE )
1118         printk( "SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n" );
1119 #endif
1120         sjcd_transfer_state = SJCD_S_STOP;
1121         goto ReSwitch;
1122       }
1123 
1124       if( !sjcd_media_is_available ){
1125         printk( "SJCD_S_DATA: no disk: go to SJCD_S_STOP mode\n" );
1126         sjcd_transfer_state = SJCD_S_STOP;
1127         goto ReSwitch;
1128       }
1129 
1130       sjcd_transfer_state = SJCD_S_READ;
1131       goto ReSwitch;
1132     } else if( SJCD_DATA_AVAILABLE( stat ) ){
1133       /*
1134        * One frame is read into device buffer. We must copy it to our memory.
1135        * Otherwise cdrom hangs up. Check to see if we have something to copy
1136        * to.
1137        */
1138       if( !CURRENT_IS_VALID && sjcd_buf_in == sjcd_buf_out ){
1139 #if defined( SJCD_TRACE )
1140         printk( "SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n" );
1141         printk( " ... all the date would be discarded\n" );
1142 #endif
1143         sjcd_transfer_state = SJCD_S_STOP;
1144         goto ReSwitch;
1145       }
1146 
1147       /*
1148        * Everything seems to be OK. Just read the frame and recalculate
1149        * indecis.
1150        */
1151       sjcd_buf_bn[ sjcd_buf_in ] = -1; /* ??? */
1152       insb( SJCDPORT( 2 ), sjcd_buf + 2048 * sjcd_buf_in, 2048 );
1153 #if defined( SJCD_TRACE )
1154       printk( "SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n",
1155              sjcd_next_bn, sjcd_buf_in, sjcd_buf_out,
1156              sjcd_buf_bn[ sjcd_buf_in ] );
1157 #endif
1158       sjcd_buf_bn[ sjcd_buf_in ] = sjcd_next_bn++;
1159       if( sjcd_buf_out == -1 ) sjcd_buf_out = sjcd_buf_in;
1160       if( ++sjcd_buf_in == SJCD_BUF_SIZ ) sjcd_buf_in = 0;
1161 
1162       /*
1163        * Only one frame is ready at time. So we should turn over to wait for
1164        * another frame. If we need that, of course.
1165        */
1166       if( --sjcd_read_count == 0 ){
1167         /*
1168          * OK, request seems to be precessed. Continue transferring...
1169          */
1170         if( !sjcd_transfer_is_active ){
1171           while( CURRENT_IS_VALID ){
1172             /*
1173              * Continue transferring.
1174              */
1175             sjcd_transfer();
1176             if( CURRENT->nr_sectors == 0 ) end_request( 1 );
1177             else break;
1178           }
1179         }
1180         if( CURRENT_IS_VALID &&
1181            ( CURRENT->sector / 4 < sjcd_next_bn ||
1182             CURRENT->sector / 4 > sjcd_next_bn + SJCD_BUF_SIZ ) ){
1183 #if defined( SJCD_TRACE )
1184           printk( "SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n" );
1185 #endif
1186           sjcd_transfer_state = SJCD_S_STOP;
1187           goto ReSwitch;
1188         }
1189       }
1190       /*
1191        * Now we should turn around rather than wait for while.
1192        */
1193       goto sjcd_s_data;
1194     }
1195 #if defined( SJCD_GATHER_STAT )
1196     else statistic.data_ticks++;
1197 #endif
1198     break;
1199   }
1200 
1201   case SJCD_S_STOP:{
1202     sjcd_read_count = 0;
1203     sjcd_send_cmd( SCMD_STOP );
1204     sjcd_transfer_state = SJCD_S_STOPPING;
1205     sjcd_transfer_timeout = 500;
1206 #if defined( SJCD_GATHER_STAT )
1207     statistic.stop_ticks++;
1208 #endif
1209     break;
1210   }
1211 
1212   case SJCD_S_STOPPING:{
1213     unsigned char stat;
1214     
1215     stat = inb( SJCDPORT( 1 ) );
1216 #if defined( SJCD_TRACE )
1217     printk( "SJCD_S_STOP: status = 0x%02x\n", stat );
1218 #endif      
1219     if( SJCD_DATA_AVAILABLE( stat ) ){
1220       int i;
1221 #if defined( SJCD_TRACE )
1222       printk( "SJCD_S_STOP: discard data\n" );
1223 #endif
1224       /*
1225        * Discard all the data from the pipe. Foolish method.
1226        */
1227       for( i = 2048; i--; ( void )inb( SJCDPORT( 2 ) ) );
1228       sjcd_transfer_timeout = 500;
1229     } else if( SJCD_STATUS_AVAILABLE( stat ) ){
1230       sjcd_load_status();
1231       if( sjcd_status_valid && sjcd_media_is_changed ) {
1232         sjcd_toc_uptodate = 0;
1233         sjcd_invalidate_buffers();
1234       }
1235       if( CURRENT_IS_VALID ){
1236         if( sjcd_status_valid ) sjcd_transfer_state = SJCD_S_READ;
1237         else sjcd_transfer_state = SJCD_S_START;
1238       } else sjcd_transfer_state = SJCD_S_IDLE;
1239       goto ReSwitch;
1240     }
1241 #if defined( SJCD_GATHER_STAT )
1242     else statistic.stopping_ticks++;
1243 #endif
1244     break;
1245   }
1246 
1247   default:
1248     printk( "SJCD: poll: invalid state %d\n", sjcd_transfer_state );
1249     return;
1250   }
1251   
1252   if( --sjcd_transfer_timeout == 0 ){
1253     printk( "SJCD: timeout in state %d\n", sjcd_transfer_state );
1254     while( CURRENT_IS_VALID ) end_request( 0 );
1255     sjcd_send_cmd( SCMD_STOP );
1256     sjcd_transfer_state = SJCD_S_IDLE;
1257     goto ReSwitch;
1258     }
1259 
1260   /*
1261    * Get back in some time. 1 should be replaced with count variable to
1262    * avoid unnecessary testings.
1263    */
1264   SJCD_SET_TIMER( sjcd_poll, 1 );
1265 }
1266 
1267 static void do_sjcd_request( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
1268 #if defined( SJCD_TRACE )
1269   printk( "SJCD: do_sjcd_request(%ld+%ld)\n",
1270          CURRENT->sector, CURRENT->nr_sectors );
1271 #endif
1272   sjcd_transfer_is_active = 1;
1273   while( CURRENT_IS_VALID ){
1274     /*
1275      * Who of us are paranoic?
1276      */
1277     if( CURRENT->bh && !buffer_locked(CURRENT->bh) )
1278       panic( DEVICE_NAME ": block not locked" );
1279 
1280     sjcd_transfer();
1281     if( CURRENT->nr_sectors == 0 ) end_request( 1 );
1282     else {
1283       sjcd_buf_out = -1;         /* Want to read a block not in buffer */
1284       if( sjcd_transfer_state == SJCD_S_IDLE ){
1285         if( !sjcd_toc_uptodate ){
1286           if( sjcd_update_toc() < 0 ){
1287             printk( "SJCD: transfer: discard\n" );
1288             while( CURRENT_IS_VALID ) end_request( 0 );
1289             break;
1290           }
1291         }
1292         sjcd_transfer_state = SJCD_S_START;
1293         SJCD_SET_TIMER( sjcd_poll, HZ/100 );
1294       }
1295       break;
1296     }
1297   }
1298   sjcd_transfer_is_active = 0;
1299 #if defined( SJCD_TRACE )
1300   printk( "sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n",
1301          sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, sjcd_buf_bn[ sjcd_buf_in ] );
1302   printk( "do_sjcd_request ends\n" );
1303 #endif
1304 }
1305 
1306 /*
1307  * Open the device special file. Check disk is in.
1308  */
1309 int sjcd_open( struct inode *ip, struct file *fp ){
     /* [previous][next][first][last][top][bottom][index][help] */
1310   /*
1311    * Check the presence of device.
1312    */
1313   if( !sjcd_present ) return( -ENXIO );
1314   
1315   /*
1316    * Only read operations are allowed. Really? (:-)
1317    */
1318   if( fp->f_mode & 2 ) return( -EROFS );
1319   
1320   if( sjcd_open_count == 0 ){
1321     int s, sjcd_open_tries;
1322 /* We don't know that, do we? */
1323 /*
1324     sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
1325 */
1326     sjcd_mode = 0;
1327     sjcd_door_was_open = 0;
1328     sjcd_transfer_state = SJCD_S_IDLE;
1329     sjcd_invalidate_buffers();
1330     sjcd_status_valid = 0;
1331 
1332     /*
1333      * Strict status checking.
1334      */
1335     for( sjcd_open_tries = 4; --sjcd_open_tries; ){
1336       if( !sjcd_status_valid ) sjcd_get_status();
1337       if( !sjcd_status_valid ){
1338 #if defined( SJCD_DIAGNOSTIC )
1339         printk( "SJCD: open: timed out when check status.\n" );
1340 #endif
1341         return( -EIO );
1342       } else if( !sjcd_media_is_available ){
1343 #if defined( SJCD_DIAGNOSTIC )
1344         printk("SJCD: open: no disk in drive\n");
1345 #endif
1346         if( !sjcd_door_closed ){
1347           sjcd_door_was_open = 1;
1348 #if defined( SJCD_TRACE )
1349           printk("SJCD: open: close the tray\n");
1350 #endif
1351           s = sjcd_tray_close();
1352           if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
1353 #if defined( SJCD_DIAGNOSTIC )
1354             printk("SJCD: open: tray close attempt failed\n");
1355 #endif
1356             return( -EIO );
1357           }
1358           continue;
1359         } else return( -EIO );
1360       }
1361       break;
1362     }
1363     s = sjcd_tray_lock();
1364     if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
1365 #if defined( SJCD_DIAGNOSTIC )
1366       printk("SJCD: open: tray lock attempt failed\n");
1367 #endif
1368       return( -EIO );
1369     }
1370 #if defined( SJCD_TRACE )
1371     printk( "SJCD: open: done\n" );
1372 #endif
1373   }
1374 #ifdef MODULE
1375   MOD_INC_USE_COUNT;
1376 #endif
1377   ++sjcd_open_count;
1378   return( 0 );
1379 }
1380 
1381 /*
1382  * On close, we flush all sjcd blocks from the buffer cache.
1383  */
1384 static void sjcd_release( struct inode *inode, struct file *file ){
     /* [previous][next][first][last][top][bottom][index][help] */
1385   int s;
1386 
1387 #if defined( SJCD_TRACE )
1388   printk( "SJCD: release\n" );
1389 #endif
1390 #ifdef MODULE
1391   MOD_DEC_USE_COUNT;
1392 #endif
1393   if( --sjcd_open_count == 0 ){
1394     sjcd_invalidate_buffers();
1395     sync_dev( inode->i_rdev );
1396     invalidate_buffers( inode->i_rdev );
1397     s = sjcd_tray_unlock();
1398     if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
1399 #if defined( SJCD_DIAGNOSTIC )
1400       printk("SJCD: release: tray unlock attempt failed.\n");
1401 #endif
1402     }
1403     if( sjcd_door_was_open ){
1404       s = sjcd_tray_open();
1405       if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
1406 #if defined( SJCD_DIAGNOSTIC )
1407         printk("SJCD: release: tray unload attempt failed.\n");
1408 #endif
1409       }
1410     }
1411   }
1412 }
1413 
1414 /*
1415  * A list of file operations allowed for this cdrom.
1416  */
1417 static struct file_operations sjcd_fops = {
1418   NULL,               /* lseek - default */
1419   block_read,         /* read - general block-dev read */
1420   block_write,        /* write - general block-dev write */
1421   NULL,               /* readdir - bad */
1422   NULL,               /* select */
1423   sjcd_ioctl,         /* ioctl */
1424   NULL,               /* mmap */
1425   sjcd_open,          /* open */
1426   sjcd_release,       /* release */
1427   NULL,               /* fsync */
1428   NULL,               /* fasync */
1429   sjcd_disk_change,   /* media change */
1430   NULL                /* revalidate */
1431 };
1432 
1433 /*
1434  * Following stuff is intended for initialization of the cdrom. It
1435  * first looks for presence of device. If the device is present, it
1436  * will be reset. Then read the version of the drive and load status.
1437  * The version is two BCD-coded bytes.
1438  */
1439 static struct {
1440   unsigned char major, minor;
1441 } sjcd_version;
1442 
1443 /*
1444  * Test for presence of drive and initialize it. Called at boot time.
1445  * Probe cdrom, find out version and status.
1446  */
1447 int sjcd_init( void ){
     /* [previous][next][first][last][top][bottom][index][help] */
1448   int i;
1449 
1450   printk("SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", SJCD_VERSION_MAJOR,
1451     SJCD_VERSION_MINOR);
1452 
1453 #if defined( SJCD_TRACE )
1454   printk("SJCD: sjcd=0x%x: ", sjcd_base);
1455 #endif  
1456 
1457   if( register_blkdev( MAJOR_NR, "sjcd", &sjcd_fops ) != 0 ){
1458     printk( "SJCD: Unable to get major %d for Sanyo CD-ROM\n", MAJOR_NR );
1459     return( -EIO );
1460   }
1461   
1462   blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST;
1463   read_ahead[ MAJOR_NR ] = 4;
1464   
1465   if( check_region( sjcd_base, 4 ) ){
1466     printk( "SJCD: Init failed, I/O port (%X) is already in use\n",
1467       sjcd_base );
1468     sjcd_cleanup();
1469     return( -EIO );
1470   }
1471   
1472   /*
1473    * Check for card. Since we are booting now, we can't use standard
1474    * wait algorithm.
1475    */
1476   printk( "SJCD: Resetting: " );
1477   sjcd_send_cmd( SCMD_RESET );
1478   for( i = 1000; i > 0 && !sjcd_status_valid; --i ){
1479     unsigned long timer;
1480 
1481     /*
1482      * Wait 10ms approx.
1483      */
1484     for( timer = jiffies; jiffies <= timer; );
1485     if ( (i % 100) == 0 ) printk( "." );
1486     ( void )sjcd_check_status();
1487   }
1488   if( i == 0 || sjcd_command_failed ){
1489     printk( " reset failed, no drive found.\n" );
1490     sjcd_cleanup();
1491     return( -EIO );
1492   } else printk( "\n" );
1493 
1494   /*
1495    * Get and print out cdrom version.
1496    */
1497   printk( "SJCD: Getting version: " );
1498   sjcd_send_cmd( SCMD_GET_VERSION );
1499   for( i = 1000; i > 0 && !sjcd_status_valid; --i ){
1500     unsigned long timer;
1501 
1502     /*
1503      * Wait 10ms approx.
1504      */
1505     for( timer = jiffies; jiffies <= timer; );
1506     if ( (i % 100) == 0 ) printk( "." );
1507     ( void )sjcd_check_status();
1508   }
1509   if( i == 0 || sjcd_command_failed ){
1510     printk( " get version failed, no drive found.\n" );
1511     sjcd_cleanup();
1512     return( -EIO );
1513   }
1514 
1515   if( sjcd_load_response( &sjcd_version, sizeof( sjcd_version ) ) == 0 ){
1516     printk( " %1x.%02x\n", ( int )sjcd_version.major,
1517              ( int )sjcd_version.minor );
1518   } else {
1519     printk( " read version failed, no drive found.\n" );
1520     sjcd_cleanup();
1521     return( -EIO );
1522   }
1523 
1524   /*
1525    * Check and print out the tray state. (if it is needed?).
1526    */
1527   if( !sjcd_status_valid ){
1528     printk( "SJCD: Getting status: " );
1529     sjcd_send_cmd( SCMD_GET_STATUS );
1530     for( i = 1000; i > 0 && !sjcd_status_valid; --i ){
1531       unsigned long timer;
1532 
1533       /*
1534        * Wait 10ms approx.
1535        */
1536       for( timer = jiffies; jiffies <= timer; );
1537       if ( (i % 100) == 0 ) printk( "." );
1538       ( void )sjcd_check_status();
1539     }
1540     if( i == 0 || sjcd_command_failed ){
1541       printk( " get status failed, no drive found.\n" );
1542       sjcd_cleanup();
1543       return( -EIO );
1544     } else printk( "\n" );
1545   }
1546 
1547   printk("SJCD: Status: port=0x%x.\n", sjcd_base);
1548 
1549   sjcd_present++;
1550   return( 0 );
1551 }
1552 
1553 static int
1554 sjcd_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1555 {
1556   if( (unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL) )
1557     printk( "SJCD: cannot unregister device.\n" );
1558   else
1559     release_region( sjcd_base, 4 );
1560 
1561   return(0);
1562 }
1563 
1564 #ifdef MODULE
1565 
1566 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1567 {
1568   return sjcd_init();
1569 }
1570 
1571 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1572 {
1573   if ( sjcd_cleanup() )
1574     printk( "SJCD: module: cannot be removed.\n" );
1575   else
1576     printk( "SJCD: module: removed.\n");
1577 }
1578 #endif

/* [previous][next][first][last][top][bottom][index][help] */