linux/drivers/block/paride/pcd.c History
<<
>>
Prefs
   1/* 
   2        pcd.c   (c) 1997-8  Grant R. Guenther <grant@torque.net>
   3                            Under the terms of the GNU General Public License.
   4
   5        This is a high-level driver for parallel port ATAPI CD-ROM
   6        drives based on chips supported by the paride module.
   7
   8        By default, the driver will autoprobe for a single parallel
   9        port ATAPI CD-ROM drive, but if their individual parameters are
  10        specified, the driver can handle up to 4 drives.
  11
  12        The behaviour of the pcd driver can be altered by setting
  13        some parameters from the insmod command line.  The following
  14        parameters are adjustable:
  15
  16            drive0      These four arguments can be arrays of       
  17            drive1      1-6 integers as follows:
  18            drive2
  19            drive3      <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
  20
  21                        Where,
  22
  23                <prt>   is the base of the parallel port address for
  24                        the corresponding drive.  (required)
  25
  26                <pro>   is the protocol number for the adapter that
  27                        supports this drive.  These numbers are
  28                        logged by 'paride' when the protocol modules
  29                        are initialised.  (0 if not given)
  30
  31                <uni>   for those adapters that support chained
  32                        devices, this is the unit selector for the
  33                        chain of devices on the given port.  It should
  34                        be zero for devices that don't support chaining.
  35                        (0 if not given)
  36
  37                <mod>   this can be -1 to choose the best mode, or one
  38                        of the mode numbers supported by the adapter.
  39                        (-1 if not given)
  40
  41                <slv>   ATAPI CD-ROMs can be jumpered to master or slave.
  42                        Set this to 0 to choose the master drive, 1 to
  43                        choose the slave, -1 (the default) to choose the
  44                        first drive found.
  45
  46                <dly>   some parallel ports require the driver to 
  47                        go more slowly.  -1 sets a default value that
  48                        should work with the chosen protocol.  Otherwise,
  49                        set this to a small integer, the larger it is
  50                        the slower the port i/o.  In some cases, setting
  51                        this to zero will speed up the device. (default -1)
  52                        
  53            major       You may use this parameter to overide the
  54                        default major number (46) that this driver
  55                        will use.  Be sure to change the device
  56                        name as well.
  57
  58            name        This parameter is a character string that
  59                        contains the name the kernel will use for this
  60                        device (in /proc output, for instance).
  61                        (default "pcd")
  62
  63            verbose     This parameter controls the amount of logging
  64                        that the driver will do.  Set it to 0 for
  65                        normal operation, 1 to see autoprobe progress
  66                        messages, or 2 to see additional debugging
  67                        output.  (default 0)
  68  
  69            nice        This parameter controls the driver's use of
  70                        idle CPU time, at the expense of some speed.
  71 
  72        If this driver is built into the kernel, you can use kernel
  73        the following command line parameters, with the same values
  74        as the corresponding module parameters listed above:
  75
  76            pcd.drive0
  77            pcd.drive1
  78            pcd.drive2
  79            pcd.drive3
  80            pcd.nice
  81
  82        In addition, you can use the parameter pcd.disable to disable
  83        the driver entirely.
  84
  85*/
  86
  87/* Changes:
  88
  89        1.01    GRG 1998.01.24  Added test unit ready support
  90        1.02    GRG 1998.05.06  Changes to pcd_completion, ready_wait,
  91                                and loosen interpretation of ATAPI
  92                                standard for clearing error status.
  93                                Use spinlocks. Eliminate sti().
  94        1.03    GRG 1998.06.16  Eliminated an Ugh
  95        1.04    GRG 1998.08.15  Added extra debugging, improvements to
  96                                pcd_completion, use HZ in loop timing
  97        1.05    GRG 1998.08.16  Conformed to "Uniform CD-ROM" standard
  98        1.06    GRG 1998.08.19  Added audio ioctl support
  99        1.07    GRG 1998.09.24  Increased reset timeout, added jumbo support
 100
 101*/
 102
 103#define PCD_VERSION     "1.07"
 104#define PCD_MAJOR       46
 105#define PCD_NAME        "pcd"
 106#define PCD_UNITS       4
 107
 108/* Here are things one can override from the insmod command.
 109   Most are autoprobed by paride unless set here.  Verbose is off
 110   by default.
 111
 112*/
 113
 114static int verbose = 0;
 115static int major = PCD_MAJOR;
 116static char *name = PCD_NAME;
 117static int nice = 0;
 118static int disable = 0;
 119
 120static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
 121static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
 122static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
 123static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
 124
 125static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
 126static int pcd_drive_count;
 127
 128enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
 129
 130/* end of parameters */
 131
 132#include <linux/module.h>
 133#include <linux/init.h>
 134#include <linux/errno.h>
 135#include <linux/fs.h>
 136#include <linux/kernel.h>
 137#include <linux/delay.h>
 138#include <linux/cdrom.h>
 139#include <linux/spinlock.h>
 140#include <linux/blkdev.h>
 141#include <asm/uaccess.h>
 142
 143static DEFINE_SPINLOCK(pcd_lock);
 144
 145module_param(verbose, bool, 0644);
 146module_param(major, int, 0);
 147module_param(name, charp, 0);
 148module_param(nice, int, 0);
 149module_param_array(drive0, int, NULL, 0);
 150module_param_array(drive1, int, NULL, 0);
 151module_param_array(drive2, int, NULL, 0);
 152module_param_array(drive3, int, NULL, 0);
 153
 154#include "paride.h"
 155#include "pseudo.h"
 156
 157#define PCD_RETRIES          5
 158#define PCD_TMO            800  /* timeout in jiffies */
 159#define PCD_DELAY           50  /* spin delay in uS */
 160#define PCD_READY_TMO       20  /* in seconds */
 161#define PCD_RESET_TMO      100  /* in tenths of a second */
 162
 163#define PCD_SPIN        (1000000*PCD_TMO)/(HZ*PCD_DELAY)
 164
 165#define IDE_ERR         0x01
 166#define IDE_DRQ         0x08
 167#define IDE_READY       0x40
 168#define IDE_BUSY        0x80
 169
 170static int pcd_open(struct cdrom_device_info *cdi, int purpose);
 171static void pcd_release(struct cdrom_device_info *cdi);
 172static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
 173static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr);
 174static int pcd_tray_move(struct cdrom_device_info *cdi, int position);
 175static int pcd_lock_door(struct cdrom_device_info *cdi, int lock);
 176static int pcd_drive_reset(struct cdrom_device_info *cdi);
 177static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn);
 178static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
 179                           unsigned int cmd, void *arg);
 180static int pcd_packet(struct cdrom_device_info *cdi,
 181                      struct packet_command *cgc);
 182
 183static int pcd_detect(void);
 184static void pcd_probe_capabilities(void);
 185static void do_pcd_read_drq(void);
 186static void do_pcd_request(struct request_queue * q);
 187static void do_pcd_read(void);
 188
 189struct pcd_unit {
 190        struct pi_adapter pia;  /* interface to paride layer */
 191        struct pi_adapter *pi;
 192        int drive;              /* master/slave */
 193        int last_sense;         /* result of last request sense */
 194        int changed;            /* media change seen */
 195        int present;            /* does this unit exist ? */
 196        char *name;             /* pcd0, pcd1, etc */
 197        struct cdrom_device_info info;  /* uniform cdrom interface */
 198        struct gendisk *disk;
 199};
 200
 201static struct pcd_unit pcd[PCD_UNITS];
 202
 203static char pcd_scratch[64];
 204static char pcd_buffer[2048];   /* raw block buffer */
 205static int pcd_bufblk = -1;     /* block in buffer, in CD units,
 206                                   -1 for nothing there. See also
 207                                   pd_unit.
 208                                 */
 209
 210/* the variables below are used mainly in the I/O request engine, which
 211   processes only one request at a time.
 212*/
 213
 214static struct pcd_unit *pcd_current; /* current request's drive */
 215static struct request *pcd_req;
 216static int pcd_retries;         /* retries on current request */
 217static int pcd_busy;            /* request being processed ? */
 218static int pcd_sector;          /* address of next requested sector */
 219static int pcd_count;           /* number of blocks still to do */
 220static char *pcd_buf;           /* buffer for request in progress */
 221
 222static int pcd_warned;          /* Have we logged a phase warning ? */
 223
 224/* kernel glue structures */
 225
 226static int pcd_block_open(struct block_device *bdev, fmode_t mode)
 227{
 228        struct pcd_unit *cd = bdev->bd_disk->private_data;
 229        return cdrom_open(&cd->info, bdev, mode);
 230}
 231
 232static int pcd_block_release(struct gendisk *disk, fmode_t mode)
 233{
 234        struct pcd_unit *cd = disk->private_data;
 235        cdrom_release(&cd->info, mode);
 236        return 0;
 237}
 238
 239static int pcd_block_ioctl(struct block_device *bdev, fmode_t mode,
 240                                unsigned cmd, unsigned long arg)
 241{
 242        struct pcd_unit *cd = bdev->bd_disk->private_data;
 243        return cdrom_ioctl(&cd->info, bdev, mode, cmd, arg);
 244}
 245
 246static int pcd_block_media_changed(struct gendisk *disk)
 247{
 248        struct pcd_unit *cd = disk->private_data;
 249        return cdrom_media_changed(&cd->info);
 250}
 251
 252static struct block_device_operations pcd_bdops = {
 253        .owner          = THIS_MODULE,
 254        .open           = pcd_block_open,
 255        .release        = pcd_block_release,
 256        .locked_ioctl   = pcd_block_ioctl,
 257        .media_changed  = pcd_block_media_changed,
 258};
 259
 260static struct cdrom_device_ops pcd_dops = {
 261        .open           = pcd_open,
 262        .release        = pcd_release,
 263        .drive_status   = pcd_drive_status,
 264        .media_changed  = pcd_media_changed,
 265        .tray_move      = pcd_tray_move,
 266        .lock_door      = pcd_lock_door,
 267        .get_mcn        = pcd_get_mcn,
 268        .reset          = pcd_drive_reset,
 269        .audio_ioctl    = pcd_audio_ioctl,
 270        .generic_packet = pcd_packet,
 271        .capability     = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
 272                          CDC_MCN | CDC_MEDIA_CHANGED | CDC_RESET |
 273                          CDC_PLAY_AUDIO | CDC_GENERIC_PACKET | CDC_CD_R |
 274                          CDC_CD_RW,
 275};
 276
 277static void pcd_init_units(void)
 278{
 279        struct pcd_unit *cd;
 280        int unit;
 281
 282        pcd_drive_count = 0;
 283        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 284                struct gendisk *disk = alloc_disk(1);
 285                if (!disk)
 286                        continue;
 287                cd->disk = disk;
 288                cd->pi = &cd->pia;
 289                cd->present = 0;
 290                cd->last_sense = 0;
 291                cd->changed = 1;
 292                cd->drive = (*drives[unit])[D_SLV];
 293                if ((*drives[unit])[D_PRT])
 294                        pcd_drive_count++;
 295
 296                cd->name = &cd->info.name[0];
 297                snprintf(cd->name, sizeof(cd->info.name), "%s%d", name, unit);
 298                cd->info.ops = &pcd_dops;
 299                cd->info.handle = cd;
 300                cd->info.speed = 0;
 301                cd->info.capacity = 1;
 302                cd->info.mask = 0;
 303                disk->major = major;
 304                disk->first_minor = unit;
 305                strcpy(disk->disk_name, cd->name);      /* umm... */
 306                disk->fops = &pcd_bdops;
 307        }
 308}
 309
 310static int pcd_open(struct cdrom_device_info *cdi, int purpose)
 311{
 312        struct pcd_unit *cd = cdi->handle;
 313        if (!cd->present)
 314                return -ENODEV;
 315        return 0;
 316}
 317
 318static void pcd_release(struct cdrom_device_info *cdi)
 319{
 320}
 321
 322static inline int status_reg(struct pcd_unit *cd)
 323{
 324        return pi_read_regr(cd->pi, 1, 6);
 325}
 326
 327static inline int read_reg(struct pcd_unit *cd, int reg)
 328{
 329        return pi_read_regr(cd->pi, 0, reg);
 330}
 331
 332static inline void write_reg(struct pcd_unit *cd, int reg, int val)
 333{
 334        pi_write_regr(cd->pi, 0, reg, val);
 335}
 336
 337static int pcd_wait(struct pcd_unit *cd, int go, int stop, char *fun, char *msg)
 338{
 339        int j, r, e, s, p;
 340
 341        j = 0;
 342        while ((((r = status_reg(cd)) & go) || (stop && (!(r & stop))))
 343               && (j++ < PCD_SPIN))
 344                udelay(PCD_DELAY);
 345
 346        if ((r & (IDE_ERR & stop)) || (j >= PCD_SPIN)) {
 347                s = read_reg(cd, 7);
 348                e = read_reg(cd, 1);
 349                p = read_reg(cd, 2);
 350                if (j >= PCD_SPIN)
 351                        e |= 0x100;
 352                if (fun)
 353                        printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
 354                               " loop=%d phase=%d\n",
 355                               cd->name, fun, msg, r, s, e, j, p);
 356                return (s << 8) + r;
 357        }
 358        return 0;
 359}
 360
 361static int pcd_command(struct pcd_unit *cd, char *cmd, int dlen, char *fun)
 362{
 363        pi_connect(cd->pi);
 364
 365        write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
 366
 367        if (pcd_wait(cd, IDE_BUSY | IDE_DRQ, 0, fun, "before command")) {
 368                pi_disconnect(cd->pi);
 369                return -1;
 370        }
 371
 372        write_reg(cd, 4, dlen % 256);
 373        write_reg(cd, 5, dlen / 256);
 374        write_reg(cd, 7, 0xa0); /* ATAPI packet command */
 375
 376        if (pcd_wait(cd, IDE_BUSY, IDE_DRQ, fun, "command DRQ")) {
 377                pi_disconnect(cd->pi);
 378                return -1;
 379        }
 380
 381        if (read_reg(cd, 2) != 1) {
 382                printk("%s: %s: command phase error\n", cd->name, fun);
 383                pi_disconnect(cd->pi);
 384                return -1;
 385        }
 386
 387        pi_write_block(cd->pi, cmd, 12);
 388
 389        return 0;
 390}
 391
 392static int pcd_completion(struct pcd_unit *cd, char *buf, char *fun)
 393{
 394        int r, d, p, n, k, j;
 395
 396        r = -1;
 397        k = 0;
 398        j = 0;
 399
 400        if (!pcd_wait(cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR,
 401                      fun, "completion")) {
 402                r = 0;
 403                while (read_reg(cd, 7) & IDE_DRQ) {
 404                        d = read_reg(cd, 4) + 256 * read_reg(cd, 5);
 405                        n = (d + 3) & 0xfffc;
 406                        p = read_reg(cd, 2) & 3;
 407
 408                        if ((p == 2) && (n > 0) && (j == 0)) {
 409                                pi_read_block(cd->pi, buf, n);
 410                                if (verbose > 1)
 411                                        printk("%s: %s: Read %d bytes\n",
 412                                               cd->name, fun, n);
 413                                r = 0;
 414                                j++;
 415                        } else {
 416                                if (verbose > 1)
 417                                        printk
 418                                            ("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
 419                                             cd->name, fun, p, d, k);
 420                                if ((verbose < 2) && !pcd_warned) {
 421                                        pcd_warned = 1;
 422                                        printk
 423                                            ("%s: WARNING: ATAPI phase errors\n",
 424                                             cd->name);
 425                                }
 426                                mdelay(1);
 427                        }
 428                        if (k++ > PCD_TMO) {
 429                                printk("%s: Stuck DRQ\n", cd->name);
 430                                break;
 431                        }
 432                        if (pcd_wait
 433                            (cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR, fun,
 434                             "completion")) {
 435                                r = -1;
 436                                break;
 437                        }
 438                }
 439        }
 440
 441        pi_disconnect(cd->pi);
 442
 443        return r;
 444}
 445
 446static void pcd_req_sense(struct pcd_unit *cd, char *fun)
 447{
 448        char rs_cmd[12] = { 0x03, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
 449        char buf[16];
 450        int r, c;
 451
 452        r = pcd_command(cd, rs_cmd, 16, "Request sense");
 453        mdelay(1);
 454        if (!r)
 455                pcd_completion(cd, buf, "Request sense");
 456
 457        cd->last_sense = -1;
 458        c = 2;
 459        if (!r) {
 460                if (fun)
 461                        printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n",
 462                               cd->name, fun, buf[2] & 0xf, buf[12], buf[13]);
 463                c = buf[2] & 0xf;
 464                cd->last_sense =
 465                    c | ((buf[12] & 0xff) << 8) | ((buf[13] & 0xff) << 16);
 466        }
 467        if ((c == 2) || (c == 6))
 468                cd->changed = 1;
 469}
 470
 471static int pcd_atapi(struct pcd_unit *cd, char *cmd, int dlen, char *buf, char *fun)
 472{
 473        int r;
 474
 475        r = pcd_command(cd, cmd, dlen, fun);
 476        mdelay(1);
 477        if (!r)
 478                r = pcd_completion(cd, buf, fun);
 479        if (r)
 480                pcd_req_sense(cd, fun);
 481
 482        return r;
 483}
 484
 485static int pcd_packet(struct cdrom_device_info *cdi, struct packet_command *cgc)
 486{
 487        return pcd_atapi(cdi->handle, cgc->cmd, cgc->buflen, cgc->buffer,
 488                         "generic packet");
 489}
 490
 491#define DBMSG(msg)      ((verbose>1)?(msg):NULL)
 492
 493static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr)
 494{
 495        struct pcd_unit *cd = cdi->handle;
 496        int res = cd->changed;
 497        if (res)
 498                cd->changed = 0;
 499        return res;
 500}
 501
 502static int pcd_lock_door(struct cdrom_device_info *cdi, int lock)
 503{
 504        char un_cmd[12] = { 0x1e, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0 };
 505
 506        return pcd_atapi(cdi->handle, un_cmd, 0, pcd_scratch,
 507                         lock ? "lock door" : "unlock door");
 508}
 509
 510static int pcd_tray_move(struct cdrom_device_info *cdi, int position)
 511{
 512        char ej_cmd[12] = { 0x1b, 0, 0, 0, 3 - position, 0, 0, 0, 0, 0, 0, 0 };
 513
 514        return pcd_atapi(cdi->handle, ej_cmd, 0, pcd_scratch,
 515                         position ? "eject" : "close tray");
 516}
 517
 518static void pcd_sleep(int cs)
 519{
 520        schedule_timeout_interruptible(cs);
 521}
 522
 523static int pcd_reset(struct pcd_unit *cd)
 524{
 525        int i, k, flg;
 526        int expect[5] = { 1, 1, 1, 0x14, 0xeb };
 527
 528        pi_connect(cd->pi);
 529        write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
 530        write_reg(cd, 7, 8);
 531
 532        pcd_sleep(20 * HZ / 1000);      /* delay a bit */
 533
 534        k = 0;
 535        while ((k++ < PCD_RESET_TMO) && (status_reg(cd) & IDE_BUSY))
 536                pcd_sleep(HZ / 10);
 537
 538        flg = 1;
 539        for (i = 0; i < 5; i++)
 540                flg &= (read_reg(cd, i + 1) == expect[i]);
 541
 542        if (verbose) {
 543                printk("%s: Reset (%d) signature = ", cd->name, k);
 544                for (i = 0; i < 5; i++)
 545                        printk("%3x", read_reg(cd, i + 1));
 546                if (!flg)
 547                        printk(" (incorrect)");
 548                printk("\n");
 549        }
 550
 551        pi_disconnect(cd->pi);
 552        return flg - 1;
 553}
 554
 555static int pcd_drive_reset(struct cdrom_device_info *cdi)
 556{
 557        return pcd_reset(cdi->handle);
 558}
 559
 560static int pcd_ready_wait(struct pcd_unit *cd, int tmo)
 561{
 562        char tr_cmd[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 563        int k, p;
 564
 565        k = 0;
 566        while (k < tmo) {
 567                cd->last_sense = 0;
 568                pcd_atapi(cd, tr_cmd, 0, NULL, DBMSG("test unit ready"));
 569                p = cd->last_sense;
 570                if (!p)
 571                        return 0;
 572                if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6)))
 573                        return p;
 574                k++;
 575                pcd_sleep(HZ);
 576        }
 577        return 0x000020;        /* timeout */
 578}
 579
 580static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
 581{
 582        char rc_cmd[12] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 583        struct pcd_unit *cd = cdi->handle;
 584
 585        if (pcd_ready_wait(cd, PCD_READY_TMO))
 586                return CDS_DRIVE_NOT_READY;
 587        if (pcd_atapi(cd, rc_cmd, 8, pcd_scratch, DBMSG("check media")))
 588                return CDS_NO_DISC;
 589        return CDS_DISC_OK;
 590}
 591
 592static int pcd_identify(struct pcd_unit *cd, char *id)
 593{
 594        int k, s;
 595        char id_cmd[12] = { 0x12, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
 596
 597        pcd_bufblk = -1;
 598
 599        s = pcd_atapi(cd, id_cmd, 36, pcd_buffer, "identify");
 600
 601        if (s)
 602                return -1;
 603        if ((pcd_buffer[0] & 0x1f) != 5) {
 604                if (verbose)
 605                        printk("%s: %s is not a CD-ROM\n",
 606                               cd->name, cd->drive ? "Slave" : "Master");
 607                return -1;
 608        }
 609        memcpy(id, pcd_buffer + 16, 16);
 610        id[16] = 0;
 611        k = 16;
 612        while ((k >= 0) && (id[k] <= 0x20)) {
 613                id[k] = 0;
 614                k--;
 615        }
 616
 617        printk("%s: %s: %s\n", cd->name, cd->drive ? "Slave" : "Master", id);
 618
 619        return 0;
 620}
 621
 622/*
 623 * returns  0, with id set if drive is detected
 624 *          -1, if drive detection failed
 625 */
 626static int pcd_probe(struct pcd_unit *cd, int ms, char *id)
 627{
 628        if (ms == -1) {
 629                for (cd->drive = 0; cd->drive <= 1; cd->drive++)
 630                        if (!pcd_reset(cd) && !pcd_identify(cd, id))
 631                                return 0;
 632        } else {
 633                cd->drive = ms;
 634                if (!pcd_reset(cd) && !pcd_identify(cd, id))
 635                        return 0;
 636        }
 637        return -1;
 638}
 639
 640static void pcd_probe_capabilities(void)
 641{
 642        int unit, r;
 643        char buffer[32];
 644        char cmd[12] = { 0x5a, 1 << 3, 0x2a, 0, 0, 0, 0, 18, 0, 0, 0, 0 };
 645        struct pcd_unit *cd;
 646
 647        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 648                if (!cd->present)
 649                        continue;
 650                r = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities");
 651                if (r)
 652                        continue;
 653                /* we should now have the cap page */
 654                if ((buffer[11] & 1) == 0)
 655                        cd->info.mask |= CDC_CD_R;
 656                if ((buffer[11] & 2) == 0)
 657                        cd->info.mask |= CDC_CD_RW;
 658                if ((buffer[12] & 1) == 0)
 659                        cd->info.mask |= CDC_PLAY_AUDIO;
 660                if ((buffer[14] & 1) == 0)
 661                        cd->info.mask |= CDC_LOCK;
 662                if ((buffer[14] & 8) == 0)
 663                        cd->info.mask |= CDC_OPEN_TRAY;
 664                if ((buffer[14] >> 6) == 0)
 665                        cd->info.mask |= CDC_CLOSE_TRAY;
 666        }
 667}
 668
 669static int pcd_detect(void)
 670{
 671        char id[18];
 672        int k, unit;
 673        struct pcd_unit *cd;
 674
 675        printk("%s: %s version %s, major %d, nice %d\n",
 676               name, name, PCD_VERSION, major, nice);
 677
 678        k = 0;
 679        if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
 680                cd = pcd;
 681                if (pi_init(cd->pi, 1, -1, -1, -1, -1, -1, pcd_buffer,
 682                            PI_PCD, verbose, cd->name)) {
 683                        if (!pcd_probe(cd, -1, id) && cd->disk) {
 684                                cd->present = 1;
 685                                k++;
 686                        } else
 687                                pi_release(cd->pi);
 688                }
 689        } else {
 690                for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 691                        int *conf = *drives[unit];
 692                        if (!conf[D_PRT])
 693                                continue;
 694                        if (!pi_init(cd->pi, 0, conf[D_PRT], conf[D_MOD],
 695                                     conf[D_UNI], conf[D_PRO], conf[D_DLY],
 696                                     pcd_buffer, PI_PCD, verbose, cd->name)) 
 697                                continue;
 698                        if (!pcd_probe(cd, conf[D_SLV], id) && cd->disk) {
 699                                cd->present = 1;
 700                                k++;
 701                        } else
 702                                pi_release(cd->pi);
 703                }
 704        }
 705        if (k)
 706                return 0;
 707
 708        printk("%s: No CD-ROM drive found\n", name);
 709        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
 710                put_disk(cd->disk);
 711        return -1;
 712}
 713
 714/* I/O request processing */
 715static struct request_queue *pcd_queue;
 716
 717static void do_pcd_request(struct request_queue * q)
 718{
 719        if (pcd_busy)
 720                return;
 721        while (1) {
 722                if (!pcd_req) {
 723                        pcd_req = blk_fetch_request(q);
 724                        if (!pcd_req)
 725                                return;
 726                }
 727
 728                if (rq_data_dir(pcd_req) == READ) {
 729                        struct pcd_unit *cd = pcd_req->rq_disk->private_data;
 730                        if (cd != pcd_current)
 731                                pcd_bufblk = -1;
 732                        pcd_current = cd;
 733                        pcd_sector = blk_rq_pos(pcd_req);
 734                        pcd_count = blk_rq_cur_sectors(pcd_req);
 735                        pcd_buf = pcd_req->buffer;
 736                        pcd_busy = 1;
 737                        ps_set_intr(do_pcd_read, NULL, 0, nice);
 738                        return;
 739                } else {
 740                        __blk_end_request_all(pcd_req, -EIO);
 741                        pcd_req = NULL;
 742                }
 743        }
 744}
 745
 746static inline void next_request(int err)
 747{
 748        unsigned long saved_flags;
 749
 750        spin_lock_irqsave(&pcd_lock, saved_flags);
 751        if (!__blk_end_request_cur(pcd_req, err))
 752                pcd_req = NULL;
 753        pcd_busy = 0;
 754        do_pcd_request(pcd_queue);
 755        spin_unlock_irqrestore(&pcd_lock, saved_flags);
 756}
 757
 758static int pcd_ready(void)
 759{
 760        return (((status_reg(pcd_current) & (IDE_BUSY | IDE_DRQ)) == IDE_DRQ));
 761}
 762
 763static void pcd_transfer(void)
 764{
 765
 766        while (pcd_count && (pcd_sector / 4 == pcd_bufblk)) {
 767                int o = (pcd_sector % 4) * 512;
 768                memcpy(pcd_buf, pcd_buffer + o, 512);
 769                pcd_count--;
 770                pcd_buf += 512;
 771                pcd_sector++;
 772        }
 773}
 774
 775static void pcd_start(void)
 776{
 777        int b, i;
 778        char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
 779
 780        pcd_bufblk = pcd_sector / 4;
 781        b = pcd_bufblk;
 782        for (i = 0; i < 4; i++) {
 783                rd_cmd[5 - i] = b & 0xff;
 784                b = b >> 8;
 785        }
 786
 787        if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) {
 788                pcd_bufblk = -1;
 789                next_request(-EIO);
 790                return;
 791        }
 792
 793        mdelay(1);
 794
 795        ps_set_intr(do_pcd_read_drq, pcd_ready, PCD_TMO, nice);
 796}
 797
 798static void do_pcd_read(void)
 799{
 800        pcd_busy = 1;
 801        pcd_retries = 0;
 802        pcd_transfer();
 803        if (!pcd_count) {
 804                next_request(0);
 805                return;
 806        }
 807
 808        pi_do_claimed(pcd_current->pi, pcd_start);
 809}
 810
 811static void do_pcd_read_drq(void)
 812{
 813        unsigned long saved_flags;
 814
 815        if (pcd_completion(pcd_current, pcd_buffer, "read block")) {
 816                if (pcd_retries < PCD_RETRIES) {
 817                        mdelay(1);
 818                        pcd_retries++;
 819                        pi_do_claimed(pcd_current->pi, pcd_start);
 820                        return;
 821                }
 822                pcd_bufblk = -1;
 823                next_request(-EIO);
 824                return;
 825        }
 826
 827        do_pcd_read();
 828        spin_lock_irqsave(&pcd_lock, saved_flags);
 829        do_pcd_request(pcd_queue);
 830        spin_unlock_irqrestore(&pcd_lock, saved_flags);
 831}
 832
 833/* the audio_ioctl stuff is adapted from sr_ioctl.c */
 834
 835static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 836{
 837        struct pcd_unit *cd = cdi->handle;
 838
 839        switch (cmd) {
 840
 841        case CDROMREADTOCHDR:
 842
 843                {
 844                        char cmd[12] =
 845                            { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
 846                         0, 0, 0 };
 847                        struct cdrom_tochdr *tochdr =
 848                            (struct cdrom_tochdr *) arg;
 849                        char buffer[32];
 850                        int r;
 851
 852                        r = pcd_atapi(cd, cmd, 12, buffer, "read toc header");
 853
 854                        tochdr->cdth_trk0 = buffer[2];
 855                        tochdr->cdth_trk1 = buffer[3];
 856
 857                        return r ? -EIO : 0;
 858                }
 859
 860        case CDROMREADTOCENTRY:
 861
 862                {
 863                        char cmd[12] =
 864                            { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
 865                         0, 0, 0 };
 866
 867                        struct cdrom_tocentry *tocentry =
 868                            (struct cdrom_tocentry *) arg;
 869                        unsigned char buffer[32];
 870                        int r;
 871
 872                        cmd[1] =
 873                            (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
 874                        cmd[6] = tocentry->cdte_track;
 875
 876                        r = pcd_atapi(cd, cmd, 12, buffer, "read toc entry");
 877
 878                        tocentry->cdte_ctrl = buffer[5] & 0xf;
 879                        tocentry->cdte_adr = buffer[5] >> 4;
 880                        tocentry->cdte_datamode =
 881                            (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
 882                        if (tocentry->cdte_format == CDROM_MSF) {
 883                                tocentry->cdte_addr.msf.minute = buffer[9];
 884                                tocentry->cdte_addr.msf.second = buffer[10];
 885                                tocentry->cdte_addr.msf.frame = buffer[11];
 886                        } else
 887                                tocentry->cdte_addr.lba =
 888                                    (((((buffer[8] << 8) + buffer[9]) << 8)
 889                                      + buffer[10]) << 8) + buffer[11];
 890
 891                        return r ? -EIO : 0;
 892                }
 893
 894        default:
 895
 896                return -ENOSYS;
 897        }
 898}
 899
 900static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
 901{
 902        char cmd[12] =
 903            { GPCMD_READ_SUBCHANNEL, 0, 0x40, 2, 0, 0, 0, 0, 24, 0, 0, 0 };
 904        char buffer[32];
 905
 906        if (pcd_atapi(cdi->handle, cmd, 24, buffer, "get mcn"))
 907                return -EIO;
 908
 909        memcpy(mcn->medium_catalog_number, buffer + 9, 13);
 910        mcn->medium_catalog_number[13] = 0;
 911
 912        return 0;
 913}
 914
 915static int __init pcd_init(void)
 916{
 917        struct pcd_unit *cd;
 918        int unit;
 919
 920        if (disable)
 921                return -EINVAL;
 922
 923        pcd_init_units();
 924
 925        if (pcd_detect())
 926                return -ENODEV;
 927
 928        /* get the atapi capabilities page */
 929        pcd_probe_capabilities();
 930
 931        if (register_blkdev(major, name)) {
 932                for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
 933                        put_disk(cd->disk);
 934                return -EBUSY;
 935        }
 936
 937        pcd_queue = blk_init_queue(do_pcd_request, &pcd_lock);
 938        if (!pcd_queue) {
 939                unregister_blkdev(major, name);
 940                for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
 941                        put_disk(cd->disk);
 942                return -ENOMEM;
 943        }
 944
 945        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 946                if (cd->present) {
 947                        register_cdrom(&cd->info);
 948                        cd->disk->private_data = cd;
 949                        cd->disk->queue = pcd_queue;
 950                        add_disk(cd->disk);
 951                }
 952        }
 953
 954        return 0;
 955}
 956
 957static void __exit pcd_exit(void)
 958{
 959        struct pcd_unit *cd;
 960        int unit;
 961
 962        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 963                if (cd->present) {
 964                        del_gendisk(cd->disk);
 965                        pi_release(cd->pi);
 966                        unregister_cdrom(&cd->info);
 967                }
 968                put_disk(cd->disk);
 969        }
 970        blk_cleanup_queue(pcd_queue);
 971        unregister_blkdev(major, name);
 972}
 973
 974MODULE_LICENSE("GPL");
 975module_init(pcd_init)
 976module_exit(pcd_exit)
 977
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.