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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [cdrom/] [optcd.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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