linux/drivers/block/paride/pcd.c
<<
>>
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                pcd_req = elv_next_request(q);
 723                if (!pcd_req)
 724                        return;
 725
 726                if (rq_data_dir(pcd_req) == READ) {
 727                        struct pcd_unit *cd = pcd_req->rq_disk->private_data;
 728                        if (cd != pcd_current)
 729                                pcd_bufblk = -1;
 730                        pcd_current = cd;
 731                        pcd_sector = pcd_req->sector;
 732                        pcd_count = pcd_req->current_nr_sectors;
 733                        pcd_buf = pcd_req->buffer;
 734                        pcd_busy = 1;
 735                        ps_set_intr(do_pcd_read, NULL, 0, nice);
 736                        return;
 737                } else
 738                        end_request(pcd_req, 0);
 739        }
 740}
 741
 742static inline void next_request(int success)
 743{
 744        unsigned long saved_flags;
 745
 746        spin_lock_irqsave(&pcd_lock, saved_flags);
 747        end_request(pcd_req, success);
 748        pcd_busy = 0;
 749        do_pcd_request(pcd_queue);
 750        spin_unlock_irqrestore(&pcd_lock, saved_flags);
 751}
 752
 753static int pcd_ready(void)
 754{
 755        return (((status_reg(pcd_current) & (IDE_BUSY | IDE_DRQ)) == IDE_DRQ));
 756}
 757
 758static void pcd_transfer(void)
 759{
 760
 761        while (pcd_count && (pcd_sector / 4 == pcd_bufblk)) {
 762                int o = (pcd_sector % 4) * 512;
 763                memcpy(pcd_buf, pcd_buffer + o, 512);
 764                pcd_count--;
 765                pcd_buf += 512;
 766                pcd_sector++;
 767        }
 768}
 769
 770static void pcd_start(void)
 771{
 772        int b, i;
 773        char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
 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(pcd_current, rd_cmd, 2048, "read block")) {
 783                pcd_bufblk = -1;
 784                next_request(0);
 785                return;
 786        }
 787
 788        mdelay(1);
 789
 790        ps_set_intr(do_pcd_read_drq, pcd_ready, PCD_TMO, nice);
 791}
 792
 793static void do_pcd_read(void)
 794{
 795        pcd_busy = 1;
 796        pcd_retries = 0;
 797        pcd_transfer();
 798        if (!pcd_count) {
 799                next_request(1);
 800                return;
 801        }
 802
 803        pi_do_claimed(pcd_current->pi, pcd_start);
 804}
 805
 806static void do_pcd_read_drq(void)
 807{
 808        unsigned long saved_flags;
 809
 810        if (pcd_completion(pcd_current, pcd_buffer, "read block")) {
 811                if (pcd_retries < PCD_RETRIES) {
 812                        mdelay(1);
 813                        pcd_retries++;
 814                        pi_do_claimed(pcd_current->pi, pcd_start);
 815                        return;
 816                }
 817                pcd_bufblk = -1;
 818                next_request(0);
 819                return;
 820        }
 821
 822        do_pcd_read();
 823        spin_lock_irqsave(&pcd_lock, saved_flags);
 824        do_pcd_request(pcd_queue);
 825        spin_unlock_irqrestore(&pcd_lock, saved_flags);
 826}
 827
 828/* the audio_ioctl stuff is adapted from sr_ioctl.c */
 829
 830static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 831{
 832        struct pcd_unit *cd = cdi->handle;
 833
 834        switch (cmd) {
 835
 836        case CDROMREADTOCHDR:
 837
 838                {
 839                        char cmd[12] =
 840                            { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
 841                         0, 0, 0 };
 842                        struct cdrom_tochdr *tochdr =
 843                            (struct cdrom_tochdr *) arg;
 844                        char buffer[32];
 845                        int r;
 846
 847                        r = pcd_atapi(cd, cmd, 12, buffer, "read toc header");
 848
 849                        tochdr->cdth_trk0 = buffer[2];
 850                        tochdr->cdth_trk1 = buffer[3];
 851
 852                        return r ? -EIO : 0;
 853                }
 854
 855        case CDROMREADTOCENTRY:
 856
 857                {
 858                        char cmd[12] =
 859                            { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
 860                         0, 0, 0 };
 861
 862                        struct cdrom_tocentry *tocentry =
 863                            (struct cdrom_tocentry *) arg;
 864                        unsigned char buffer[32];
 865                        int r;
 866
 867                        cmd[1] =
 868                            (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
 869                        cmd[6] = tocentry->cdte_track;
 870
 871                        r = pcd_atapi(cd, cmd, 12, buffer, "read toc entry");
 872
 873                        tocentry->cdte_ctrl = buffer[5] & 0xf;
 874                        tocentry->cdte_adr = buffer[5] >> 4;
 875                        tocentry->cdte_datamode =
 876                            (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
 877                        if (tocentry->cdte_format == CDROM_MSF) {
 878                                tocentry->cdte_addr.msf.minute = buffer[9];
 879                                tocentry->cdte_addr.msf.second = buffer[10];
 880                                tocentry->cdte_addr.msf.frame = buffer[11];
 881                        } else
 882                                tocentry->cdte_addr.lba =
 883                                    (((((buffer[8] << 8) + buffer[9]) << 8)
 884                                      + buffer[10]) << 8) + buffer[11];
 885
 886                        return r ? -EIO : 0;
 887                }
 888
 889        default:
 890
 891                return -ENOSYS;
 892        }
 893}
 894
 895static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
 896{
 897        char cmd[12] =
 898            { GPCMD_READ_SUBCHANNEL, 0, 0x40, 2, 0, 0, 0, 0, 24, 0, 0, 0 };
 899        char buffer[32];
 900
 901        if (pcd_atapi(cdi->handle, cmd, 24, buffer, "get mcn"))
 902                return -EIO;
 903
 904        memcpy(mcn->medium_catalog_number, buffer + 9, 13);
 905        mcn->medium_catalog_number[13] = 0;
 906
 907        return 0;
 908}
 909
 910static int __init pcd_init(void)
 911{
 912        struct pcd_unit *cd;
 913        int unit;
 914
 915        if (disable)
 916                return -EINVAL;
 917
 918        pcd_init_units();
 919
 920        if (pcd_detect())
 921                return -ENODEV;
 922
 923        /* get the atapi capabilities page */
 924        pcd_probe_capabilities();
 925
 926        if (register_blkdev(major, name)) {
 927                for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
 928                        put_disk(cd->disk);
 929                return -EBUSY;
 930        }
 931
 932        pcd_queue = blk_init_queue(do_pcd_request, &pcd_lock);
 933        if (!pcd_queue) {
 934                unregister_blkdev(major, name);
 935                for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
 936                        put_disk(cd->disk);
 937                return -ENOMEM;
 938        }
 939
 940        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 941                if (cd->present) {
 942                        register_cdrom(&cd->info);
 943                        cd->disk->private_data = cd;
 944                        cd->disk->queue = pcd_queue;
 945                        add_disk(cd->disk);
 946                }
 947        }
 948
 949        return 0;
 950}
 951
 952static void __exit pcd_exit(void)
 953{
 954        struct pcd_unit *cd;
 955        int unit;
 956
 957        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 958                if (cd->present) {
 959                        del_gendisk(cd->disk);
 960                        pi_release(cd->pi);
 961                        unregister_cdrom(&cd->info);
 962                }
 963                put_disk(cd->disk);
 964        }
 965        blk_cleanup_queue(pcd_queue);
 966        unregister_blkdev(major, name);
 967}
 968
 969MODULE_LICENSE("GPL");
 970module_init(pcd_init)
 971module_exit(pcd_exit)
 972
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.