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

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [drivers/] [block/] [paride/] [pcd.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
        pcd.c   (c) 1997-8  Grant R. Guenther <grant@torque.net>
3
                            Under the terms of the GNU public license.
4
 
5
 
6
        Special 2.0.34 version
7
 
8
 
9
        This is high-level driver for parallel port ATAPI CDrom
10
        drives based on chips supported by the paride module.
11
 
12
        By default, the driver will autoprobe for a single parallel
13
        port ATAPI CDrom drive, but if their individual parameters are
14
        specified, the driver can handle up to 4 drives.
15
 
16
        The behaviour of the pcd driver can be altered by setting
17
        some parameters from the insmod command line.  The following
18
        parameters are adjustable:
19
 
20
            drive0      These four arguments can be arrays of
21
            drive1      1-6 integers as follows:
22
            drive2
23
            drive3      <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
24
 
25
                        Where,
26
 
27
                <prt>   is the base of the parallel port address for
28
                        the corresponding drive.  (required)
29
 
30
                <pro>   is the protocol number for the adapter that
31
                        supports this drive.  These numbers are
32
                        logged by 'paride' when the protocol modules
33
                        are initialised.  (0 if not given)
34
 
35
                <uni>   for those adapters that support chained
36
                        devices, this is the unit selector for the
37
                        chain of devices on the given port.  It should
38
                        be zero for devices that don't support chaining.
39
                        (0 if not given)
40
 
41
                <mod>   this can be -1 to choose the best mode, or one
42
                        of the mode numbers supported by the adapter.
43
                        (-1 if not given)
44
 
45
                <slv>   ATAPI CDroms can be jumpered to master or slave.
46
                        Set this to 0 to choose the master drive, 1 to
47
                        choose the slave, -1 (the default) to choose the
48
                        first drive found.
49
 
50
                <dly>   some parallel ports require the driver to
51
                        go more slowly.  -1 sets a default value that
52
                        should work with the chosen protocol.  Otherwise,
53
                        set this to a small integer, the larger it is
54
                        the slower the port i/o.  In some cases, setting
55
                        this to zero will speed up the device. (default -1)
56
 
57
            major       You may use this parameter to overide the
58
                        default major number (46) that this driver
59
                        will use.  Be sure to change the device
60
                        name as well.
61
 
62
            name        This parameter is a character string that
63
                        contains the name the kernel will use for this
64
                        device (in /proc output, for instance).
65
                        (default "pcd")
66
 
67
            verbose     This parameter controls the amount of logging
68
                        that the driver will do.  Set it to 0 for
69
                        normal operation, 1 to see autoprobe progress
70
                        messages, or 2 to see additional debugging
71
                        output.  (default 0)
72
 
73
            nice        This parameter controls the driver's use of
74
                        idle CPU time, at the expense of some speed.
75
 
76
        If this driver is built into the kernel, you can use kernel
77
        the following command line parameters, with the same values
78
        as the corresponding module parameters listed above:
79
 
80
            pcd.drive0
81
            pcd.drive1
82
            pcd.drive2
83
            pcd.drive3
84
            pcd.nice
85
 
86
        In addition, you can use the parameter pcd.disable to disable
87
        the driver entirely.
88
 
89
*/
90
 
91
/* Changes:
92
 
93
        1.01    GRG 1997.01.24  Added test unit ready support
94
        1.02    GRG 1998.05.06  Changes to pcd_completion, ready_wait,
95
                                and loosen interpretation of ATAPI
96
                                standard for clearing error status.
97
                                Use spinlocks. Eliminate sti().
98
        1.03    GRG 1998.06.16  Eliminated an Ugh
99
        1.04    GRG 1998.08.15  Added extra debugging, improvements to
100
                                pcd_completion, use HZ in loop timing
101
        1.05s   GRG 1998.09.24  Added jumbo support, adjust reset timeout
102
 
103
*/
104
 
105
#define PCD_VERSION     "1.05s"
106
#define PCD_MAJOR       46
107
#define PCD_NAME        "pcd"
108
#define PCD_UNITS       4
109
 
110
/* Here are things one can override from the insmod command.
111
   Most are autoprobed by paride unless set here.  Verbose is off
112
   by default.
113
 
114
*/
115
 
116
static int      verbose = 0;
117
static int      major = PCD_MAJOR;
118
static char     *name = PCD_NAME;
119
static int      nice = 0;
120
static int      disable = 0;
121
 
122
static int drive0[6] = {0,0,0,-1,-1,-1};
123
static int drive1[6] = {0,0,0,-1,-1,-1};
124
static int drive2[6] = {0,0,0,-1,-1,-1};
125
static int drive3[6] = {0,0,0,-1,-1,-1};
126
 
127
static int (*drives[4])[6] = {&drive0,&drive1,&drive2,&drive3};
128
static int pcd_drive_count;
129
 
130
#define D_PRT   0
131
#define D_PRO   1
132
#define D_UNI   2
133
#define D_MOD   3
134
#define D_SLV   4
135
#define D_DLY   5
136
 
137
#define DU              (*drives[unit])
138
 
139
/* end of parameters */
140
 
141
#include <linux/module.h>
142
#include <linux/errno.h>
143
#include <linux/fs.h>
144
#include <linux/kernel.h>
145
#include <linux/delay.h>
146
#include <linux/cdrom.h>
147
 
148
#include <asm/segment.h>
149
#include "spinlock.h"
150
 
151
#ifndef MODULE
152
 
153
#include "setup.h"
154
 
155
static STT pcd_stt[6] = {{"drive0",6,drive0},
156
                         {"drive1",6,drive1},
157
                         {"drive2",6,drive2},
158
                         {"drive3",6,drive3},
159
                         {"disable",1,&disable},
160
                         {"nice",1,&nice}};
161
 
162
void pcd_setup( char *str, int *ints)
163
 
164
{       generic_setup(pcd_stt,6,str);
165
}
166
 
167
#endif
168
 
169
#include "paride.h"
170
 
171
/* set up defines for blk.h,  why don't all drivers do it this way ? */
172
 
173
#define MAJOR_NR        major
174
#define DEVICE_NAME "PCD"
175
#define DEVICE_REQUEST do_pcd_request
176
#define DEVICE_NR(device) (MINOR(device))
177
#define DEVICE_ON(device)
178
#define DEVICE_OFF(device)
179
 
180
#include <linux/blk.h>
181
 
182
#include "pseudo.h"
183
 
184
#define PCD_RETRIES          5
185
#define PCD_TMO            800          /* timeout in jiffies */
186
#define PCD_DELAY           50          /* spin delay in uS */
187
#define PCD_READY_TMO       20          /* in seconds */
188
 
189
#define PCD_SPIN        (1000000*PCD_TMO)/(HZ*PCD_DELAY)
190
 
191
#define IDE_ERR         0x01
192
#define IDE_DRQ         0x08
193
#define IDE_READY       0x40
194
#define IDE_BUSY        0x80
195
 
196
int pcd_init(void);
197
void cleanup_module( void );
198
 
199
static int      pcd_open(struct inode *inode, struct file *file);
200
static void     do_pcd_request(void);
201
static void     do_pcd_read(void);
202
static int      pcd_ioctl(struct inode *inode,struct file *file,
203
                         unsigned int cmd, unsigned long arg);
204
 
205
static void pcd_release (struct inode *inode, struct file *file);
206
 
207
static int      pcd_detect(void);
208
static void     pcd_lock(int unit);
209
static void     pcd_unlock(int unit);
210
static void     pcd_eject(int unit);
211
static int      pcd_check_media(int unit);
212
static void     do_pcd_read_drq(void);
213
 
214
static int pcd_blocksizes[PCD_UNITS];
215
 
216
#define PCD_NAMELEN     8
217
 
218
struct pcd_unit {
219
        struct pi_adapter pia;  /* interface to paride layer */
220
        struct pi_adapter *pi;
221
        int drive;              /* master/slave */
222
        int last_sense;         /* result of last request sense */
223
        int access;             /* count of active opens */
224
        int present;            /* does this unit exist ? */
225
        char name[PCD_NAMELEN]; /* pcd0, pcd1, etc */
226
        };
227
 
228
struct pcd_unit pcd[PCD_UNITS];
229
 
230
/*  'unit' must be defined in all functions - either as a local or a param */
231
 
232
#define PCD pcd[unit]
233
#define PI PCD.pi
234
 
235
static char pcd_scratch[64];
236
static char pcd_buffer[2048];           /* raw block buffer */
237
static int pcd_bufblk = -1;             /* block in buffer, in CD units,
238
                                           -1 for nothing there. See also
239
                                           pd_unit.
240
                                         */
241
 
242
/* the variables below are used mainly in the I/O request engine, which
243
   processes only one request at a time.
244
*/
245
 
246
static int pcd_unit = -1;               /* unit of current request & bufblk */
247
static int pcd_retries;                 /* retries on current request */
248
static int pcd_busy = 0;         /* request being processed ? */
249
static int pcd_sector;                  /* address of next requested sector */
250
static int pcd_count;                   /* number of blocks still to do */
251
static char * pcd_buf;                  /* buffer for request in progress */
252
 
253
static int pcd_warned = 0;               /* Have we logged a phase warning ? */
254
 
255
/* kernel glue structures */
256
 
257
static struct file_operations pcd_fops = {
258
        NULL,                   /* lseek - default */
259
        block_read,             /* read - general block-dev read */
260
        block_write,            /* write - general block-dev write */
261
        NULL,                   /* readdir - bad */
262
        NULL,                   /* select */
263
        pcd_ioctl,              /* ioctl */
264
        NULL,                   /* mmap */
265
        pcd_open,               /* open */
266
        pcd_release,            /* release */
267
        block_fsync,            /* fsync */
268
        NULL,                   /* fasync */
269
        NULL,                   /* media change ? */
270
        NULL                    /* revalidate new media */
271
};
272
 
273
static void pcd_init_units( void )
274
 
275
{       int     unit, j;
276
 
277
        pcd_drive_count = 0;
278
        for (unit=0;unit<PCD_UNITS;unit++) {
279
                PCD.pi = & PCD.pia;
280
                PCD.access = 0;
281
                PCD.present = 0;
282
                PCD.last_sense = 0;
283
                j = 0;
284
                while ((j < PCD_NAMELEN-2) && (PCD.name[j]=name[j])) j++;
285
                PCD.name[j++] = '0' + unit;
286
                PCD.name[j] = 0;
287
                PCD.drive = DU[D_SLV];
288
                if (DU[D_PRT]) pcd_drive_count++;
289
        }
290
}
291
 
292
int pcd_init (void)     /* preliminary initialisation */
293
 
294
{       int     i;
295
 
296
        if (disable) return -1;
297
 
298
        pcd_init_units();
299
 
300
        if (pcd_detect()) return -1;
301
 
302
        if (register_blkdev(MAJOR_NR,name,&pcd_fops)) {
303
                printk("pcd: unable to get major number %d\n",MAJOR_NR);
304
                return -1;
305
        }
306
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
307
        read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
308
 
309
        for (i=0;i<PCD_UNITS;i++) pcd_blocksizes[i] = 1024;
310
        blksize_size[MAJOR_NR] = pcd_blocksizes;
311
 
312
        return 0;
313
}
314
 
315
static int pcd_open (struct inode *inode, struct file *file)
316
 
317
{       int unit = DEVICE_NR(inode->i_rdev);
318
 
319
        if  ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV;
320
 
321
        if (file->f_mode & 2) return -EROFS;  /* wants to write ? */
322
 
323
        MOD_INC_USE_COUNT;
324
 
325
        if (pcd_check_media(unit)) {
326
                MOD_DEC_USE_COUNT;
327
                return -ENXIO;
328
        }
329
 
330
        pcd_lock(unit);
331
 
332
        PCD.access++;
333
        return 0;
334
}
335
 
336
static void do_pcd_request (void)
337
 
338
{       int unit;
339
 
340
        if (pcd_busy) return;
341
        while (1) {
342
            if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
343
            INIT_REQUEST;
344
            if (CURRENT->cmd == READ) {
345
                unit = MINOR(CURRENT->rq_dev);
346
                if (unit != pcd_unit) {
347
                        pcd_bufblk = -1;
348
                        pcd_unit = unit;
349
                }
350
                pcd_sector = CURRENT->sector;
351
                pcd_count = CURRENT->nr_sectors;
352
                pcd_buf = CURRENT->buffer;
353
                pcd_busy = 1;
354
                ps_set_intr(do_pcd_read,0,0,nice);
355
                return;
356
            }
357
            else end_request(0);
358
        }
359
}
360
 
361
static int pcd_ioctl(struct inode *inode,struct file *file,
362
                    unsigned int cmd, unsigned long arg)
363
 
364
/* we currently support only the EJECT ioctl. */
365
 
366
{       int unit = DEVICE_NR(inode->i_rdev);
367
        if  ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV;
368
 
369
        switch (cmd) {
370
            case CDROMEJECT: if (PCD.access == 1) {
371
                                pcd_eject(unit);
372
                                return 0;
373
                             }
374
            default:
375
                return -EINVAL;
376
        }
377
}
378
 
379
static void pcd_release (struct inode *inode, struct file *file)
380
 
381
{       kdev_t  devp;
382
        int     unit;
383
 
384
        devp = inode->i_rdev;
385
        unit = DEVICE_NR(devp);
386
 
387
        if  ((unit >= PCD_UNITS) || (PCD.access <= 0))
388
                        return;
389
 
390
        PCD.access--;
391
 
392
        if (!PCD.access) {
393
                fsync_dev(devp);
394
 
395
                invalidate_inodes(devp);
396
 
397
                invalidate_buffers(devp);
398
                pcd_unlock(unit);
399
 
400
        }
401
 
402
        MOD_DEC_USE_COUNT;
403
 
404
}
405
 
406
#ifdef MODULE
407
 
408
/* Glue for modules ... */
409
 
410
int     init_module(void)
411
 
412
{       int     err;
413
 
414
#ifdef PARIDE_JUMBO
415
       { extern paride_init();
416
         paride_init();
417
       }
418
#endif
419
 
420
        err = pcd_init();
421
 
422
        return err;
423
}
424
 
425
void    cleanup_module(void)
426
 
427
{       int unit;
428
 
429
        unregister_blkdev(MAJOR_NR,name);
430
 
431
        for (unit=0;unit<PCD_UNITS;unit++)
432
           if (PCD.present) pi_release(PI);
433
}
434
 
435
#endif
436
 
437
#define WR(c,r,v)       pi_write_regr(PI,c,r,v)
438
#define RR(c,r)         (pi_read_regr(PI,c,r))
439
 
440
static int pcd_wait( int unit, int go, int stop, char * fun, char * msg )
441
 
442
{       int j, r, e, s, p;
443
 
444
        j = 0;
445
        while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(j++<PCD_SPIN))
446
                udelay(PCD_DELAY);
447
 
448
        if ((r&(IDE_ERR&stop))||(j>=PCD_SPIN)) {
449
           s = RR(0,7);
450
           e = RR(0,1);
451
           p = RR(0,2);
452
           if (j >= PCD_SPIN) e |= 0x100;
453
           if (fun) printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
454
                           " loop=%d phase=%d\n",
455
                            PCD.name,fun,msg,r,s,e,j,p);
456
           return (s<<8)+r;
457
        }
458
        return 0;
459
}
460
 
461
static int pcd_command( int unit, char * cmd, int dlen, char * fun )
462
 
463
{       pi_connect(PI);
464
 
465
        WR(0,6,0xa0 + 0x10*PCD.drive);
466
 
467
        if (pcd_wait(unit,IDE_BUSY|IDE_DRQ,0,fun,"before command")) {
468
                pi_disconnect(PI);
469
                return -1;
470
        }
471
 
472
        WR(0,4,dlen % 256);
473
        WR(0,5,dlen / 256);
474
        WR(0,7,0xa0);          /* ATAPI packet command */
475
 
476
        if (pcd_wait(unit,IDE_BUSY,IDE_DRQ,fun,"command DRQ")) {
477
                pi_disconnect(PI);
478
                return -1;
479
        }
480
 
481
        if (RR(0,2) != 1) {
482
           printk("%s: %s: command phase error\n",PCD.name,fun);
483
           pi_disconnect(PI);
484
           return -1;
485
        }
486
 
487
        pi_write_block(PI,cmd,12);
488
 
489
        return 0;
490
}
491
 
492
static int pcd_completion( int unit, char * buf,  char * fun )
493
 
494
{       int r, d, p, n, k, j;
495
 
496
        r = -1; k = 0; j = 0;
497
 
498
        if (!pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,
499
                                                fun,"completion")) {
500
            r = 0;
501
            while (RR(0,7)&IDE_DRQ) {
502
                d = (RR(0,4)+256*RR(0,5));
503
                n = ((d+3)&0xfffc);
504
                p = RR(0,2)&3;
505
 
506
                if ((p == 2) && (n > 0) && (j == 0)) {
507
                    pi_read_block(PI,buf,n);
508
                    if (verbose > 1)
509
                        printk("%s: %s: Read %d bytes\n",PCD.name,fun,n);
510
                    r = 0; j++;
511
                } else {
512
                    if (verbose > 1)
513
                        printk("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
514
                                        PCD.name,fun,p,d,k);
515
                    if ((verbose < 2) && !pcd_warned) {
516
                        pcd_warned = 1;
517
                        printk("%s: WARNING: ATAPI phase errors\n",PCD.name);
518
                        }
519
                    udelay(1000);
520
                }
521
                if (k++ > PCD_TMO) {
522
                        printk("%s: Stuck DRQ\n",PCD.name);
523
                        break;
524
                }
525
                if (pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,
526
                                fun,"completion")) {
527
                        r = -1;
528
                        break;
529
                }
530
            }
531
        }
532
 
533
        pi_disconnect(PI);
534
 
535
        return r;
536
}
537
 
538
static void pcd_req_sense( int unit, char *fun )
539
 
540
{       char    rs_cmd[12] = { 0x03,0,0,0,16,0,0,0,0,0,0,0 };
541
        char    buf[16];
542
        int     r;
543
 
544
        r = pcd_command(unit,rs_cmd,16,"Request sense");
545
        udelay(1000);
546
        if (!r) pcd_completion(unit,buf,"Request sense");
547
 
548
        PCD.last_sense = -1;
549
        if (!r) {
550
            if (fun) printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n",
551
                               PCD.name,fun,buf[2]&0xf,buf[12],buf[13]);
552
            PCD.last_sense = (buf[2]&0xf) | ((buf[12]&0xff)<<8)
553
                                          | ((buf[13]&0xff)<<16) ;
554
        }
555
}
556
 
557
static int pcd_atapi( int unit, char * cmd, int dlen, char * buf, char * fun )
558
 
559
{       int r;
560
 
561
        r = pcd_command(unit,cmd,dlen,fun);
562
        udelay(1000);
563
        if (!r) r = pcd_completion(unit,buf,fun);
564
        if (r) pcd_req_sense(unit,fun);
565
 
566
        return r;
567
}
568
 
569
#define DBMSG(msg)      ((verbose>1)?(msg):NULL)
570
 
571
static void pcd_lock(int unit)
572
 
573
{       char    lo_cmd[12] = { 0x1e,0,0,0,1,0,0,0,0,0,0,0 };
574
        char    cl_cmd[12] = { 0x1b,0,0,0,3,0,0,0,0,0,0,0 };
575
 
576
        pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd1"));
577
        pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd2"));
578
        pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd3"));
579
        pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd4"));
580
        pcd_atapi(unit,cl_cmd,0,pcd_scratch,"close door");
581
 
582
        pcd_atapi(unit,lo_cmd,0,pcd_scratch,DBMSG("ld"));
583
        pcd_atapi(unit,lo_cmd,0,pcd_scratch,"lock door");
584
}
585
 
586
static void pcd_unlock( int unit )
587
 
588
{       char    un_cmd[12] = { 0x1e,0,0,0,0,0,0,0,0,0,0,0 };
589
 
590
        pcd_atapi(unit,un_cmd,0,pcd_scratch,"unlock door");
591
}
592
 
593
static void pcd_eject( int unit)
594
 
595
{       char    ej_cmd[12] = { 0x1b,0,0,0,2,0,0,0,0,0,0,0 };
596
 
597
        pcd_unlock(unit);
598
        pcd_atapi(unit,ej_cmd,0,pcd_scratch,"eject");
599
}
600
 
601
#define PCD_RESET_TMO   100             /* in tenths of a second */
602
 
603
static void pcd_sleep( int cs )
604
 
605
{       current->state = TASK_INTERRUPTIBLE;
606
        current->timeout = jiffies + cs;
607
        schedule();
608
}
609
 
610
static int pcd_reset( int unit )
611
 
612
/* the ATAPI standard actually specifies the contents of all 7 registers
613
   after a reset, but the specification is ambiguous concerning the last
614
   two bytes, and different drives interpret the standard differently.
615
*/
616
 
617
{       int     i, k, flg;
618
        int     expect[5] = {1,1,1,0x14,0xeb};
619
 
620
        pi_connect(PI);
621
        WR(0,6,0xa0 + 0x10*PCD.drive);
622
        WR(0,7,8);
623
 
624
        pcd_sleep(2);           /* delay a bit*/
625
 
626
        k = 0;
627
        while ((k++ < PCD_RESET_TMO) && (RR(1,6)&IDE_BUSY))
628
                pcd_sleep(10);
629
 
630
        flg = 1;
631
        for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
632
 
633
        if (verbose) {
634
                printk("%s: Reset (%d) signature = ",PCD.name,k);
635
                for (i=0;i<5;i++) printk("%3x",RR(0,i+1));
636
                if (!flg) printk(" (incorrect)");
637
                printk("\n");
638
        }
639
 
640
        pi_disconnect(PI);
641
        return flg-1;
642
}
643
 
644
static int pcd_ready_wait( int unit, int tmo )
645
 
646
{       char    tr_cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
647
        int     k, p;
648
 
649
        k = 0;
650
        while (k < tmo) {
651
          PCD.last_sense = 0;
652
          pcd_atapi(unit,tr_cmd,0,NULL,DBMSG("test unit ready"));
653
          p = PCD.last_sense;
654
          if (!p) return 0;
655
          if (!(((p & 0xffff) == 0x0402)||((p & 0xff) == 6))) return p;
656
          k++;
657
          pcd_sleep(100);
658
        }
659
        return 0x000020;        /* timeout */
660
}
661
 
662
static int pcd_check_media( int unit )
663
 
664
{       char    rc_cmd[12] = { 0x25,0,0,0,0,0,0,0,0,0,0,0};
665
 
666
        pcd_ready_wait(unit,PCD_READY_TMO);
667
        return (pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("check media")));
668
}
669
 
670
static int pcd_identify( int unit, char * id )
671
 
672
{       int k, s;
673
        char   id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0};
674
 
675
        pcd_bufblk = -1;
676
 
677
        s = pcd_atapi(unit,id_cmd,36,pcd_buffer,"identify");
678
 
679
        if (s) return -1;
680
        if ((pcd_buffer[0] & 0x1f) != 5) {
681
          if (verbose) printk("%s: %s is not a CDrom\n",
682
                        PCD.name,PCD.drive?"Slave":"Master");
683
          return -1;
684
        }
685
        for (k=0;k<16;k++) id[k] = pcd_buffer[16+k]; id[16] = 0;
686
        k = 16; while ((k >= 0) && (id[k] <= 0x20)) { id[k] = 0; k--; }
687
 
688
        printk("%s: %s: %s\n",PCD.name,PCD.drive?"Slave":"Master",id);
689
 
690
        return 0;
691
}
692
 
693
static int pcd_probe( int unit, int ms, char * id )
694
 
695
/*      returns  0, with id set if drive is detected
696
                -1, if drive detection failed
697
*/
698
 
699
{       if (ms == -1) {
700
            for (PCD.drive=0;PCD.drive<=1;PCD.drive++)
701
               if (!pcd_reset(unit) && !pcd_identify(unit,id))
702
                  return 0;
703
        } else {
704
            PCD.drive = ms;
705
            if (!pcd_reset(unit) && !pcd_identify(unit,id))
706
                return 0;
707
        }
708
        return -1;
709
}
710
 
711
static int pcd_detect( void )
712
 
713
{       char    id[18];
714
        int     k, unit;
715
 
716
        printk("%s: %s version %s, major %d, nice %d\n",
717
                name,name,PCD_VERSION,major,nice);
718
 
719
        k = 0;
720
        if (pcd_drive_count == 0) {  /* nothing spec'd - so autoprobe for 1 */
721
            unit = 0;
722
            if (pi_init(PI,1,-1,-1,-1,-1,-1,pcd_buffer,
723
                     PI_PCD,verbose,PCD.name)) {
724
                if (!pcd_probe(unit,-1,id)) {
725
                        PCD.present = 1;
726
                        k++;
727
                } else pi_release(PI);
728
            }
729
 
730
        } else for (unit=0;unit<PCD_UNITS;unit++) if (DU[D_PRT])
731
            if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
732
                        DU[D_PRO],DU[D_DLY],pcd_buffer,PI_PCD,verbose,
733
                        PCD.name)) {
734
                if (!pcd_probe(unit,DU[D_SLV],id)) {
735
                        PCD.present = 1;
736
                        k++;
737
                } else pi_release(PI);
738
            }
739
 
740
        if (k) return 0;
741
 
742
        printk("%s: No CDrom drive found\n",name);
743
        return -1;
744
}
745
 
746
/* I/O request processing */
747
 
748
static int pcd_ready( void )
749
 
750
{       int     unit = pcd_unit;
751
 
752
        return (((RR(1,6)&(IDE_BUSY|IDE_DRQ))==IDE_DRQ)) ;
753
}
754
 
755
static void pcd_transfer( void )
756
 
757
{       int     k, o;
758
 
759
        while (pcd_count && (pcd_sector/4 == pcd_bufblk)) {
760
                o = (pcd_sector % 4) * 512;
761
                for(k=0;k<512;k++) pcd_buf[k] = pcd_buffer[o+k];
762
                pcd_count--;
763
                pcd_buf += 512;
764
                pcd_sector++;
765
        }
766
}
767
 
768
static void pcd_start( void )
769
 
770
{       int     unit = pcd_unit;
771
        int     b, i;
772
        char    rd_cmd[12] = {0xa8,0,0,0,0,0,0,0,0,1,0,0};
773
        long    saved_flags;
774
 
775
        pcd_bufblk = pcd_sector / 4;
776
        b = pcd_bufblk;
777
        for(i=0;i<4;i++) {
778
           rd_cmd[5-i] = b & 0xff;
779
           b = b >> 8;
780
        }
781
 
782
        if (pcd_command(unit,rd_cmd,2048,"read block")) {
783
                pcd_bufblk = -1;
784
                spin_lock_irqsave(&io_request_lock,saved_flags);
785
                pcd_busy = 0;
786
                end_request(0);
787
                do_pcd_request();
788
                spin_unlock_irqrestore(&io_request_lock,saved_flags);
789
                return;
790
        }
791
 
792
        udelay(1000);
793
 
794
        ps_set_intr(do_pcd_read_drq,pcd_ready,PCD_TMO,nice);
795
 
796
}
797
 
798
static void do_pcd_read( void )
799
 
800
 
801
{       int     unit = pcd_unit;
802
        long    saved_flags;
803
 
804
        pcd_busy = 1;
805
        pcd_retries = 0;
806
        pcd_transfer();
807
        if (!pcd_count) {
808
                spin_lock_irqsave(&io_request_lock,saved_flags);
809
                end_request(1);
810
                pcd_busy = 0;
811
                do_pcd_request();
812
                spin_unlock_irqrestore(&io_request_lock,saved_flags);
813
                return;
814
        }
815
 
816
        pi_do_claimed(PI,pcd_start);
817
}
818
 
819
static void do_pcd_read_drq( void )
820
 
821
{       int     unit = pcd_unit;
822
        long    saved_flags;
823
 
824
        if (pcd_completion(unit,pcd_buffer,"read block")) {
825
                if (pcd_retries < PCD_RETRIES) {
826
                        udelay(1000);
827
                        pcd_retries++;
828
                        pi_do_claimed(PI,pcd_start);
829
                        return;
830
                        }
831
                spin_lock_irqsave(&io_request_lock,saved_flags);
832
                pcd_busy = 0;
833
                pcd_bufblk = -1;
834
                end_request(0);
835
                do_pcd_request();
836
                spin_unlock_irqrestore(&io_request_lock,saved_flags);
837
                return;
838
        }
839
 
840
        do_pcd_read();
841
        spin_lock_irqsave(&io_request_lock,saved_flags);
842
        do_pcd_request();
843
        spin_unlock_irqrestore(&io_request_lock,saved_flags);
844
}
845
 
846
/* end of pcd.c */
847
 

powered by: WebSVN 2.1.0

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