OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [cdrom/] [optcd.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/*      linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver
2
        $Id: optcd.c,v 1.1 2005-12-20 10:16:38 jcastillo Exp $
3
 
4
        Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
5
 
6
 
7
        Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks
8
        by Eberhard Moenkeberg (emoenke@gwdg.de).
9
 
10
        This program is free software; you can redistribute it and/or modify
11
        it under the terms of the GNU General Public License as published by
12
        the Free Software Foundation; either version 2, or (at your option)
13
        any later version.
14
 
15
        This program is distributed in the hope that it will be useful,
16
        but WITHOUT ANY WARRANTY; without even the implied warranty of
17
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
        GNU General Public License for more details.
19
 
20
        You should have received a copy of the GNU General Public License
21
        along with this program; if not, write to the Free Software
22
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
*/
24
 
25
/*      Revision history
26
 
27
 
28
        14-5-95         v0.0    Plays sound tracks. No reading of data CDs yet.
29
                                Detection of disk change doesn't work.
30
        21-5-95         v0.1    First ALPHA version. CD can be mounted. The
31
                                device major nr is borrowed from the Aztech
32
                                driver. Speed is around 240 kb/s, as measured
33
                                with "time dd if=/dev/cdrom of=/dev/null \
34
                                bs=2048 count=4096".
35
        24-6-95         v0.2    Reworked the #defines for the command codes
36
                                and the like, as well as the structure of
37
                                the hardware communication protocol, to
38
                                reflect the "official" documentation, kindly
39
                                supplied by C.K. Tan, Optics Storage Pte. Ltd.
40
                                Also tidied up the state machine somewhat.
41
        28-6-95         v0.3    Removed the ISP-16 interface code, as this
42
                                should go into its own driver. The driver now
43
                                has its own major nr.
44
                                Disk change detection now seems to work, too.
45
                                This version became part of the standard
46
                                kernel as of version 1.3.7
47
        24-9-95         v0.4    Re-inserted ISP-16 interface code which I
48
                                copied from sjcd.c, with a few changes.
49
                                Updated README.optcd. Submitted for
50
                                inclusion in 1.3.21
51
        29-9-95         v0.4a   Fixed bug that prevented compilation as module
52
        25-10-95        v0.5    Started multisession code. Implementation
53
                                copied from Werner Zimmermann, who copied it
54
                                from Heiko Schlittermann's mcdx.
55
        17-1-96         v0.6    Multisession works; some cleanup too.
56
        18-4-96         v0.7    Increased some timing constants;
57
                                thanks to Luke McFarlane. Also tidied up some
58
                                printk behaviour. ISP16 initialization
59
                                is now handled by a separate driver.
60
*/
61
 
62
/* Includes */
63
 
64
 
65
#include <linux/module.h>
66
#include <linux/mm.h>
67
#include <linux/ioport.h>
68
#include <asm/io.h>
69
 
70
#define MAJOR_NR OPTICS_CDROM_MAJOR
71
#include <linux/blk.h>
72
 
73
#include <linux/cdrom.h>
74
#include <linux/optcd.h>
75
 
76
 
77
/* Debug support */
78
 
79
 
80
/* Don't forget to add new debug flags here. */
81
#if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
82
    DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
83
#define DEBUG(x) debug x
84
static void debug(int debug_this, const char* fmt, ...)
85
{
86
        char s[1024];
87
        va_list args;
88
 
89
        if (!debug_this)
90
                return;
91
 
92
        va_start(args, fmt);
93
        vsprintf(s, fmt, args);
94
        printk(KERN_DEBUG "optcd: %s\n", s);
95
        va_end(args);
96
}
97
#else
98
#define DEBUG(x)
99
#endif
100
 
101
/* Drive hardware/firmware characteristics
102
   Identifiers in accordance with Optics Storage documentation */
103
 
104
 
105
#define optcd_port optcd                        /* Needed for the modutils. */
106
static short optcd_port = OPTCD_PORTBASE;       /* I/O base of drive. */
107
 
108
/* Drive registers, read */
109
#define DATA_PORT       optcd_port      /* Read data/status */
110
#define STATUS_PORT     optcd_port+1    /* Indicate data/status availability */
111
 
112
/* Drive registers, write */
113
#define COMIN_PORT      optcd_port      /* For passing command/parameter */
114
#define RESET_PORT      optcd_port+1    /* Write anything and wait 0.5 sec */
115
#define HCON_PORT       optcd_port+2    /* Host Xfer Configuration */
116
 
117
 
118
/* Command completion/status read from DATA register */
119
#define ST_DRVERR               0x80
120
#define ST_DOOR_OPEN            0x40
121
#define ST_MIXEDMODE_DISK       0x20
122
#define ST_MODE_BITS            0x1c
123
#define ST_M_STOP               0x00
124
#define ST_M_READ               0x04
125
#define ST_M_AUDIO              0x04
126
#define ST_M_PAUSE              0x08
127
#define ST_M_INITIAL            0x0c
128
#define ST_M_ERROR              0x10
129
#define ST_M_OTHERS             0x14
130
#define ST_MODE2TRACK           0x02
131
#define ST_DSK_CHG              0x01
132
#define ST_L_LOCK               0x01
133
#define ST_CMD_OK               0x00
134
#define ST_OP_OK                0x01
135
#define ST_PA_OK                0x02
136
#define ST_OP_ERROR             0x05
137
#define ST_PA_ERROR             0x06
138
 
139
 
140
/* Error codes (appear as command completion code from DATA register) */
141
/* Player related errors */
142
#define ERR_ILLCMD      0x11    /* Illegal command to player module */
143
#define ERR_ILLPARM     0x12    /* Illegal parameter to player module */
144
#define ERR_SLEDGE      0x13
145
#define ERR_FOCUS       0x14
146
#define ERR_MOTOR       0x15
147
#define ERR_RADIAL      0x16
148
#define ERR_PLL         0x17    /* PLL lock error */
149
#define ERR_SUB_TIM     0x18    /* Subcode timeout error */
150
#define ERR_SUB_NF      0x19    /* Subcode not found error */
151
#define ERR_TRAY        0x1a
152
#define ERR_TOC         0x1b    /* Table of Contents read error */
153
#define ERR_JUMP        0x1c
154
/* Data errors */
155
#define ERR_MODE        0x21
156
#define ERR_FORM        0x22
157
#define ERR_HEADADDR    0x23    /* Header Address not found */
158
#define ERR_CRC         0x24
159
#define ERR_ECC         0x25    /* Uncorrectable ECC error */
160
#define ERR_CRC_UNC     0x26    /* CRC error and uncorrectable error */
161
#define ERR_ILLBSYNC    0x27    /* Illegal block sync error */
162
#define ERR_VDST        0x28    /* VDST not found */
163
/* Timeout errors */
164
#define ERR_READ_TIM    0x31    /* Read timeout error */
165
#define ERR_DEC_STP     0x32    /* Decoder stopped */
166
#define ERR_DEC_TIM     0x33    /* Decoder interrupt timeout error */
167
/* Function abort codes */
168
#define ERR_KEY         0x41    /* Key -Detected abort */
169
#define ERR_READ_FINISH 0x42    /* Read Finish */
170
/* Second Byte diagnostic codes */
171
#define ERR_NOBSYNC     0x01    /* No block sync */
172
#define ERR_SHORTB      0x02    /* Short block */
173
#define ERR_LONGB       0x03    /* Long block */
174
#define ERR_SHORTDSP    0x04    /* Short DSP word */
175
#define ERR_LONGDSP     0x05    /* Long DSP word */
176
 
177
 
178
/* Status availability flags read from STATUS register */
179
#define FL_EJECT        0x20
180
#define FL_WAIT         0x10    /* active low */
181
#define FL_EOP          0x08    /* active low */
182
#define FL_STEN         0x04    /* Status available when low */
183
#define FL_DTEN         0x02    /* Data available when low */
184
#define FL_DRQ          0x01    /* active low */
185
#define FL_RESET        0xde    /* These bits are high after a reset */
186
#define FL_STDT         (FL_STEN|FL_DTEN)
187
 
188
 
189
/* Transfer mode, written to HCON register */
190
#define HCON_DTS        0x08
191
#define HCON_SDRQB      0x04
192
#define HCON_LOHI       0x02
193
#define HCON_DMA16      0x01
194
 
195
 
196
/* Drive command set, written to COMIN register */
197
/* Quick response commands */
198
#define COMDRVST        0x20    /* Drive Status Read */
199
#define COMERRST        0x21    /* Error Status Read */
200
#define COMIOCTLISTAT   0x22    /* Status Read; reset disk changed bit */
201
#define COMINITSINGLE   0x28    /* Initialize Single Speed */
202
#define COMINITDOUBLE   0x29    /* Initialize Double Speed */
203
#define COMUNLOCK       0x30    /* Unlock */
204
#define COMLOCK         0x31    /* Lock */
205
#define COMLOCKST       0x32    /* Lock/Unlock Status */
206
#define COMVERSION      0x40    /* Get Firmware Revision */
207
#define COMVOIDREADMODE 0x50    /* Void Data Read Mode */
208
/* Read commands */
209
#define COMFETCH        0x60    /* Prefetch Data */
210
#define COMREAD         0x61    /* Read */
211
#define COMREADRAW      0x62    /* Read Raw Data */
212
#define COMREADALL      0x63    /* Read All 2646 Bytes */
213
/* Player control commands */
214
#define COMLEADIN       0x70    /* Seek To Lead-in */
215
#define COMSEEK         0x71    /* Seek */
216
#define COMPAUSEON      0x80    /* Pause On */
217
#define COMPAUSEOFF     0x81    /* Pause Off */
218
#define COMSTOP         0x82    /* Stop */
219
#define COMOPEN         0x90    /* Open Tray Door */
220
#define COMCLOSE        0x91    /* Close Tray Door */
221
#define COMPLAY         0xa0    /* Audio Play */
222
#define COMPLAY_TNO     0xa2    /* Audio Play By Track Number */
223
#define COMSUBQ         0xb0    /* Read Sub-q Code */
224
#define COMLOCATION     0xb1    /* Read Head Position */
225
/* Audio control commands */
226
#define COMCHCTRL       0xc0    /* Audio Channel Control */
227
/* Miscellaneous (test) commands */
228
#define COMDRVTEST      0xd0    /* Write Test Bytes */
229
#define COMTEST         0xd1    /* Diagnostic Test */
230
 
231
/* Low level drive interface. Only here we do actual I/O
232
   Waiting for status / data available */
233
 
234
 
235
/* Busy wait until FLAG goes low. Return 0 on timeout. */
236
inline static int flag_low(int flag, unsigned long timeout)
237
{
238
        int flag_high;
239
        unsigned long count = 0;
240
 
241
        while ((flag_high = (inb(STATUS_PORT) & flag)))
242
                if (++count >= timeout)
243
                        break;
244
 
245
        DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
246
                flag, count, flag_high ? " timeout" : ""));
247
        return !flag_high;
248
}
249
 
250
 
251
/* Timed waiting for status or data */
252
static int sleep_timeout;       /* max # of ticks to sleep */
253
static struct wait_queue *waitq = NULL;
254
static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL};
255
 
256
#define SET_TIMER(func, jifs) \
257
        delay_timer.expires = jiffies+(jifs); \
258
        delay_timer.function = (void *) (func); \
259
        add_timer(&delay_timer);
260
#define CLEAR_TIMER     del_timer(&delay_timer)
261
 
262
 
263
/* Timer routine: wake up when desired flag goes low,
264
   or when timeout expires. */
265
static void sleep_timer(void)
266
{
267
        int flags = inb(STATUS_PORT) & FL_STDT;
268
 
269
        if (flags == FL_STDT && --sleep_timeout > 0) {
270
                SET_TIMER(sleep_timer, HZ/100); /* multi-statement macro */
271
        } else
272
                wake_up(&waitq);
273
}
274
 
275
 
276
/* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
277
static int sleep_flag_low(int flag, unsigned long timeout)
278
{
279
        int flag_high;
280
 
281
        DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
282
 
283
        sleep_timeout = timeout;
284
        flag_high = inb(STATUS_PORT) & flag;
285
        if (flag_high && sleep_timeout > 0) {
286
                SET_TIMER(sleep_timer, HZ/100);
287
                sleep_on(&waitq);
288
                flag_high = inb(STATUS_PORT) & flag;
289
        }
290
 
291
        DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
292
                flag, timeout, flag_high ? " timeout" : ""));
293
        return !flag_high;
294
}
295
 
296
/* Low level drive interface. Only here we do actual I/O
297
   Sending commands and parameters */
298
 
299
 
300
/* Errors in the command protocol */
301
#define ERR_IF_CMD_TIMEOUT      0x100
302
#define ERR_IF_ERR_TIMEOUT      0x101
303
#define ERR_IF_RESP_TIMEOUT     0x102
304
#define ERR_IF_DATA_TIMEOUT     0x103
305
#define ERR_IF_NOSTAT           0x104
306
 
307
 
308
/* Send command code. Return <0 indicates error */
309
static int send_cmd(int cmd)
310
{
311
        unsigned char ack;
312
 
313
        DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
314
 
315
        outb(HCON_DTS, HCON_PORT);      /* Enable Suspend Data Transfer */
316
        outb(cmd, COMIN_PORT);          /* Send command code */
317
        if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
318
                return -ERR_IF_CMD_TIMEOUT;
319
        ack = inb(DATA_PORT);           /* read command acknowledge */
320
        outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
321
        return ack==ST_OP_OK ? 0 : -ack;
322
}
323
 
324
 
325
/* Send command parameters. Return <0 indicates error */
326
static int send_params(struct cdrom_msf *params)
327
{
328
        unsigned char ack;
329
 
330
        DEBUG((DEBUG_DRIVE_IF, "sending parameters"
331
                " %02x:%02x:%02x"
332
                " %02x:%02x:%02x",
333
                params->cdmsf_min0,
334
                params->cdmsf_sec0,
335
                params->cdmsf_frame0,
336
                params->cdmsf_min1,
337
                params->cdmsf_sec1,
338
                params->cdmsf_frame1));
339
 
340
        outb(params->cdmsf_min0, COMIN_PORT);
341
        outb(params->cdmsf_sec0, COMIN_PORT);
342
        outb(params->cdmsf_frame0, COMIN_PORT);
343
        outb(params->cdmsf_min1, COMIN_PORT);
344
        outb(params->cdmsf_sec1, COMIN_PORT);
345
        outb(params->cdmsf_frame1, COMIN_PORT);
346
        if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
347
                return -ERR_IF_CMD_TIMEOUT;
348
        ack = inb(DATA_PORT);           /* read command acknowledge */
349
        return ack==ST_PA_OK ? 0 : -ack;
350
}
351
 
352
 
353
/* Send parameters for SEEK command. Return <0 indicates error */
354
static int send_seek_params(struct cdrom_msf *params)
355
{
356
        unsigned char ack;
357
 
358
        DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
359
                " %02x:%02x:%02x",
360
                params->cdmsf_min0,
361
                params->cdmsf_sec0,
362
                params->cdmsf_frame0));
363
 
364
        outb(params->cdmsf_min0, COMIN_PORT);
365
        outb(params->cdmsf_sec0, COMIN_PORT);
366
        outb(params->cdmsf_frame0, COMIN_PORT);
367
        if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
368
                return -ERR_IF_CMD_TIMEOUT;
369
        ack = inb(DATA_PORT);           /* read command acknowledge */
370
        return ack==ST_PA_OK ? 0 : -ack;
371
}
372
 
373
 
374
/* Wait for command execution status. Choice between busy waiting
375
   and sleeping. Return value <0 indicates timeout. */
376
inline static int get_exec_status(int busy_waiting)
377
{
378
        unsigned char exec_status;
379
 
380
        if (busy_waiting
381
            ? !flag_low(FL_STEN, BUSY_TIMEOUT)
382
            : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
383
                return -ERR_IF_CMD_TIMEOUT;
384
 
385
        exec_status = inb(DATA_PORT);
386
        DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
387
        return exec_status;
388
}
389
 
390
 
391
/* Wait busy for extra byte of data that a command returns.
392
   Return value <0 indicates timeout. */
393
inline static int get_data(int short_timeout)
394
{
395
        unsigned char data;
396
 
397
        if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
398
                return -ERR_IF_DATA_TIMEOUT;
399
 
400
        data = inb(DATA_PORT);
401
        DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
402
        return data;
403
}
404
 
405
 
406
/* Returns 0 if failed */
407
static int reset_drive(void)
408
{
409
        unsigned long count = 0;
410
        int flags;
411
 
412
        DEBUG((DEBUG_DRIVE_IF, "reset drive"));
413
 
414
        outb(0, RESET_PORT);
415
        while (++count < RESET_WAIT)
416
                inb(DATA_PORT);
417
 
418
        count = 0;
419
        while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
420
                if (++count >= BUSY_TIMEOUT)
421
                        break;
422
 
423
        DEBUG((DEBUG_DRIVE_IF, "reset %s",
424
                flags == FL_RESET ? "succeeded" : "failed"));
425
 
426
        if (flags != FL_RESET)
427
                return 0;                /* Reset failed */
428
        outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
429
        return 1;                       /* Reset succeeded */
430
}
431
 
432
 
433
/* Facilities for asynchronous operation */
434
 
435
/* Read status/data availability flags FL_STEN and FL_DTEN */
436
inline static int stdt_flags(void)
437
{
438
        return inb(STATUS_PORT) & FL_STDT;
439
}
440
 
441
 
442
/* Fetch status that has previously been waited for. <0 means not available */
443
inline static int fetch_status(void)
444
{
445
        unsigned char status;
446
 
447
        if (inb(STATUS_PORT) & FL_STEN)
448
                return -ERR_IF_NOSTAT;
449
 
450
        status = inb(DATA_PORT);
451
        DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
452
        return status;
453
}
454
 
455
 
456
/* Fetch data that has previously been waited for. */
457
inline static void fetch_data(char *buf, int n)
458
{
459
        insb(DATA_PORT, buf, n);
460
        DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
461
}
462
 
463
 
464
/* Flush status and data fifos */
465
inline static void flush_data(void)
466
{
467
        while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
468
                inb(DATA_PORT);
469
        DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
470
}
471
 
472
/* Command protocol */
473
 
474
 
475
/* Send a simple command and wait for response. Command codes < COMFETCH
476
   are quick response commands */
477
inline static int exec_cmd(int cmd)
478
{
479
        int ack = send_cmd(cmd);
480
        if (ack < 0)
481
                return ack;
482
        return get_exec_status(cmd < COMFETCH);
483
}
484
 
485
 
486
/* Send a command with parameters. Don't wait for the response,
487
 * which consists of data blocks read from the CD. */
488
inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
489
{
490
        int ack = send_cmd(cmd);
491
        if (ack < 0)
492
                return ack;
493
        return send_params(params);
494
}
495
 
496
 
497
/* Send a seek command with parameters and wait for response */
498
inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
499
{
500
        int ack = send_cmd(cmd);
501
        if (ack < 0)
502
                return ack;
503
        ack = send_seek_params(params);
504
        if (ack < 0)
505
                return ack;
506
        return 0;
507
}
508
 
509
 
510
/* Send a command with parameters and wait for response */
511
inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
512
{
513
        int ack = exec_read_cmd(cmd, params);
514
        if (ack < 0)
515
                return ack;
516
        return get_exec_status(0);
517
}
518
 
519
/* Address conversion routines */
520
 
521
 
522
/* Binary to BCD (2 digits) */
523
inline static void single_bin2bcd(u_char *p)
524
{
525
        DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
526
        *p = (*p % 10) | ((*p / 10) << 4);
527
}
528
 
529
 
530
/* Convert entire msf struct */
531
static void bin2bcd(struct cdrom_msf *msf)
532
{
533
        single_bin2bcd(&msf->cdmsf_min0);
534
        single_bin2bcd(&msf->cdmsf_sec0);
535
        single_bin2bcd(&msf->cdmsf_frame0);
536
        single_bin2bcd(&msf->cdmsf_min1);
537
        single_bin2bcd(&msf->cdmsf_sec1);
538
        single_bin2bcd(&msf->cdmsf_frame1);
539
}
540
 
541
 
542
/* Linear block address to minute, second, frame form */
543
#define CD_FPM  (CD_SECS * CD_FRAMES)   /* frames per minute */
544
 
545
static void lba2msf(int lba, struct cdrom_msf *msf)
546
{
547
        DEBUG((DEBUG_CONV, "lba2msf %d", lba));
548
        lba += CD_MSF_OFFSET;
549
        msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
550
        msf->cdmsf_sec0 = lba / CD_FRAMES;
551
        msf->cdmsf_frame0 = lba % CD_FRAMES;
552
        msf->cdmsf_min1 = 0;
553
        msf->cdmsf_sec1 = 0;
554
        msf->cdmsf_frame1 = 0;
555
        bin2bcd(msf);
556
}
557
 
558
 
559
/* Two BCD digits to binary */
560
inline static u_char bcd2bin(u_char bcd)
561
{
562
        DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
563
        return (bcd >> 4) * 10 + (bcd & 0x0f);
564
}
565
 
566
 
567
static void msf2lba(union cdrom_addr *addr)
568
{
569
        addr->lba = addr->msf.minute * CD_FPM
570
                    + addr->msf.second * CD_FRAMES
571
                    + addr->msf.frame - CD_MSF_OFFSET;
572
}
573
 
574
 
575
/* Minute, second, frame address BCD to binary or to linear address,
576
   depending on MODE */
577
static void msf_bcd2bin(union cdrom_addr *addr)
578
{
579
        addr->msf.minute = bcd2bin(addr->msf.minute);
580
        addr->msf.second = bcd2bin(addr->msf.second);
581
        addr->msf.frame = bcd2bin(addr->msf.frame);
582
}
583
 
584
/* High level drive commands */
585
 
586
 
587
static int audio_status = CDROM_AUDIO_NO_STATUS;
588
static char toc_uptodate = 0;
589
static char disk_changed = 1;
590
 
591
/* Get drive status, flagging completion of audio play and disk changes. */
592
static int drive_status(void)
593
{
594
        int status;
595
 
596
        status = exec_cmd(COMIOCTLISTAT);
597
        DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
598
        if (status < 0)
599
                return status;
600
        if (status == 0xff)     /* No status available */
601
                return -ERR_IF_NOSTAT;
602
 
603
        if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
604
                (audio_status == CDROM_AUDIO_PLAY)) {
605
                audio_status = CDROM_AUDIO_COMPLETED;
606
        }
607
 
608
        if (status & ST_DSK_CHG) {
609
                toc_uptodate = 0;
610
                disk_changed = 1;
611
                audio_status = CDROM_AUDIO_NO_STATUS;
612
        }
613
 
614
        return status;
615
}
616
 
617
 
618
/* Read the current Q-channel info. Also used for reading the
619
   table of contents. qp->cdsc_format must be set on entry to
620
   indicate the desired address format */
621
static int get_q_channel(struct cdrom_subchnl *qp)
622
{
623
        int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
624
 
625
        status = drive_status();
626
        if (status < 0)
627
                return status;
628
        qp->cdsc_audiostatus = audio_status;
629
 
630
        status = exec_cmd(COMSUBQ);
631
        if (status < 0)
632
                return status;
633
 
634
        d1 = get_data(0);
635
        if (d1 < 0)
636
                return d1;
637
        qp->cdsc_adr = d1;
638
        qp->cdsc_ctrl = d1 >> 4;
639
 
640
        d2 = get_data(0);
641
        if (d2 < 0)
642
                return d2;
643
        qp->cdsc_trk = bcd2bin(d2);
644
 
645
        d3 = get_data(0);
646
        if (d3 < 0)
647
                return d3;
648
        qp->cdsc_ind = bcd2bin(d3);
649
 
650
        d4 = get_data(0);
651
        if (d4 < 0)
652
                return d4;
653
        qp->cdsc_reladdr.msf.minute = d4;
654
 
655
        d5 = get_data(0);
656
        if (d5 < 0)
657
                return d5;
658
        qp->cdsc_reladdr.msf.second = d5;
659
 
660
        d6 = get_data(0);
661
        if (d6 < 0)
662
                return d6;
663
        qp->cdsc_reladdr.msf.frame = d6;
664
 
665
        d7 = get_data(0);
666
        if (d7 < 0)
667
                return d7;
668
        /* byte not used */
669
 
670
        d8 = get_data(0);
671
        if (d8 < 0)
672
                return d8;
673
        qp->cdsc_absaddr.msf.minute = d8;
674
 
675
        d9 = get_data(0);
676
        if (d9 < 0)
677
                return d9;
678
        qp->cdsc_absaddr.msf.second = d9;
679
 
680
        d10 = get_data(0);
681
        if (d10 < 0)
682
                return d10;
683
        qp->cdsc_absaddr.msf.frame = d10;
684
 
685
        DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
686
                d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
687
 
688
        msf_bcd2bin(&qp->cdsc_absaddr);
689
        msf_bcd2bin(&qp->cdsc_reladdr);
690
        if (qp->cdsc_format == CDROM_LBA) {
691
                msf2lba(&qp->cdsc_absaddr);
692
                msf2lba(&qp->cdsc_reladdr);
693
        }
694
 
695
        return 0;
696
}
697
 
698
/* Table of contents handling */
699
 
700
 
701
/* Errors in table of contents */
702
#define ERR_TOC_MISSINGINFO     0x120
703
#define ERR_TOC_MISSINGENTRY    0x121
704
 
705
 
706
struct cdrom_disk_info {
707
        unsigned char           first;
708
        unsigned char           last;
709
        struct cdrom_msf0       disk_length;
710
        struct cdrom_msf0       first_track;
711
        /* Multisession info: */
712
        unsigned char           next;
713
        struct cdrom_msf0       next_session;
714
        struct cdrom_msf0       last_session;
715
        unsigned char           multi;
716
        unsigned char           xa;
717
        unsigned char           audio;
718
};
719
static struct cdrom_disk_info disk_info;
720
 
721
#define MAX_TRACKS              111
722
static struct cdrom_subchnl toc[MAX_TRACKS];
723
 
724
#define QINFO_FIRSTTRACK        100 /* bcd2bin(0xa0) */
725
#define QINFO_LASTTRACK         101 /* bcd2bin(0xa1) */
726
#define QINFO_DISKLENGTH        102 /* bcd2bin(0xa2) */
727
#define QINFO_NEXTSESSION       110 /* bcd2bin(0xb0) */
728
 
729
#define I_FIRSTTRACK    0x01
730
#define I_LASTTRACK     0x02
731
#define I_DISKLENGTH    0x04
732
#define I_NEXTSESSION   0x08
733
#define I_ALL   (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
734
 
735
 
736
#if DEBUG_TOC
737
void toc_debug_info(int i)
738
{
739
        printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d"
740
                "  %2d:%02d.%02d %2d:%02d.%02d\n",
741
                i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
742
                toc[i].cdsc_trk, toc[i].cdsc_ind,
743
                toc[i].cdsc_reladdr.msf.minute,
744
                toc[i].cdsc_reladdr.msf.second,
745
                toc[i].cdsc_reladdr.msf.frame,
746
                toc[i].cdsc_absaddr.msf.minute,
747
                toc[i].cdsc_absaddr.msf.second,
748
                toc[i].cdsc_absaddr.msf.frame);
749
}
750
#endif
751
 
752
 
753
static int read_toc(void)
754
{
755
        int status, limit, count;
756
        unsigned char got_info = 0;
757
        struct cdrom_subchnl q_info;
758
#if DEBUG_TOC
759
        int i;
760
#endif
761
 
762
        DEBUG((DEBUG_TOC, "starting read_toc"));
763
 
764
        count = 0;
765
        for (limit = 60; limit > 0; limit--) {
766
                int index;
767
 
768
                q_info.cdsc_format = CDROM_MSF;
769
                status = get_q_channel(&q_info);
770
                if (status < 0)
771
                        return status;
772
 
773
                index = q_info.cdsc_ind;
774
                if (index > 0 && index < MAX_TRACKS
775
                    && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
776
                        toc[index] = q_info;
777
                        DEBUG((DEBUG_TOC, "got %d", index));
778
                        if (index < 100)
779
                                count++;
780
 
781
                        switch (q_info.cdsc_ind) {
782
                        case QINFO_FIRSTTRACK:
783
                                got_info |= I_FIRSTTRACK;
784
                                break;
785
                        case QINFO_LASTTRACK:
786
                                got_info |= I_LASTTRACK;
787
                                break;
788
                        case QINFO_DISKLENGTH:
789
                                got_info |= I_DISKLENGTH;
790
                                break;
791
                        case QINFO_NEXTSESSION:
792
                                got_info |= I_NEXTSESSION;
793
                                break;
794
                        }
795
                }
796
 
797
                if ((got_info & I_ALL) == I_ALL
798
                    && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
799
                       >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
800
                        break;
801
        }
802
 
803
        /* Construct disk_info from TOC */
804
        if (disk_info.first == 0) {
805
                disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
806
                disk_info.first_track.minute =
807
                        toc[disk_info.first].cdsc_absaddr.msf.minute;
808
                disk_info.first_track.second =
809
                        toc[disk_info.first].cdsc_absaddr.msf.second;
810
                disk_info.first_track.frame =
811
                        toc[disk_info.first].cdsc_absaddr.msf.frame;
812
        }
813
        disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
814
        disk_info.disk_length.minute =
815
                        toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
816
        disk_info.disk_length.second =
817
                        toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
818
        disk_info.disk_length.frame =
819
                        toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
820
        disk_info.next_session.minute =
821
                        toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
822
        disk_info.next_session.second =
823
                        toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
824
        disk_info.next_session.frame =
825
                        toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
826
        disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
827
        disk_info.last_session.minute =
828
                        toc[disk_info.next].cdsc_absaddr.msf.minute;
829
        disk_info.last_session.second =
830
                        toc[disk_info.next].cdsc_absaddr.msf.second;
831
        disk_info.last_session.frame =
832
                        toc[disk_info.next].cdsc_absaddr.msf.frame;
833
        toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
834
                        disk_info.disk_length.minute;
835
        toc[disk_info.last + 1].cdsc_absaddr.msf.second =
836
                        disk_info.disk_length.second;
837
        toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
838
                        disk_info.disk_length.frame;
839
#if DEBUG_TOC
840
        for (i = 1; i <= disk_info.last + 1; i++)
841
                toc_debug_info(i);
842
        toc_debug_info(QINFO_FIRSTTRACK);
843
        toc_debug_info(QINFO_LASTTRACK);
844
        toc_debug_info(QINFO_DISKLENGTH);
845
        toc_debug_info(QINFO_NEXTSESSION);
846
#endif
847
 
848
        DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
849
                got_info, count));
850
        if ((got_info & I_ALL) != I_ALL
851
            || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
852
               < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
853
                return -ERR_TOC_MISSINGINFO;
854
        return 0;
855
}
856
 
857
 
858
#ifdef MULTISESSION
859
static int get_multi_disk_info(void)
860
{
861
        int sessions, status;
862
        struct cdrom_msf multi_index;
863
 
864
 
865
        for (sessions = 2; sessions < 10 /* %%for now */; sessions++) {
866
                int count;
867
 
868
                for (count = 100; count < MAX_TRACKS; count++)
869
                        toc[count].cdsc_ind = 0;
870
 
871
                multi_index.cdmsf_min0 = disk_info.next_session.minute;
872
                multi_index.cdmsf_sec0 = disk_info.next_session.second;
873
                multi_index.cdmsf_frame0 = disk_info.next_session.frame;
874
                if (multi_index.cdmsf_sec0 >= 20)
875
                        multi_index.cdmsf_sec0 -= 20;
876
                else {
877
                        multi_index.cdmsf_sec0 += 40;
878
                        multi_index.cdmsf_min0--;
879
                }
880
                DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
881
                        multi_index.cdmsf_min0,
882
                        multi_index.cdmsf_sec0,
883
                        multi_index.cdmsf_frame0));
884
                bin2bcd(&multi_index);
885
                multi_index.cdmsf_min1 = 0;
886
                multi_index.cdmsf_sec1 = 0;
887
                multi_index.cdmsf_frame1 = 1;
888
 
889
                status = exec_read_cmd(COMREAD, &multi_index);
890
                if (status < 0) {
891
                        DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
892
                                -status));
893
                        break;
894
                }
895
                status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
896
 
897
                flush_data();
898
                if (status < 0) {
899
                        DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
900
                        break;
901
                }
902
 
903
                status = read_toc();
904
                if (status < 0) {
905
                        DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
906
                        break;
907
                }
908
 
909
                disk_info.multi = 1;
910
        }
911
 
912
        exec_cmd(COMSTOP);
913
 
914
        if (status < 0)
915
                return -EIO;
916
        return 0;
917
}
918
#endif MULTISESSION
919
 
920
 
921
static int update_toc(void)
922
{
923
        int status, count;
924
 
925
        if (toc_uptodate)
926
                return 0;
927
 
928
        DEBUG((DEBUG_TOC, "starting update_toc"));
929
 
930
        disk_info.first = 0;
931
        for (count = 0; count < MAX_TRACKS; count++)
932
                toc[count].cdsc_ind = 0;
933
 
934
        status = exec_cmd(COMLEADIN);
935
        if (status < 0)
936
                return -EIO;
937
 
938
        status = read_toc();
939
        if (status < 0) {
940
                DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
941
                return -EIO;
942
        }
943
 
944
        /* Audio disk detection. Look at first track. */
945
        disk_info.audio =
946
                (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
947
 
948
        /* XA detection */
949
        disk_info.xa = drive_status() & ST_MODE2TRACK;
950
 
951
        /* Multisession detection: if we want this, define MULTISESSION */
952
        disk_info.multi = 0;
953
#ifdef MULTISESSION
954
        if (disk_info.xa)
955
                get_multi_disk_info();  /* Here disk_info.multi is set */
956
#endif MULTISESSION
957
        if (disk_info.multi)
958
                printk(KERN_WARNING "optcd: Multisession support experimental, "
959
                        "see linux/Documentation/cdrom/optcd\n");
960
 
961
        DEBUG((DEBUG_TOC, "exiting update_toc"));
962
 
963
        toc_uptodate = 1;
964
        return 0;
965
}
966
 
967
/* Request handling */
968
 
969
 
970
#define CURRENT_VALID \
971
        (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
972
         && CURRENT -> cmd == READ && CURRENT -> sector != -1)
973
 
974
 
975
/* Buffers for block size conversion. */
976
#define NOBUF           -1
977
 
978
static char buf[CD_FRAMESIZE * N_BUFS];
979
static volatile int buf_bn[N_BUFS], next_bn;
980
static volatile int buf_in = 0, buf_out = NOBUF;
981
 
982
inline static void opt_invalidate_buffers(void)
983
{
984
        int i;
985
 
986
        DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
987
 
988
        for (i = 0; i < N_BUFS; i++)
989
                buf_bn[i] = NOBUF;
990
        buf_out = NOBUF;
991
}
992
 
993
 
994
/* Take care of the different block sizes between cdrom and Linux.
995
   When Linux gets variable block sizes this will probably go away. */
996
static void transfer(void)
997
{
998
#if DEBUG_BUFFERS | DEBUG_REQUEST
999
        printk(KERN_DEBUG "optcd: executing transfer\n");
1000
#endif
1001
 
1002
        if (!CURRENT_VALID)
1003
                return;
1004
        while (CURRENT -> nr_sectors) {
1005
                int bn = CURRENT -> sector / 4;
1006
                int i, offs, nr_sectors;
1007
                for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
1008
 
1009
                DEBUG((DEBUG_REQUEST, "found %d", i));
1010
 
1011
                if (i >= N_BUFS) {
1012
                        buf_out = NOBUF;
1013
                        break;
1014
                }
1015
 
1016
                offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
1017
                nr_sectors = 4 - (CURRENT -> sector & 3);
1018
 
1019
                if (buf_out != i) {
1020
                        buf_out = i;
1021
                        if (buf_bn[i] != bn) {
1022
                                buf_out = NOBUF;
1023
                                continue;
1024
                        }
1025
                }
1026
 
1027
                if (nr_sectors > CURRENT -> nr_sectors)
1028
                        nr_sectors = CURRENT -> nr_sectors;
1029
                memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512);
1030
                CURRENT -> nr_sectors -= nr_sectors;
1031
                CURRENT -> sector += nr_sectors;
1032
                CURRENT -> buffer += nr_sectors * 512;
1033
        }
1034
}
1035
 
1036
 
1037
/* State machine for reading disk blocks */
1038
 
1039
enum state_e {
1040
        S_IDLE,         /* 0 */
1041
        S_START,        /* 1 */
1042
        S_READ,         /* 2 */
1043
        S_DATA,         /* 3 */
1044
        S_STOP,         /* 4 */
1045
        S_STOPPING      /* 5 */
1046
};
1047
 
1048
static volatile enum state_e state = S_IDLE;
1049
#if DEBUG_STATE
1050
static volatile enum state_e state_old = S_STOP;
1051
static volatile int flags_old = 0;
1052
static volatile long state_n = 0;
1053
#endif
1054
 
1055
 
1056
/* Used as mutex to keep do_optcd_request (and other processes calling
1057
   ioctl) out while some process is inside a VFS call.
1058
   Reverse is accomplished by checking if state = S_IDLE upon entry
1059
   of opt_ioctl and opt_media_change. */
1060
static int in_vfs = 0;
1061
 
1062
 
1063
static volatile int transfer_is_active = 0;
1064
static volatile int error = 0;   /* %% do something with this?? */
1065
static int tries;               /* ibid?? */
1066
static int timeout = 0;
1067
 
1068
static struct timer_list req_timer = {NULL, NULL, 0, 0, NULL};
1069
 
1070
#define SET_REQ_TIMER(func, jifs) \
1071
        req_timer.expires = jiffies+(jifs); \
1072
        req_timer.function = (void *) (func); \
1073
        add_timer(&req_timer);
1074
#define CLEAR_REQ_TIMER del_timer(&req_timer)
1075
 
1076
static void poll(void)
1077
{
1078
        static volatile int read_count = 1;
1079
        int flags;
1080
        int loop_again = 1;
1081
        int status = 0;
1082
        int skip = 0;
1083
 
1084
        if (error) {
1085
                printk(KERN_ERR "optcd: I/O error 0x%02x\n", error);
1086
                opt_invalidate_buffers();
1087
                if (!tries--) {
1088
                        printk(KERN_ERR "optcd: read block %d failed;"
1089
                                " Giving up\n", next_bn);
1090
                        if (transfer_is_active)
1091
                                loop_again = 0;
1092
                        if (CURRENT_VALID)
1093
                                end_request(0);
1094
                        tries = 5;
1095
                }
1096
                error = 0;
1097
                state = S_STOP;
1098
        }
1099
 
1100
        while (loop_again)
1101
        {
1102
                loop_again = 0; /* each case must flip this back to 1 if we want
1103
                                 to come back up here */
1104
 
1105
#if DEBUG_STATE
1106
                if (state == state_old)
1107
                        state_n++;
1108
                else {
1109
                        state_old = state;
1110
                        if (++state_n > 1)
1111
                                printk(KERN_DEBUG "optcd: %ld times "
1112
                                        "in previous state\n", state_n);
1113
                        printk(KERN_DEBUG "optcd: state %d\n", state);
1114
                        state_n = 0;
1115
                }
1116
#endif
1117
 
1118
                switch (state) {
1119
                case S_IDLE:
1120
                        return;
1121
                case S_START:
1122
                        if (in_vfs)
1123
                                break;
1124
                        if (send_cmd(COMDRVST)) {
1125
                                state = S_IDLE;
1126
                                while (CURRENT_VALID)
1127
                                        end_request(0);
1128
                                return;
1129
                        }
1130
                        state = S_READ;
1131
                        timeout = READ_TIMEOUT;
1132
                        break;
1133
                case S_READ: {
1134
                        struct cdrom_msf msf;
1135
                        if (!skip) {
1136
                                status = fetch_status();
1137
                                if (status < 0)
1138
                                        break;
1139
                                if (status & ST_DSK_CHG) {
1140
                                        toc_uptodate = 0;
1141
                                        opt_invalidate_buffers();
1142
                                }
1143
                        }
1144
                        skip = 0;
1145
                        if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1146
                                toc_uptodate = 0;
1147
                                opt_invalidate_buffers();
1148
                                printk(KERN_WARNING "optcd: %s\n",
1149
                                        (status & ST_DOOR_OPEN)
1150
                                        ? "door open"
1151
                                        : "disk removed");
1152
                                state = S_IDLE;
1153
                                while (CURRENT_VALID)
1154
                                        end_request(0);
1155
                                return;
1156
                        }
1157
                        if (!CURRENT_VALID) {
1158
                                state = S_STOP;
1159
                                loop_again = 1;
1160
                                break;
1161
                        }
1162
                        next_bn = CURRENT -> sector / 4;
1163
                        lba2msf(next_bn, &msf);
1164
                        read_count = N_BUFS;
1165
                        msf.cdmsf_frame1 = read_count; /* Not BCD! */
1166
 
1167
                        DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x",
1168
                                msf.cdmsf_min0,
1169
                                msf.cdmsf_sec0,
1170
                                msf.cdmsf_frame0,
1171
                                msf.cdmsf_min1,
1172
                                msf.cdmsf_sec1,
1173
                                msf.cdmsf_frame1));
1174
                        DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"
1175
                                " buf_out:%d buf_bn:%d",
1176
                                next_bn,
1177
                                buf_in,
1178
                                buf_out,
1179
                                buf_bn[buf_in]));
1180
 
1181
                        exec_read_cmd(COMREAD, &msf);
1182
                        state = S_DATA;
1183
                        timeout = READ_TIMEOUT;
1184
                        break;
1185
                }
1186
                case S_DATA:
1187
                        flags = stdt_flags() & (FL_STEN|FL_DTEN);
1188
 
1189
#if DEBUG_STATE
1190
                        if (flags != flags_old) {
1191
                                flags_old = flags;
1192
                                printk(KERN_DEBUG "optcd: flags:%x\n", flags);
1193
                        }
1194
                        if (flags == FL_STEN)
1195
                                printk(KERN_DEBUG "timeout cnt: %d\n", timeout);
1196
#endif
1197
 
1198
                        switch (flags) {
1199
                        case FL_DTEN:           /* only STEN low */
1200
                                if (!tries--) {
1201
                                        printk(KERN_ERR
1202
                                                "optcd: read block %d failed; "
1203
                                                "Giving up\n", next_bn);
1204
                                        if (transfer_is_active) {
1205
                                                tries = 0;
1206
                                                break;
1207
                                        }
1208
                                        if (CURRENT_VALID)
1209
                                                end_request(0);
1210
                                        tries = 5;
1211
                                }
1212
                                state = S_START;
1213
                                timeout = READ_TIMEOUT;
1214
                                loop_again = 1;
1215
                        case (FL_STEN|FL_DTEN):  /* both high */
1216
                                break;
1217
                        default:        /* DTEN low */
1218
                                tries = 5;
1219
                                if (!CURRENT_VALID && buf_in == buf_out) {
1220
                                        state = S_STOP;
1221
                                        loop_again = 1;
1222
                                        break;
1223
                                }
1224
                                if (read_count<=0)
1225
                                        printk(KERN_WARNING
1226
                                                "optcd: warning - try to read"
1227
                                                " 0 frames\n");
1228
                                while (read_count) {
1229
                                        buf_bn[buf_in] = NOBUF;
1230
                                        if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {
1231
                                        /* should be no waiting here!?? */
1232
                                                printk(KERN_ERR
1233
                                                   "read_count:%d "
1234
                                                   "CURRENT->nr_sectors:%ld "
1235
                                                   "buf_in:%d\n",
1236
                                                        read_count,
1237
                                                        CURRENT->nr_sectors,
1238
                                                        buf_in);
1239
                                                printk(KERN_ERR
1240
                                                        "transfer active: %x\n",
1241
                                                        transfer_is_active);
1242
                                                read_count = 0;
1243
                                                state = S_STOP;
1244
                                                loop_again = 1;
1245
                                                end_request(0);
1246
                                                break;
1247
                                        }
1248
                                        fetch_data(buf+
1249
                                            CD_FRAMESIZE*buf_in,
1250
                                            CD_FRAMESIZE);
1251
                                        read_count--;
1252
 
1253
                                        DEBUG((DEBUG_REQUEST,
1254
                                                "S_DATA; ---I've read data- "
1255
                                                "read_count: %d",
1256
                                                read_count));
1257
                                        DEBUG((DEBUG_REQUEST,
1258
                                                "next_bn:%d  buf_in:%d "
1259
                                                "buf_out:%d  buf_bn:%d",
1260
                                                next_bn,
1261
                                                buf_in,
1262
                                                buf_out,
1263
                                                buf_bn[buf_in]));
1264
 
1265
                                        buf_bn[buf_in] = next_bn++;
1266
                                        if (buf_out == NOBUF)
1267
                                                buf_out = buf_in;
1268
                                        buf_in = buf_in + 1 ==
1269
                                                N_BUFS ? 0 : buf_in + 1;
1270
                                }
1271
                                if (!transfer_is_active) {
1272
                                        while (CURRENT_VALID) {
1273
                                                transfer();
1274
                                                if (CURRENT -> nr_sectors == 0)
1275
                                                        end_request(1);
1276
                                                else
1277
                                                        break;
1278
                                        }
1279
                                }
1280
 
1281
                                if (CURRENT_VALID
1282
                                    && (CURRENT -> sector / 4 < next_bn ||
1283
                                    CURRENT -> sector / 4 >
1284
                                     next_bn + N_BUFS)) {
1285
                                        state = S_STOP;
1286
                                        loop_again = 1;
1287
                                        break;
1288
                                }
1289
                                timeout = READ_TIMEOUT;
1290
                                if (read_count == 0) {
1291
                                        state = S_STOP;
1292
                                        loop_again = 1;
1293
                                        break;
1294
                                }
1295
                        }
1296
                        break;
1297
                case S_STOP:
1298
                        if (read_count != 0)
1299
                                printk(KERN_ERR
1300
                                        "optcd: discard data=%x frames\n",
1301
                                        read_count);
1302
                        flush_data();
1303
                        if (send_cmd(COMDRVST)) {
1304
                                state = S_IDLE;
1305
                                while (CURRENT_VALID)
1306
                                        end_request(0);
1307
                                return;
1308
                        }
1309
                        state = S_STOPPING;
1310
                        timeout = STOP_TIMEOUT;
1311
                        break;
1312
                case S_STOPPING:
1313
                        status = fetch_status();
1314
                        if (status < 0 && timeout)
1315
                                        break;
1316
                        if ((status >= 0) && (status & ST_DSK_CHG)) {
1317
                                toc_uptodate = 0;
1318
                                opt_invalidate_buffers();
1319
                        }
1320
                        if (CURRENT_VALID) {
1321
                                if (status >= 0) {
1322
                                        state = S_READ;
1323
                                        loop_again = 1;
1324
                                        skip = 1;
1325
                                        break;
1326
                                } else {
1327
                                        state = S_START;
1328
                                        timeout = 1;
1329
                                }
1330
                        } else {
1331
                                state = S_IDLE;
1332
                                return;
1333
                        }
1334
                        break;
1335
                default:
1336
                        printk(KERN_ERR "optcd: invalid state %d\n", state);
1337
                        return;
1338
                } /* case */
1339
        } /* while */
1340
 
1341
        if (!timeout--) {
1342
                printk(KERN_ERR "optcd: timeout in state %d\n", state);
1343
                state = S_STOP;
1344
                if (exec_cmd(COMSTOP) < 0) {
1345
                        state = S_IDLE;
1346
                        while (CURRENT_VALID)
1347
                                end_request(0);
1348
                        return;
1349
                }
1350
        }
1351
 
1352
        SET_REQ_TIMER(poll, HZ/100);
1353
}
1354
 
1355
 
1356
static void do_optcd_request(void)
1357
{
1358
        DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
1359
               CURRENT -> sector, CURRENT -> nr_sectors));
1360
 
1361
        if (disk_info.audio) {
1362
                printk(KERN_WARNING "optcd: tried to mount an Audio CD\n");
1363
                end_request(0);
1364
                return;
1365
        }
1366
 
1367
        transfer_is_active = 1;
1368
        while (CURRENT_VALID) {
1369
                if (CURRENT->bh) {
1370
                        if (!buffer_locked(CURRENT->bh))
1371
                                panic(DEVICE_NAME ": block not locked");
1372
                }
1373
                transfer();     /* First try to transfer block from buffers */
1374
                if (CURRENT -> nr_sectors == 0) {
1375
                        end_request(1);
1376
                } else {        /* Want to read a block not in buffer */
1377
                        buf_out = NOBUF;
1378
                        if (state == S_IDLE) {
1379
                                /* %% Should this block the request queue?? */
1380
                                if (update_toc() < 0) {
1381
                                        while (CURRENT_VALID)
1382
                                                end_request(0);
1383
                                        break;
1384
                                }
1385
                                /* Start state machine */
1386
                                state = S_START;
1387
                                timeout = READ_TIMEOUT;
1388
                                tries = 5;
1389
                                /* %% why not start right away?? */
1390
                                SET_REQ_TIMER(poll, HZ/100);
1391
                        }
1392
                        break;
1393
                }
1394
        }
1395
        transfer_is_active = 0;
1396
 
1397
        DEBUG((DEBUG_REQUEST, "next_bn:%d  buf_in:%d buf_out:%d  buf_bn:%d",
1398
               next_bn, buf_in, buf_out, buf_bn[buf_in]));
1399
        DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1400
}
1401
 
1402
/* IOCTLs */
1403
 
1404
 
1405
static char auto_eject = 0;
1406
 
1407
static int cdrompause(void)
1408
{
1409
        int status;
1410
 
1411
        if (audio_status != CDROM_AUDIO_PLAY)
1412
                return -EINVAL;
1413
 
1414
        status = exec_cmd(COMPAUSEON);
1415
        if (status < 0) {
1416
                DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1417
                return -EIO;
1418
        }
1419
        audio_status = CDROM_AUDIO_PAUSED;
1420
        return 0;
1421
}
1422
 
1423
 
1424
static int cdromresume(void)
1425
{
1426
        int status;
1427
 
1428
        if (audio_status != CDROM_AUDIO_PAUSED)
1429
                return -EINVAL;
1430
 
1431
        status = exec_cmd(COMPAUSEOFF);
1432
        if (status < 0) {
1433
                DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1434
                audio_status = CDROM_AUDIO_ERROR;
1435
                return -EIO;
1436
        }
1437
        audio_status = CDROM_AUDIO_PLAY;
1438
        return 0;
1439
}
1440
 
1441
 
1442
static int cdromplaymsf(unsigned long arg)
1443
{
1444
        int status;
1445
        struct cdrom_msf msf;
1446
 
1447
        status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1448
        if (status)
1449
                return status;
1450
        memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1451
 
1452
        bin2bcd(&msf);
1453
        status = exec_long_cmd(COMPLAY, &msf);
1454
        if (status < 0) {
1455
                DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1456
                audio_status = CDROM_AUDIO_ERROR;
1457
                return -EIO;
1458
        }
1459
 
1460
        audio_status = CDROM_AUDIO_PLAY;
1461
        return 0;
1462
}
1463
 
1464
 
1465
static int cdromplaytrkind(unsigned long arg)
1466
{
1467
        int status;
1468
        struct cdrom_ti ti;
1469
        struct cdrom_msf msf;
1470
 
1471
        status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
1472
        if (status)
1473
                return status;
1474
        memcpy_fromfs(&ti, (void *) arg, sizeof ti);
1475
 
1476
        if (ti.cdti_trk0 < disk_info.first
1477
            || ti.cdti_trk0 > disk_info.last
1478
            || ti.cdti_trk1 < ti.cdti_trk0)
1479
                return -EINVAL;
1480
        if (ti.cdti_trk1 > disk_info.last)
1481
                ti.cdti_trk1 = disk_info.last;
1482
 
1483
        msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1484
        msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1485
        msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1486
        msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1487
        msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1488
        msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1489
 
1490
        DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1491
                msf.cdmsf_min0,
1492
                msf.cdmsf_sec0,
1493
                msf.cdmsf_frame0,
1494
                msf.cdmsf_min1,
1495
                msf.cdmsf_sec1,
1496
                msf.cdmsf_frame1));
1497
 
1498
        bin2bcd(&msf);
1499
        status = exec_long_cmd(COMPLAY, &msf);
1500
        if (status < 0) {
1501
                DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1502
                audio_status = CDROM_AUDIO_ERROR;
1503
                return -EIO;
1504
        }
1505
 
1506
        audio_status = CDROM_AUDIO_PLAY;
1507
        return 0;
1508
}
1509
 
1510
 
1511
static int cdromreadtochdr(unsigned long arg)
1512
{
1513
        int status;
1514
        struct cdrom_tochdr tochdr;
1515
 
1516
        status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
1517
        if (status)
1518
                return status;
1519
 
1520
        tochdr.cdth_trk0 = disk_info.first;
1521
        tochdr.cdth_trk1 = disk_info.last;
1522
 
1523
        memcpy_tofs((void *) arg, &tochdr, sizeof tochdr);
1524
        return 0;
1525
}
1526
 
1527
 
1528
static int cdromreadtocentry(unsigned long arg)
1529
{
1530
        int status;
1531
        struct cdrom_tocentry entry;
1532
        struct cdrom_subchnl *tocptr;
1533
 
1534
        status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
1535
        if (status)
1536
                return status;
1537
        memcpy_fromfs(&entry, (void *) arg, sizeof entry);
1538
 
1539
        if (entry.cdte_track == CDROM_LEADOUT)
1540
                tocptr = &toc[disk_info.last + 1];
1541
        else if (entry.cdte_track > disk_info.last
1542
                || entry.cdte_track < disk_info.first)
1543
                return -EINVAL;
1544
        else
1545
                tocptr = &toc[entry.cdte_track];
1546
 
1547
        entry.cdte_adr = tocptr->cdsc_adr;
1548
        entry.cdte_ctrl = tocptr->cdsc_ctrl;
1549
        entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1550
        entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1551
        entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1552
        /* %% What should go into entry.cdte_datamode? */
1553
 
1554
        if (entry.cdte_format == CDROM_LBA)
1555
                msf2lba(&entry.cdte_addr);
1556
        else if (entry.cdte_format != CDROM_MSF)
1557
                return -EINVAL;
1558
 
1559
        memcpy_tofs((void *) arg, &entry, sizeof entry);
1560
        return 0;
1561
}
1562
 
1563
 
1564
static int cdromvolctrl(unsigned long arg)
1565
{
1566
        int status;
1567
        struct cdrom_volctrl volctrl;
1568
        struct cdrom_msf msf;
1569
 
1570
        status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
1571
        if (status)
1572
                return status;
1573
        memcpy_fromfs(&volctrl, (char *) arg, sizeof volctrl);
1574
 
1575
        msf.cdmsf_min0 = 0x10;
1576
        msf.cdmsf_sec0 = 0x32;
1577
        msf.cdmsf_frame0 = volctrl.channel0;
1578
        msf.cdmsf_min1 = volctrl.channel1;
1579
        msf.cdmsf_sec1 = volctrl.channel2;
1580
        msf.cdmsf_frame1 = volctrl.channel3;
1581
 
1582
        status = exec_long_cmd(COMCHCTRL, &msf);
1583
        if (status < 0) {
1584
                DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1585
                return -EIO;
1586
        }
1587
        return 0;
1588
}
1589
 
1590
 
1591
static int cdromsubchnl(unsigned long arg)
1592
{
1593
        int status;
1594
        struct cdrom_subchnl subchnl;
1595
 
1596
        status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
1597
        if (status)
1598
                return status;
1599
        memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
1600
 
1601
        if (subchnl.cdsc_format != CDROM_LBA
1602
            && subchnl.cdsc_format != CDROM_MSF)
1603
                return -EINVAL;
1604
 
1605
        status = get_q_channel(&subchnl);
1606
        if (status < 0) {
1607
                DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1608
                return -EIO;
1609
        }
1610
 
1611
        memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
1612
        return 0;
1613
}
1614
 
1615
 
1616
static int cdromread(unsigned long arg, int blocksize, int cmd)
1617
{
1618
        int status;
1619
        struct cdrom_msf msf;
1620
        char buf[CD_FRAMESIZE_RAWER];
1621
 
1622
        status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
1623
        if (status)
1624
                return status;
1625
        memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1626
 
1627
        bin2bcd(&msf);
1628
        msf.cdmsf_min1 = 0;
1629
        msf.cdmsf_sec1 = 0;
1630
        msf.cdmsf_frame1 = 1;   /* read only one frame */
1631
        status = exec_read_cmd(cmd, &msf);
1632
 
1633
        DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1634
 
1635
        if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1636
                return -EIO;
1637
        fetch_data(buf, blocksize);
1638
 
1639
        memcpy_tofs((void *) arg, &buf, blocksize);
1640
        return 0;
1641
}
1642
 
1643
 
1644
static int cdromseek(unsigned long arg)
1645
{
1646
        int status;
1647
        struct cdrom_msf msf;
1648
 
1649
        status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1650
        if (status)
1651
                return status;
1652
        memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1653
 
1654
        bin2bcd(&msf);
1655
        status = exec_seek_cmd(COMSEEK, &msf);
1656
 
1657
        DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1658
 
1659
        if (status < 0)
1660
                return -EIO;
1661
        return 0;
1662
}
1663
 
1664
 
1665
#ifdef MULTISESSION
1666
static int cdrommultisession(unsigned long arg)
1667
{
1668
        int status;
1669
        struct cdrom_multisession ms;
1670
 
1671
        status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);
1672
        if (status)
1673
                return status;
1674
        memcpy_fromfs(&ms, (void*) arg, sizeof ms);
1675
 
1676
        ms.addr.msf.minute = disk_info.last_session.minute;
1677
        ms.addr.msf.second = disk_info.last_session.second;
1678
        ms.addr.msf.frame = disk_info.last_session.frame;
1679
 
1680
        if (ms.addr_format != CDROM_LBA
1681
           && ms.addr_format != CDROM_MSF)
1682
                return -EINVAL;
1683
        if (ms.addr_format == CDROM_LBA)
1684
                msf2lba(&ms.addr);
1685
 
1686
        ms.xa_flag = disk_info.xa;
1687
 
1688
        memcpy_tofs((void*) arg, &ms,
1689
                sizeof(struct cdrom_multisession));
1690
 
1691
#if DEBUG_MULTIS
1692
        if (ms.addr_format == CDROM_MSF)
1693
                printk(KERN_DEBUG
1694
                        "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1695
                        ms.xa_flag,
1696
                        ms.addr.msf.minute,
1697
                        ms.addr.msf.second,
1698
                        ms.addr.msf.frame);
1699
        else
1700
                printk(KERN_DEBUG
1701
                    "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
/* VFS calls */
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
        /* is do_optcd_request or another ioctl busy? */
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) {  /* Actions that can be taken with door open */
1762
                case CDROMCLOSETRAY:
1763
                        /* We do this before trying to read the toc. */
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;  /* This is a no-op */
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
        /* The drive detects the mode and automatically delivers the
1824
           correct 2048 bytes, so we don't need these IOCTLs */
1825
        case CDROMREADMODE2:    retval = -EINVAL; break;
1826
        case CDROMREADMODE1:    retval = -EINVAL; break;
1827
 
1828
        /* Drive doesn't support reading audio */
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; /* not implemented */
1839
        case CDROMVOLREAD:      retval = -EINVAL; break; /* not implemented */
1840
 
1841
        case CDROMREADRAW:
1842
                        /* this drive delivers 2340 bytes in raw mode */
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; /* not implemented */
1854
        case CDROMCLOSETRAY:    break;  /* The action was taken earlier */
1855
        default:                retval = -EINVAL;
1856
        }
1857
        in_vfs = 0;
1858
        return retval;
1859
}
1860
 
1861
 
1862
static int open_count = 0;
1863
 
1864
/* Open device special file; check that a disk is in. */
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);    /* close door */
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(KERN_INFO "optcd: no disk or door open\n");
1888
                        return -EIO;
1889
                }
1890
                status = exec_cmd(COMLOCK);             /* Lock door */
1891
                if (status < 0) {
1892
                        DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1893
                }
1894
                status = update_toc();  /* Read table of contents */
1895
                if (status < 0)  {
1896
                        DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1897
                        status = exec_cmd(COMUNLOCK);   /* Unlock door */
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
/* Release device special file; flush all blocks from the buffer cache */
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);   /* Unlock door */
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
/* Check if disk has been changed */
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
/* Driver initialisation */
1957
 
1958
 
1959
/* Returns 1 if a drive is detected with a version string
1960
   starting with "DOLPHIN". Otherwise 0. */
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(KERN_INFO "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,                   /* lseek - default */
2000
        block_read,             /* read - general block-dev read */
2001
        block_write,            /* write - general block-dev write */
2002
        NULL,                   /* readdir - bad */
2003
        NULL,                   /* select */
2004
        opt_ioctl,              /* ioctl */
2005
        NULL,                   /* mmap */
2006
        opt_open,               /* open */
2007
        opt_release,            /* release */
2008
        NULL,                   /* fsync */
2009
        NULL,                   /* fasync */
2010
        opt_media_change,       /* media change */
2011
        NULL                    /* revalidate */
2012
};
2013
 
2014
 
2015
/* Get kernel parameter when used as a kernel driver */
2016
void optcd_setup(char *str, int *ints)
2017
{
2018
        if (ints[0] > 0)
2019
                optcd_port = ints[1];
2020
}
2021
 
2022
/* Test for presence of drive and initialize it. Called at boot time
2023
   or during module initialisation. */
2024
int optcd_init(void)
2025
{
2026
        int status;
2027
 
2028
        if (optcd_port <= 0) {
2029
                printk(KERN_INFO
2030
                        "optcd: no Optics Storage CDROM Initialization\n");
2031
                return -EIO;
2032
        }
2033
        if (check_region(optcd_port, 4)) {
2034
                printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
2035
                        optcd_port);
2036
                return -EIO;
2037
        }
2038
 
2039
        if (!reset_drive()) {
2040
                printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
2041
                return -EIO;
2042
        }
2043
        if (!version_ok()) {
2044
                printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
2045
                return -EIO;
2046
        }
2047
        status = exec_cmd(COMINITDOUBLE);
2048
        if (status < 0) {
2049
                printk(KERN_ERR "optcd: cannot init double speed mode\n");
2050
                DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2051
                return -EIO;
2052
        }
2053
        if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
2054
        {
2055
                printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);
2056
                return -EIO;
2057
        }
2058
 
2059
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
2060
        read_ahead[MAJOR_NR] = 4;
2061
        request_region(optcd_port, 4, "optcd");
2062
 
2063
        printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2064
        return 0;
2065
}
2066
 
2067
 
2068
#ifdef MODULE
2069
int init_module(void)
2070
{
2071
        return optcd_init();
2072
}
2073
 
2074
 
2075
void cleanup_module(void)
2076
{
2077
        if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2078
                printk(KERN_ERR "optcd: what's that: can't unregister\n");
2079
                return;
2080
        }
2081
        release_region(optcd_port, 4);
2082
        printk(KERN_INFO "optcd: module released.\n");
2083
}
2084
#endif MODULE

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.