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 inode *inode, struct file *file)
 227{
 228        struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data;
 229        return cdrom_open(&cd->info, inode, file);
 230}
 231
 232static int pcd_block_release(struct inode *inode, struct file *file)
 233{
 234        struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data;
 235        return cdrom_release(&cd->info, file);
 236}
 237
 238static int pcd_block_ioctl(struct inode *inode, struct file *file,
 239                                unsigned cmd, unsigned long arg)
 240{
 241        struct pcd_unit *cd = inode->i_bdev->bd_disk->private_data;
 242        return cdrom_ioctl(file, &cd->info, inode, cmd, arg);
 243}
 244
 245static int pcd_block_media_changed(struct gendisk *disk)
 246{
 247        struct pcd_unit *cd = disk->private_data;
 248        return cdrom_media_changed(&cd->info);
 249}
 250
 251static struct block_device_operations pcd_bdops = {
 252        .owner          = THIS_MODULE,
 253        .open           = pcd_block_open,
 254        .release        = pcd_block_release,
 255        .ioctl          = pcd_block_ioctl,
 256        .media_changed  = pcd_block_media_changed,
 257};
 258
 259static struct cdrom_device_ops pcd_dops = {
 260        .open           = pcd_open,
 261        .release        = pcd_release,
 262        .drive_status   = pcd_drive_status,
 263        .media_changed  = pcd_media_changed,
 264        .tray_move      = pcd_tray_move,
 265        .lock_door      = pcd_lock_door,
 266        .get_mcn        = pcd_get_mcn,
 267        .reset          = pcd_drive_reset,
 268        .audio_ioctl    = pcd_audio_ioctl,
 269        .generic_packet = pcd_packet,
 270        .capability     = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
 271                          CDC_MCN | CDC_MEDIA_CHANGED | CDC_RESET |
 272                          CDC_PLAY_AUDIO | CDC_GENERIC_PACKET | CDC_CD_R |
 273                          CDC_CD_RW,
 274};
 275
 276static void pcd_init_units(void)
 277{
 278        struct pcd_unit *cd;
 279        int unit;
 280
 281        pcd_drive_count = 0;
 282        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 283                struct gendisk *disk = alloc_disk(1);
 284                if (!disk)
 285                        continue;
 286                cd->disk = disk;
 287                cd->pi = &cd->pia;
 288                cd->present = 0;
 289                cd->last_sense = 0;
 290                cd->changed = 1;
 291                cd->drive = (*drives[unit])[D_SLV];
 292                if ((*drives[unit])[D_PRT])
 293                        pcd_drive_count++;
 294
 295                cd->name = &cd->info.name[0];
 296                snprintf(cd->name, sizeof(cd->info.name), "%s%d", name, unit);
 297                cd->info.ops = &pcd_dops;
 298                cd->info.handle = cd;
 299                cd->info.speed = 0;
 300                cd->info.capacity = 1;
 301                cd->info.mask = 0;
 302                disk->major = major;
 303                disk->first_minor = unit;
 304                strcpy(disk->disk_name, cd->name);      /* umm... */
 305                disk->fops = &pcd_bdops;
 306        }
 307}
 308
 309static int pcd_open(struct cdrom_device_info *cdi, int purpose)
 310{
 311        struct pcd_unit *cd = cdi->handle;
 312        if (!cd->present)
 313                return -ENODEV;
 314        return 0;
 315}
 316
 317static void pcd_release(struct cdrom_device_info *cdi)
 318{
 319}
 320
 321static inline int status_reg(struct pcd_unit *cd)
 322{
 323        return pi_read_regr(cd->pi, 1, 6);
 324}
 325
 326static inline int read_reg(struct pcd_unit *cd, int reg)
 327{
 328        return pi_read_regr(cd->pi, 0, reg);
 329}
 330
 331static inline void write_reg(struct pcd_unit *cd, int reg, int val)
 332{
 333        pi_write_regr(cd->pi, 0, reg, val);
 334}
 335
 336static int pcd_wait(struct pcd_unit *cd, int go, int stop, char *fun, char *msg)
 337{
 338        int j, r, e, s, p;
 339
 340        j = 0;
 341        while ((((r = status_reg(cd)) & go) || (stop && (!(r & stop))))
 342               && (j++ < PCD_SPIN))
 343                udelay(PCD_DELAY);
 344
 345        if ((r & (IDE_ERR & stop)) || (j >= PCD_SPIN)) {
 346                s = read_reg(cd, 7);
 347                e = read_reg(cd, 1);
 348                p = read_reg(cd, 2);
 349                if (j >= PCD_SPIN)
 350                        e |= 0x100;
 351                if (fun)
 352                        printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
 353                               " loop=%d phase=%d\n",
 354                               cd->name, fun, msg, r, s, e, j, p);
 355                return (s << 8) + r;
 356        }
 357        return 0;
 358}
 359
 360static int pcd_command(struct pcd_unit *cd, char *cmd, int dlen, char *fun)
 361{
 362        pi_connect(cd->pi);
 363
 364        write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
 365
 366        if (pcd_wait(cd, IDE_BUSY | IDE_DRQ, 0, fun, "before command")) {
 367                pi_disconnect(cd->pi);
 368                return -1;
 369        }
 370
 371        write_reg(cd, 4, dlen % 256);
 372        write_reg(cd, 5, dlen / 256);
 373        write_reg(cd, 7, 0xa0); /* ATAPI packet command */
 374
 375        if (pcd_wait(cd, IDE_BUSY, IDE_DRQ, fun, "command DRQ")) {
 376                pi_disconnect(cd->pi);
 377                return -1;
 378        }
 379
 380        if (read_reg(cd, 2) != 1) {
 381                printk("%s: %s: command phase error\n", cd->name, fun);
 382                pi_disconnect(cd->pi);
 383                return -1;
 384        }
 385
 386        pi_write_block(cd->pi, cmd, 12);
 387
 388        return 0;
 389}
 390
 391static int pcd_completion(struct pcd_unit *cd, char *buf, char *fun)
 392{
 393        int r, d, p, n, k, j;
 394
 395        r = -1;
 396        k = 0;
 397        j = 0;
 398
 399        if (!pcd_wait(cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR,
 400                      fun, "completion")) {
 401                r = 0;
 402                while (read_reg(cd, 7) & IDE_DRQ) {
 403                        d = read_reg(cd, 4) + 256 * read_reg(cd, 5);
 404                        n = (d + 3) & 0xfffc;
 405                        p = read_reg(cd, 2) & 3;
 406
 407                        if ((p == 2) && (n > 0) && (j == 0)) {
 408                                pi_read_block(cd->pi, buf, n);
 409                                if (verbose > 1)
 410                                        printk("%s: %s: Read %d bytes\n",
 411                                               cd->name, fun, n);
 412                                r = 0;
 413                                j++;
 414                        } else {
 415                                if (verbose > 1)
 416                                        printk
 417                                            ("%s: %s: Unexpected phase %d, d=%d, k=%d\n",
 418                                             cd->name, fun, p, d, k);
 419                                if ((verbose < 2) && !pcd_warned) {
 420                                        pcd_warned = 1;
 421                                        printk
 422                                            ("%s: WARNING: ATAPI phase errors\n",
 423                                             cd->name);
 424                                }
 425                                mdelay(1);
 426                        }
 427                        if (k++ > PCD_TMO) {
 428                                printk("%s: Stuck DRQ\n", cd->name);
 429                                break;
 430                        }
 431                        if (pcd_wait
 432                            (cd, IDE_BUSY, IDE_DRQ | IDE_READY | IDE_ERR, fun,
 433                             "completion")) {
 434                                r = -1;
 435                                break;
 436                        }
 437                }
 438        }
 439
 440        pi_disconnect(cd->pi);
 441
 442        return r;
 443}
 444
 445static void pcd_req_sense(struct pcd_unit *cd, char *fun)
 446{
 447        char rs_cmd[12] = { 0x03, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
 448        char buf[16];
 449        int r, c;
 450
 451        r = pcd_command(cd, rs_cmd, 16, "Request sense");
 452        mdelay(1);
 453        if (!r)
 454                pcd_completion(cd, buf, "Request sense");
 455
 456        cd->last_sense = -1;
 457        c = 2;
 458        if (!r) {
 459                if (fun)
 460                        printk("%s: %s: Sense key: %x, ASC: %x, ASQ: %x\n",
 461                               cd->name, fun, buf[2] & 0xf, buf[12], buf[13]);
 462                c = buf[2] & 0xf;
 463                cd->last_sense =
 464                    c | ((buf[12] & 0xff) << 8) | ((buf[13] & 0xff) << 16);
 465        }
 466        if ((c == 2) || (c == 6))
 467                cd->changed = 1;
 468}
 469
 470static int pcd_atapi(struct pcd_unit *cd, char *cmd, int dlen, char *buf, char *fun)
 471{
 472        int r;
 473
 474        r = pcd_command(cd, cmd, dlen, fun);
 475        mdelay(1);
 476        if (!r)
 477                r = pcd_completion(cd, buf, fun);
 478        if (r)
 479                pcd_req_sense(cd, fun);
 480
 481        return r;
 482}
 483
 484static int pcd_packet(struct cdrom_device_info *cdi, struct packet_command *cgc)
 485{
 486        return pcd_atapi(cdi->handle, cgc->cmd, cgc->buflen, cgc->buffer,
 487                         "generic packet");
 488}
 489
 490#define DBMSG(msg)      ((verbose>1)?(msg):NULL)
 491
 492static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr)
 493{
 494        struct pcd_unit *cd = cdi->handle;
 495        int res = cd->changed;
 496        if (res)
 497                cd->changed = 0;
 498        return res;
 499}
 500
 501static int pcd_lock_door(struct cdrom_device_info *cdi, int lock)
 502{
 503        char un_cmd[12] = { 0x1e, 0, 0, 0, lock, 0, 0, 0, 0, 0, 0, 0 };
 504
 505        return pcd_atapi(cdi->handle, un_cmd, 0, pcd_scratch,
 506                         lock ? "lock door" : "unlock door");
 507}
 508
 509static int pcd_tray_move(struct cdrom_device_info *cdi, int position)
 510{
 511        char ej_cmd[12] = { 0x1b, 0, 0, 0, 3 - position, 0, 0, 0, 0, 0, 0, 0 };
 512
 513        return pcd_atapi(cdi->handle, ej_cmd, 0, pcd_scratch,
 514                         position ? "eject" : "close tray");
 515}
 516
 517static void pcd_sleep(int cs)
 518{
 519        schedule_timeout_interruptible(cs);
 520}
 521
 522static int pcd_reset(struct pcd_unit *cd)
 523{
 524        int i, k, flg;
 525        int expect[5] = { 1, 1, 1, 0x14, 0xeb };
 526
 527        pi_connect(cd->pi);
 528        write_reg(cd, 6, 0xa0 + 0x10 * cd->drive);
 529        write_reg(cd, 7, 8);
 530
 531        pcd_sleep(20 * HZ / 1000);      /* delay a bit */
 532
 533        k = 0;
 534        while ((k++ < PCD_RESET_TMO) && (status_reg(cd) & IDE_BUSY))
 535                pcd_sleep(HZ / 10);
 536
 537        flg = 1;
 538        for (i = 0; i < 5; i++)
 539                flg &= (read_reg(cd, i + 1) == expect[i]);
 540
 541        if (verbose) {
 542                printk("%s: Reset (%d) signature = ", cd->name, k);
 543                for (i = 0; i < 5; i++)
 544                        printk("%3x", read_reg(cd, i + 1));
 545                if (!flg)
 546                        printk(" (incorrect)");
 547                printk("\n");
 548        }
 549
 550        pi_disconnect(cd->pi);
 551        return flg - 1;
 552}
 553
 554static int pcd_drive_reset(struct cdrom_device_info *cdi)
 555{
 556        return pcd_reset(cdi->handle);
 557}
 558
 559static int pcd_ready_wait(struct pcd_unit *cd, int tmo)
 560{
 561        char tr_cmd[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 562        int k, p;
 563
 564        k = 0;
 565        while (k < tmo) {
 566                cd->last_sense = 0;
 567                pcd_atapi(cd, tr_cmd, 0, NULL, DBMSG("test unit ready"));
 568                p = cd->last_sense;
 569                if (!p)
 570                        return 0;
 571                if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6)))
 572                        return p;
 573                k++;
 574                pcd_sleep(HZ);
 575        }
 576        return 0x000020;        /* timeout */
 577}
 578
 579static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
 580{
 581        char rc_cmd[12] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 582        struct pcd_unit *cd = cdi->handle;
 583
 584        if (pcd_ready_wait(cd, PCD_READY_TMO))
 585                return CDS_DRIVE_NOT_READY;
 586        if (pcd_atapi(cd, rc_cmd, 8, pcd_scratch, DBMSG("check media")))
 587                return CDS_NO_DISC;
 588        return CDS_DISC_OK;
 589}
 590
 591static int pcd_identify(struct pcd_unit *cd, char *id)
 592{
 593        int k, s;
 594        char id_cmd[12] = { 0x12, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
 595
 596        pcd_bufblk = -1;
 597
 598        s = pcd_atapi(cd, id_cmd, 36, pcd_buffer, "identify");
 599
 600        if (s)
 601                return -1;
 602        if ((pcd_buffer[0] & 0x1f) != 5) {
 603                if (verbose)
 604                        printk("%s: %s is not a CD-ROM\n",
 605                               cd->name, cd->drive ? "Slave" : "Master");
 606                return -1;
 607        }
 608        memcpy(id, pcd_buffer + 16, 16);
 609        id[16] = 0;
 610        k = 16;
 611        while ((k >= 0) && (id[k] <= 0x20)) {
 612                id[k] = 0;
 613                k--;
 614        }
 615
 616        printk("%s: %s: %s\n", cd->name, cd->drive ? "Slave" : "Master", id);
 617
 618        return 0;
 619}
 620
 621/*
 622 * returns  0, with id set if drive is detected
 623 *          -1, if drive detection failed
 624 */
 625static int pcd_probe(struct pcd_unit *cd, int ms, char *id)
 626{
 627        if (ms == -1) {
 628                for (cd->drive = 0; cd->drive <= 1; cd->drive++)
 629                        if (!pcd_reset(cd) && !pcd_identify(cd, id))
 630                                return 0;
 631        } else {
 632                cd->drive = ms;
 633                if (!pcd_reset(cd) && !pcd_identify(cd, id))
 634                        return 0;
 635        }
 636        return -1;
 637}
 638
 639static void pcd_probe_capabilities(void)
 640{
 641        int unit, r;
 642        char buffer[32];
 643        char cmd[12] = { 0x5a, 1 << 3, 0x2a, 0, 0, 0, 0, 18, 0, 0, 0, 0 };
 644        struct pcd_unit *cd;
 645
 646        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 647                if (!cd->present)
 648                        continue;
 649                r = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities");
 650                if (r)
 651                        continue;
 652                /* we should now have the cap page */
 653                if ((buffer[11] & 1) == 0)
 654                        cd->info.mask |= CDC_CD_R;
 655                if ((buffer[11] & 2) == 0)
 656                        cd->info.mask |= CDC_CD_RW;
 657                if ((buffer[12] & 1) == 0)
 658                        cd->info.mask |= CDC_PLAY_AUDIO;
 659                if ((buffer[14] & 1) == 0)
 660                        cd->info.mask |= CDC_LOCK;
 661                if ((buffer[14] & 8) == 0)
 662                        cd->info.mask |= CDC_OPEN_TRAY;
 663                if ((buffer[14] >> 6) == 0)
 664                        cd->info.mask |= CDC_CLOSE_TRAY;
 665        }
 666}
 667
 668static int pcd_detect(void)
 669{
 670        char id[18];
 671        int k, unit;
 672        struct pcd_unit *cd;
 673
 674        printk("%s: %s version %s, major %d, nice %d\n",
 675               name, name, PCD_VERSION, major, nice);
 676
 677        k = 0;
 678        if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
 679                cd = pcd;
 680                if (pi_init(cd->pi, 1, -1, -1, -1, -1, -1, pcd_buffer,
 681                            PI_PCD, verbose, cd->name)) {
 682                        if (!pcd_probe(cd, -1, id) && cd->disk) {
 683                                cd->present = 1;
 684                                k++;
 685                        } else
 686                                pi_release(cd->pi);
 687                }
 688        } else {
 689                for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 690                        int *conf = *drives[unit];
 691                        if (!conf[D_PRT])
 692                                continue;
 693                        if (!pi_init(cd->pi, 0, conf[D_PRT], conf[D_MOD],
 694                                     conf[D_UNI], conf[D_PRO], conf[D_DLY],
 695                                     pcd_buffer, PI_PCD, verbose, cd->name)) 
 696                                continue;
 697                        if (!pcd_probe(cd, conf[D_SLV], id) && cd->disk) {
 698                                cd->present = 1;
 699                                k++;
 700                        } else
 701                                pi_release(cd->pi);
 702                }
 703        }
 704        if (k)
 705                return 0;
 706
 707        printk("%s: No CD-ROM drive found\n", name);
 708        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
 709                put_disk(cd->disk);
 710        return -1;
 711}
 712
 713/* I/O request processing */
 714static struct request_queue *pcd_queue;
 715
 716static void do_pcd_request(struct request_queue * q)
 717{
 718        if (pcd_busy)
 719                return;
 720        while (1) {
 721                pcd_req = elv_next_request(q);
 722                if (!pcd_req)
 723                        return;
 724
 725                if (rq_data_dir(pcd_req) == READ) {
 726                        struct pcd_unit *cd = pcd_req->rq_disk->private_data;
 727                        if (cd != pcd_current)
 728                                pcd_bufblk = -1;
 729                        pcd_current = cd;
 730                        pcd_sector = pcd_req->sector;
 731                        pcd_count = pcd_req->current_nr_sectors;
 732                        pcd_buf = pcd_req->buffer;
 733                        pcd_busy = 1;
 734                        ps_set_intr(do_pcd_read, NULL, 0, nice);
 735                        return;
 736                } else
 737                        end_request(pcd_req, 0);
 738        }
 739}
 740
 741static inline void next_request(int success)
 742{
 743        unsigned long saved_flags;
 744
 745        spin_lock_irqsave(&pcd_lock, saved_flags);
 746        end_request(pcd_req, success);
 747        pcd_busy = 0;
 748        do_pcd_request(pcd_queue);
 749        spin_unlock_irqrestore(&pcd_lock, saved_flags);
 750}
 751
 752static int pcd_ready(void)
 753{
 754        return (((status_reg(pcd_current) & (IDE_BUSY | IDE_DRQ)) == IDE_DRQ));
 755}
 756
 757static void pcd_transfer(void)
 758{
 759
 760        while (pcd_count && (pcd_sector / 4 == pcd_bufblk)) {
 761                int o = (pcd_sector % 4) * 512;
 762                memcpy(pcd_buf, pcd_buffer + o, 512);
 763                pcd_count--;
 764                pcd_buf += 512;
 765                pcd_sector++;
 766        }
 767}
 768
 769static void pcd_start(void)
 770{
 771        int b, i;
 772        char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
 773
 774        pcd_bufblk = pcd_sector / 4;
 775        b = pcd_bufblk;
 776        for (i = 0; i < 4; i++) {
 777                rd_cmd[5 - i] = b & 0xff;
 778                b = b >> 8;
 779        }
 780
 781        if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) {
 782                pcd_bufblk = -1;
 783                next_request(0);
 784                return;
 785        }
 786
 787        mdelay(1);
 788
 789        ps_set_intr(do_pcd_read_drq, pcd_ready, PCD_TMO, nice);
 790}
 791
 792static void do_pcd_read(void)
 793{
 794        pcd_busy = 1;
 795        pcd_retries = 0;
 796        pcd_transfer();
 797        if (!pcd_count) {
 798                next_request(1);
 799                return;
 800        }
 801
 802        pi_do_claimed(pcd_current->pi, pcd_start);
 803}
 804
 805static void do_pcd_read_drq(void)
 806{
 807        unsigned long saved_flags;
 808
 809        if (pcd_completion(pcd_current, pcd_buffer, "read block")) {
 810                if (pcd_retries < PCD_RETRIES) {
 811                        mdelay(1);
 812                        pcd_retries++;
 813                        pi_do_claimed(pcd_current->pi, pcd_start);
 814                        return;
 815                }
 816                pcd_bufblk = -1;
 817                next_request(0);
 818                return;
 819        }
 820
 821        do_pcd_read();
 822        spin_lock_irqsave(&pcd_lock, saved_flags);
 823        do_pcd_request(pcd_queue);
 824        spin_unlock_irqrestore(&pcd_lock, saved_flags);
 825}
 826
 827/* the audio_ioctl stuff is adapted from sr_ioctl.c */
 828
 829static int pcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 830{
 831        struct pcd_unit *cd = cdi->handle;
 832
 833        switch (cmd) {
 834
 835        case CDROMREADTOCHDR:
 836
 837                {
 838                        char cmd[12] =
 839                            { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
 840                         0, 0, 0 };
 841                        struct cdrom_tochdr *tochdr =
 842                            (struct cdrom_tochdr *) arg;
 843                        char buffer[32];
 844                        int r;
 845
 846                        r = pcd_atapi(cd, cmd, 12, buffer, "read toc header");
 847
 848                        tochdr->cdth_trk0 = buffer[2];
 849                        tochdr->cdth_trk1 = buffer[3];
 850
 851                        return r ? -EIO : 0;
 852                }
 853
 854        case CDROMREADTOCENTRY:
 855
 856                {
 857                        char cmd[12] =
 858                            { GPCMD_READ_TOC_PMA_ATIP, 0, 0, 0, 0, 0, 0, 0, 12,
 859                         0, 0, 0 };
 860
 861                        struct cdrom_tocentry *tocentry =
 862                            (struct cdrom_tocentry *) arg;
 863                        unsigned char buffer[32];
 864                        int r;
 865
 866                        cmd[1] =
 867                            (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
 868                        cmd[6] = tocentry->cdte_track;
 869
 870                        r = pcd_atapi(cd, cmd, 12, buffer, "read toc entry");
 871
 872                        tocentry->cdte_ctrl = buffer[5] & 0xf;
 873                        tocentry->cdte_adr = buffer[5] >> 4;
 874                        tocentry->cdte_datamode =
 875                            (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
 876                        if (tocentry->cdte_format == CDROM_MSF) {
 877                                tocentry->cdte_addr.msf.minute = buffer[9];
 878                                tocentry->cdte_addr.msf.second = buffer[10];
 879                                tocentry->cdte_addr.msf.frame = buffer[11];
 880                        } else
 881                                tocentry->cdte_addr.lba =
 882                                    (((((buffer[8] << 8) + buffer[9]) << 8)
 883                                      + buffer[10]) << 8) + buffer[11];
 884
 885                        return r ? -EIO : 0;
 886                }
 887
 888        default:
 889
 890                return -ENOSYS;
 891        }
 892}
 893
 894static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
 895{
 896        char cmd[12] =
 897            { GPCMD_READ_SUBCHANNEL, 0, 0x40, 2, 0, 0, 0, 0, 24, 0, 0, 0 };
 898        char buffer[32];
 899
 900        if (pcd_atapi(cdi->handle, cmd, 24, buffer, "get mcn"))
 901                return -EIO;
 902
 903        memcpy(mcn->medium_catalog_number, buffer + 9, 13);
 904        mcn->medium_catalog_number[13] = 0;
 905
 906        return 0;
 907}
 908
 909static int __init pcd_init(void)
 910{
 911        struct pcd_unit *cd;
 912        int unit;
 913
 914        if (disable)
 915                return -EINVAL;
 916
 917        pcd_init_units();
 918
 919        if (pcd_detect())
 920                return -ENODEV;
 921
 922        /* get the atapi capabilities page */
 923        pcd_probe_capabilities();
 924
 925        if (register_blkdev(major, name)) {
 926                for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
 927                        put_disk(cd->disk);
 928                return -EBUSY;
 929        }
 930
 931        pcd_queue = blk_init_queue(do_pcd_request, &pcd_lock);
 932        if (!pcd_queue) {
 933                unregister_blkdev(major, name);
 934                for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
 935                        put_disk(cd->disk);
 936                return -ENOMEM;
 937        }
 938
 939        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 940                if (cd->present) {
 941                        register_cdrom(&cd->info);
 942                        cd->disk->private_data = cd;
 943                        cd->disk->queue = pcd_queue;
 944                        add_disk(cd->disk);
 945                }
 946        }
 947
 948        return 0;
 949}
 950
 951static void __exit pcd_exit(void)
 952{
 953        struct pcd_unit *cd;
 954        int unit;
 955
 956        for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
 957                if (cd->present) {
 958                        del_gendisk(cd->disk);
 959                        pi_release(cd->pi);
 960                        unregister_cdrom(&cd->info);
 961                }
 962                put_disk(cd->disk);
 963        }
 964        blk_cleanup_queue(pcd_queue);
 965        unregister_blkdev(major, name);
 966}
 967
 968MODULE_LICENSE("GPL");
 969module_init(pcd_init)
 970module_exit(pcd_exit)
 971
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.