linux/drivers/ide/ide-proc.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/ide/ide-proc.c        Version 1.05    Mar 05, 2003
   3 *
   4 *  Copyright (C) 1997-1998     Mark Lord
   5 *  Copyright (C) 2003          Red Hat <alan@redhat.com>
   6 *
   7 *  Some code was moved here from ide.c, see it for original copyrights.
   8 */
   9
  10/*
  11 * This is the /proc/ide/ filesystem implementation.
  12 *
  13 * Drive/Driver settings can be retrieved by reading the drive's
  14 * "settings" files.  e.g.    "cat /proc/ide0/hda/settings"
  15 * To write a new value "val" into a specific setting "name", use:
  16 *   echo "name:val" >/proc/ide/ide0/hda/settings
  17 *
  18 * Also useful, "cat /proc/ide0/hda/[identify, smart_values,
  19 * smart_thresholds, capabilities]" will issue an IDENTIFY /
  20 * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS /
  21 * SENSE CAPABILITIES command to /dev/hda, and then dump out the
  22 * returned data as 256 16-bit words.  The "hdparm" utility will
  23 * be updated someday soon to use this mechanism.
  24 *
  25 */
  26
  27#include <linux/module.h>
  28
  29#include <asm/uaccess.h>
  30#include <linux/errno.h>
  31#include <linux/proc_fs.h>
  32#include <linux/stat.h>
  33#include <linux/mm.h>
  34#include <linux/pci.h>
  35#include <linux/ctype.h>
  36#include <linux/hdreg.h>
  37#include <linux/ide.h>
  38#include <linux/seq_file.h>
  39
  40#include <asm/io.h>
  41
  42static struct proc_dir_entry *proc_ide_root;
  43
  44static int proc_ide_read_imodel
  45        (char *page, char **start, off_t off, int count, int *eof, void *data)
  46{
  47        ide_hwif_t      *hwif = (ide_hwif_t *) data;
  48        int             len;
  49        const char      *name;
  50
  51        /*
  52         * Neither ide_unknown nor ide_forced should be set at this point.
  53         */
  54        switch (hwif->chipset) {
  55                case ide_generic:       name = "generic";       break;
  56                case ide_pci:           name = "pci";           break;
  57                case ide_cmd640:        name = "cmd640";        break;
  58                case ide_dtc2278:       name = "dtc2278";       break;
  59                case ide_ali14xx:       name = "ali14xx";       break;
  60                case ide_qd65xx:        name = "qd65xx";        break;
  61                case ide_umc8672:       name = "umc8672";       break;
  62                case ide_ht6560b:       name = "ht6560b";       break;
  63                case ide_rz1000:        name = "rz1000";        break;
  64                case ide_trm290:        name = "trm290";        break;
  65                case ide_cmd646:        name = "cmd646";        break;
  66                case ide_cy82c693:      name = "cy82c693";      break;
  67                case ide_4drives:       name = "4drives";       break;
  68                case ide_pmac:          name = "mac-io";        break;
  69                case ide_au1xxx:        name = "au1xxx";        break;
  70                case ide_etrax100:      name = "etrax100";      break;
  71                case ide_acorn:         name = "acorn";         break;
  72                default:                name = "(unknown)";     break;
  73        }
  74        len = sprintf(page, "%s\n", name);
  75        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
  76}
  77
  78static int proc_ide_read_mate
  79        (char *page, char **start, off_t off, int count, int *eof, void *data)
  80{
  81        ide_hwif_t      *hwif = (ide_hwif_t *) data;
  82        int             len;
  83
  84        if (hwif && hwif->mate && hwif->mate->present)
  85                len = sprintf(page, "%s\n", hwif->mate->name);
  86        else
  87                len = sprintf(page, "(none)\n");
  88        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
  89}
  90
  91static int proc_ide_read_channel
  92        (char *page, char **start, off_t off, int count, int *eof, void *data)
  93{
  94        ide_hwif_t      *hwif = (ide_hwif_t *) data;
  95        int             len;
  96
  97        page[0] = hwif->channel ? '1' : '0';
  98        page[1] = '\n';
  99        len = 2;
 100        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 101}
 102
 103static int proc_ide_read_identify
 104        (char *page, char **start, off_t off, int count, int *eof, void *data)
 105{
 106        ide_drive_t     *drive = (ide_drive_t *)data;
 107        int             len = 0, i = 0;
 108        int             err = 0;
 109
 110        len = sprintf(page, "\n");
 111
 112        if (drive) {
 113                unsigned short *val = (unsigned short *) page;
 114
 115                err = taskfile_lib_get_identify(drive, page);
 116                if (!err) {
 117                        char *out = ((char *)page) + (SECTOR_WORDS * 4);
 118                        page = out;
 119                        do {
 120                                out += sprintf(out, "%04x%c",
 121                                        le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
 122                                val += 1;
 123                        } while (i < (SECTOR_WORDS * 2));
 124                        len = out - page;
 125                }
 126        }
 127        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 128}
 129
 130/**
 131 *      __ide_add_setting       -       add an ide setting option
 132 *      @drive: drive to use
 133 *      @name: setting name
 134 *      @rw: true if the function is read write
 135 *      @data_type: type of data
 136 *      @min: range minimum
 137 *      @max: range maximum
 138 *      @mul_factor: multiplication scale
 139 *      @div_factor: divison scale
 140 *      @data: private data field
 141 *      @set: setting
 142 *      @auto_remove: setting auto removal flag
 143 *
 144 *      Removes the setting named from the device if it is present.
 145 *      The function takes the settings_lock to protect against
 146 *      parallel changes. This function must not be called from IRQ
 147 *      context. Returns 0 on success or -1 on failure.
 148 *
 149 *      BUGS: This code is seriously over-engineered. There is also
 150 *      magic about how the driver specific features are setup. If
 151 *      a driver is attached we assume the driver settings are auto
 152 *      remove.
 153 */
 154
 155static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
 156{
 157        ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
 158
 159        mutex_lock(&ide_setting_mtx);
 160        while ((*p) && strcmp((*p)->name, name) < 0)
 161                p = &((*p)->next);
 162        if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
 163                goto abort;
 164        if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
 165                goto abort;
 166        strcpy(setting->name, name);
 167        setting->rw = rw;
 168        setting->data_type = data_type;
 169        setting->min = min;
 170        setting->max = max;
 171        setting->mul_factor = mul_factor;
 172        setting->div_factor = div_factor;
 173        setting->data = data;
 174        setting->set = set;
 175
 176        setting->next = *p;
 177        if (auto_remove)
 178                setting->auto_remove = 1;
 179        *p = setting;
 180        mutex_unlock(&ide_setting_mtx);
 181        return 0;
 182abort:
 183        mutex_unlock(&ide_setting_mtx);
 184        kfree(setting);
 185        return -1;
 186}
 187
 188int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
 189{
 190        return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1);
 191}
 192
 193EXPORT_SYMBOL(ide_add_setting);
 194
 195/**
 196 *      __ide_remove_setting    -       remove an ide setting option
 197 *      @drive: drive to use
 198 *      @name: setting name
 199 *
 200 *      Removes the setting named from the device if it is present.
 201 *      The caller must hold the setting semaphore.
 202 */
 203
 204static void __ide_remove_setting (ide_drive_t *drive, char *name)
 205{
 206        ide_settings_t **p, *setting;
 207
 208        p = (ide_settings_t **) &drive->settings;
 209
 210        while ((*p) && strcmp((*p)->name, name))
 211                p = &((*p)->next);
 212        if ((setting = (*p)) == NULL)
 213                return;
 214
 215        (*p) = setting->next;
 216
 217        kfree(setting->name);
 218        kfree(setting);
 219}
 220
 221/**
 222 *      auto_remove_settings    -       remove driver specific settings
 223 *      @drive: drive
 224 *
 225 *      Automatically remove all the driver specific settings for this
 226 *      drive. This function may not be called from IRQ context. The
 227 *      caller must hold ide_setting_mtx.
 228 */
 229
 230static void auto_remove_settings (ide_drive_t *drive)
 231{
 232        ide_settings_t *setting;
 233repeat:
 234        setting = drive->settings;
 235        while (setting) {
 236                if (setting->auto_remove) {
 237                        __ide_remove_setting(drive, setting->name);
 238                        goto repeat;
 239                }
 240                setting = setting->next;
 241        }
 242}
 243
 244/**
 245 *      ide_find_setting_by_name        -       find a drive specific setting
 246 *      @drive: drive to scan
 247 *      @name: setting name
 248 *
 249 *      Scan's the device setting table for a matching entry and returns
 250 *      this or NULL if no entry is found. The caller must hold the
 251 *      setting semaphore
 252 */
 253
 254static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
 255{
 256        ide_settings_t *setting = drive->settings;
 257
 258        while (setting) {
 259                if (strcmp(setting->name, name) == 0)
 260                        break;
 261                setting = setting->next;
 262        }
 263        return setting;
 264}
 265
 266/**
 267 *      ide_read_setting        -       read an IDE setting
 268 *      @drive: drive to read from
 269 *      @setting: drive setting
 270 *
 271 *      Read a drive setting and return the value. The caller
 272 *      must hold the ide_setting_mtx when making this call.
 273 *
 274 *      BUGS: the data return and error are the same return value
 275 *      so an error -EINVAL and true return of the same value cannot
 276 *      be told apart
 277 */
 278
 279static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
 280{
 281        int             val = -EINVAL;
 282        unsigned long   flags;
 283
 284        if ((setting->rw & SETTING_READ)) {
 285                spin_lock_irqsave(&ide_lock, flags);
 286                switch(setting->data_type) {
 287                        case TYPE_BYTE:
 288                                val = *((u8 *) setting->data);
 289                                break;
 290                        case TYPE_SHORT:
 291                                val = *((u16 *) setting->data);
 292                                break;
 293                        case TYPE_INT:
 294                                val = *((u32 *) setting->data);
 295                                break;
 296                }
 297                spin_unlock_irqrestore(&ide_lock, flags);
 298        }
 299        return val;
 300}
 301
 302/**
 303 *      ide_write_setting       -       read an IDE setting
 304 *      @drive: drive to read from
 305 *      @setting: drive setting
 306 *      @val: value
 307 *
 308 *      Write a drive setting if it is possible. The caller
 309 *      must hold the ide_setting_mtx when making this call.
 310 *
 311 *      BUGS: the data return and error are the same return value
 312 *      so an error -EINVAL and true return of the same value cannot
 313 *      be told apart
 314 *
 315 *      FIXME:  This should be changed to enqueue a special request
 316 *      to the driver to change settings, and then wait on a sema for completion.
 317 *      The current scheme of polling is kludgy, though safe enough.
 318 */
 319
 320static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
 321{
 322        if (!capable(CAP_SYS_ADMIN))
 323                return -EACCES;
 324        if (setting->set)
 325                return setting->set(drive, val);
 326        if (!(setting->rw & SETTING_WRITE))
 327                return -EPERM;
 328        if (val < setting->min || val > setting->max)
 329                return -EINVAL;
 330        if (ide_spin_wait_hwgroup(drive))
 331                return -EBUSY;
 332        switch (setting->data_type) {
 333                case TYPE_BYTE:
 334                        *((u8 *) setting->data) = val;
 335                        break;
 336                case TYPE_SHORT:
 337                        *((u16 *) setting->data) = val;
 338                        break;
 339                case TYPE_INT:
 340                        *((u32 *) setting->data) = val;
 341                        break;
 342        }
 343        spin_unlock_irq(&ide_lock);
 344        return 0;
 345}
 346
 347static int set_xfer_rate (ide_drive_t *drive, int arg)
 348{
 349        int err;
 350
 351        if (arg < 0 || arg > 70)
 352                return -EINVAL;
 353
 354        err = ide_wait_cmd(drive,
 355                        WIN_SETFEATURES, (u8) arg,
 356                        SETFEATURES_XFER, 0, NULL);
 357
 358        if (!err && arg) {
 359                ide_set_xfer_rate(drive, (u8) arg);
 360                ide_driveid_update(drive);
 361        }
 362        return err;
 363}
 364
 365/**
 366 *      ide_add_generic_settings        -       generic ide settings
 367 *      @drive: drive being configured
 368 *
 369 *      Add the generic parts of the system settings to the /proc files.
 370 *      The caller must not be holding the ide_setting_mtx.
 371 */
 372
 373void ide_add_generic_settings (ide_drive_t *drive)
 374{
 375/*
 376 *                        drive         setting name            read/write access                               data type       min     max                             mul_factor      div_factor      data pointer                    set function
 377 */
 378        __ide_add_setting(drive,        "io_32bit",             drive->no_io_32bit ? SETTING_READ : SETTING_RW, TYPE_BYTE,      0,      1 + (SUPPORT_VLB_SYNC << 1),    1,              1,              &drive->io_32bit,               set_io_32bit,   0);
 379        __ide_add_setting(drive,        "keepsettings",         SETTING_RW,                                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->keep_settings,          NULL,           0);
 380        __ide_add_setting(drive,        "nice1",                SETTING_RW,                                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->nice1,                  NULL,           0);
 381        __ide_add_setting(drive,        "pio_mode",             SETTING_WRITE,                                  TYPE_BYTE,      0,      255,                            1,              1,              NULL,                           set_pio_mode,   0);
 382        __ide_add_setting(drive,        "unmaskirq",            drive->no_unmask ? SETTING_READ : SETTING_RW,   TYPE_BYTE,      0,      1,                              1,              1,              &drive->unmask,                 NULL,           0);
 383        __ide_add_setting(drive,        "using_dma",            SETTING_RW,                                     TYPE_BYTE,      0,      1,                              1,              1,              &drive->using_dma,              set_using_dma,  0);
 384        __ide_add_setting(drive,        "init_speed",           SETTING_RW,                                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->init_speed,             NULL,           0);
 385        __ide_add_setting(drive,        "current_speed",        SETTING_RW,                                     TYPE_BYTE,      0,      70,                             1,              1,              &drive->current_speed,          set_xfer_rate,  0);
 386        __ide_add_setting(drive,        "number",               SETTING_RW,                                     TYPE_BYTE,      0,      3,                              1,              1,              &drive->dn,                     NULL,           0);
 387}
 388
 389static void proc_ide_settings_warn(void)
 390{
 391        static int warned = 0;
 392
 393        if (warned)
 394                return;
 395
 396        printk(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is "
 397                            "obsolete, and will be removed soon!\n");
 398        warned = 1;
 399}
 400
 401static int proc_ide_read_settings
 402        (char *page, char **start, off_t off, int count, int *eof, void *data)
 403{
 404        ide_drive_t     *drive = (ide_drive_t *) data;
 405        ide_settings_t  *setting = (ide_settings_t *) drive->settings;
 406        char            *out = page;
 407        int             len, rc, mul_factor, div_factor;
 408
 409        proc_ide_settings_warn();
 410
 411        mutex_lock(&ide_setting_mtx);
 412        out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
 413        out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
 414        while(setting) {
 415                mul_factor = setting->mul_factor;
 416                div_factor = setting->div_factor;
 417                out += sprintf(out, "%-24s", setting->name);
 418                if ((rc = ide_read_setting(drive, setting)) >= 0)
 419                        out += sprintf(out, "%-16d", rc * mul_factor / div_factor);
 420                else
 421                        out += sprintf(out, "%-16s", "write-only");
 422                out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
 423                if (setting->rw & SETTING_READ)
 424                        out += sprintf(out, "r");
 425                if (setting->rw & SETTING_WRITE)
 426                        out += sprintf(out, "w");
 427                out += sprintf(out, "\n");
 428                setting = setting->next;
 429        }
 430        len = out - page;
 431        mutex_unlock(&ide_setting_mtx);
 432        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 433}
 434
 435#define MAX_LEN 30
 436
 437static int proc_ide_write_settings(struct file *file, const char __user *buffer,
 438                                   unsigned long count, void *data)
 439{
 440        ide_drive_t     *drive = (ide_drive_t *) data;
 441        char            name[MAX_LEN + 1];
 442        int             for_real = 0;
 443        unsigned long   n;
 444        ide_settings_t  *setting;
 445        char *buf, *s;
 446
 447        if (!capable(CAP_SYS_ADMIN))
 448                return -EACCES;
 449
 450        proc_ide_settings_warn();
 451
 452        if (count >= PAGE_SIZE)
 453                return -EINVAL;
 454
 455        s = buf = (char *)__get_free_page(GFP_USER);
 456        if (!buf)
 457                return -ENOMEM;
 458
 459        if (copy_from_user(buf, buffer, count)) {
 460                free_page((unsigned long)buf);
 461                return -EFAULT;
 462        }
 463
 464        buf[count] = '\0';
 465
 466        /*
 467         * Skip over leading whitespace
 468         */
 469        while (count && isspace(*s)) {
 470                --count;
 471                ++s;
 472        }
 473        /*
 474         * Do one full pass to verify all parameters,
 475         * then do another to actually write the new settings.
 476         */
 477        do {
 478                char *p = s;
 479                n = count;
 480                while (n > 0) {
 481                        unsigned val;
 482                        char *q = p;
 483
 484                        while (n > 0 && *p != ':') {
 485                                --n;
 486                                p++;
 487                        }
 488                        if (*p != ':')
 489                                goto parse_error;
 490                        if (p - q > MAX_LEN)
 491                                goto parse_error;
 492                        memcpy(name, q, p - q);
 493                        name[p - q] = 0;
 494
 495                        if (n > 0) {
 496                                --n;
 497                                p++;
 498                        } else
 499                                goto parse_error;
 500
 501                        val = simple_strtoul(p, &q, 10);
 502                        n -= q - p;
 503                        p = q;
 504                        if (n > 0 && !isspace(*p))
 505                                goto parse_error;
 506                        while (n > 0 && isspace(*p)) {
 507                                --n;
 508                                ++p;
 509                        }
 510
 511                        mutex_lock(&ide_setting_mtx);
 512                        setting = ide_find_setting_by_name(drive, name);
 513                        if (!setting)
 514                        {
 515                                mutex_unlock(&ide_setting_mtx);
 516                                goto parse_error;
 517                        }
 518                        if (for_real)
 519                                ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
 520                        mutex_unlock(&ide_setting_mtx);
 521                }
 522        } while (!for_real++);
 523        free_page((unsigned long)buf);
 524        return count;
 525parse_error:
 526        free_page((unsigned long)buf);
 527        printk("proc_ide_write_settings(): parse error\n");
 528        return -EINVAL;
 529}
 530
 531int proc_ide_read_capacity
 532        (char *page, char **start, off_t off, int count, int *eof, void *data)
 533{
 534        int len = sprintf(page,"%llu\n", (long long)0x7fffffff);
 535        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 536}
 537
 538EXPORT_SYMBOL_GPL(proc_ide_read_capacity);
 539
 540int proc_ide_read_geometry
 541        (char *page, char **start, off_t off, int count, int *eof, void *data)
 542{
 543        ide_drive_t     *drive = (ide_drive_t *) data;
 544        char            *out = page;
 545        int             len;
 546
 547        out += sprintf(out,"physical     %d/%d/%d\n",
 548                        drive->cyl, drive->head, drive->sect);
 549        out += sprintf(out,"logical      %d/%d/%d\n",
 550                        drive->bios_cyl, drive->bios_head, drive->bios_sect);
 551
 552        len = out - page;
 553        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 554}
 555
 556EXPORT_SYMBOL(proc_ide_read_geometry);
 557
 558static int proc_ide_read_dmodel
 559        (char *page, char **start, off_t off, int count, int *eof, void *data)
 560{
 561        ide_drive_t     *drive = (ide_drive_t *) data;
 562        struct hd_driveid *id = drive->id;
 563        int             len;
 564
 565        len = sprintf(page, "%.40s\n",
 566                (id && id->model[0]) ? (char *)id->model : "(none)");
 567        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 568}
 569
 570static int proc_ide_read_driver
 571        (char *page, char **start, off_t off, int count, int *eof, void *data)
 572{
 573        ide_drive_t     *drive = (ide_drive_t *) data;
 574        struct device   *dev = &drive->gendev;
 575        ide_driver_t    *ide_drv;
 576        int             len;
 577
 578        if (dev->driver) {
 579                ide_drv = container_of(dev->driver, ide_driver_t, gen_driver);
 580                len = sprintf(page, "%s version %s\n",
 581                                dev->driver->name, ide_drv->version);
 582        } else
 583                len = sprintf(page, "ide-default version 0.9.newide\n");
 584        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 585}
 586
 587static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
 588{
 589        struct device *dev = &drive->gendev;
 590        int ret = 1;
 591        int err;
 592
 593        device_release_driver(dev);
 594        /* FIXME: device can still be in use by previous driver */
 595        strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
 596        err = device_attach(dev);
 597        if (err < 0)
 598                printk(KERN_WARNING "IDE: %s: device_attach error: %d\n",
 599                        __FUNCTION__, err);
 600        drive->driver_req[0] = 0;
 601        if (dev->driver == NULL) {
 602                err = device_attach(dev);
 603                if (err < 0)
 604                        printk(KERN_WARNING
 605                                "IDE: %s: device_attach(2) error: %d\n",
 606                                __FUNCTION__, err);
 607        }
 608        if (dev->driver && !strcmp(dev->driver->name, driver))
 609                ret = 0;
 610
 611        return ret;
 612}
 613
 614static int proc_ide_write_driver
 615        (struct file *file, const char __user *buffer, unsigned long count, void *data)
 616{
 617        ide_drive_t     *drive = (ide_drive_t *) data;
 618        char name[32];
 619
 620        if (!capable(CAP_SYS_ADMIN))
 621                return -EACCES;
 622        if (count > 31)
 623                count = 31;
 624        if (copy_from_user(name, buffer, count))
 625                return -EFAULT;
 626        name[count] = '\0';
 627        if (ide_replace_subdriver(drive, name))
 628                return -EINVAL;
 629        return count;
 630}
 631
 632static int proc_ide_read_media
 633        (char *page, char **start, off_t off, int count, int *eof, void *data)
 634{
 635        ide_drive_t     *drive = (ide_drive_t *) data;
 636        const char      *media;
 637        int             len;
 638
 639        switch (drive->media) {
 640                case ide_disk:  media = "disk\n";
 641                                break;
 642                case ide_cdrom: media = "cdrom\n";
 643                                break;
 644                case ide_tape:  media = "tape\n";
 645                                break;
 646                case ide_floppy:media = "floppy\n";
 647                                break;
 648                case ide_optical:media = "optical\n";
 649                                break;
 650                default:        media = "UNKNOWN\n";
 651                                break;
 652        }
 653        strcpy(page,media);
 654        len = strlen(media);
 655        PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 656}
 657
 658static ide_proc_entry_t generic_drive_entries[] = {
 659        { "driver",     S_IFREG|S_IRUGO,        proc_ide_read_driver,   proc_ide_write_driver },
 660        { "identify",   S_IFREG|S_IRUSR,        proc_ide_read_identify, NULL },
 661        { "media",      S_IFREG|S_IRUGO,        proc_ide_read_media,    NULL },
 662        { "model",      S_IFREG|S_IRUGO,        proc_ide_read_dmodel,   NULL },
 663        { "settings",   S_IFREG|S_IRUSR|S_IWUSR,proc_ide_read_settings, proc_ide_write_settings },
 664        { NULL, 0, NULL, NULL }
 665};
 666
 667static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
 668{
 669        struct proc_dir_entry *ent;
 670
 671        if (!dir || !p)
 672                return;
 673        while (p->name != NULL) {
 674                ent = create_proc_entry(p->name, p->mode, dir);
 675                if (!ent) return;
 676                ent->data = data;
 677                ent->read_proc = p->read_proc;
 678                ent->write_proc = p->write_proc;
 679                p++;
 680        }
 681}
 682
 683static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
 684{
 685        if (!dir || !p)
 686                return;
 687        while (p->name != NULL) {
 688                remove_proc_entry(p->name, dir);
 689                p++;
 690        }
 691}
 692
 693void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
 694{
 695        ide_add_proc_entries(drive->proc, driver->proc, drive);
 696}
 697
 698EXPORT_SYMBOL(ide_proc_register_driver);
 699
 700/**
 701 *      ide_proc_unregister_driver      -       remove driver specific data
 702 *      @drive: drive
 703 *      @driver: driver
 704 *
 705 *      Clean up the driver specific /proc files and IDE settings
 706 *      for a given drive.
 707 *
 708 *      Takes ide_setting_mtx and ide_lock.
 709 *      Caller must hold none of the locks.
 710 */
 711
 712void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
 713{
 714        unsigned long flags;
 715
 716        ide_remove_proc_entries(drive->proc, driver->proc);
 717
 718        mutex_lock(&ide_setting_mtx);
 719        spin_lock_irqsave(&ide_lock, flags);
 720        /*
 721         * ide_setting_mtx protects the settings list
 722         * ide_lock protects the use of settings
 723         *
 724         * so we need to hold both, ide_settings_sem because we want to
 725         * modify the settings list, and ide_lock because we cannot take
 726         * a setting out that is being used.
 727         *
 728         * OTOH both ide_{read,write}_setting are only ever used under
 729         * ide_setting_mtx.
 730         */
 731        auto_remove_settings(drive);
 732        spin_unlock_irqrestore(&ide_lock, flags);
 733        mutex_unlock(&ide_setting_mtx);
 734}
 735
 736EXPORT_SYMBOL(ide_proc_unregister_driver);
 737
 738static void create_proc_ide_drives(ide_hwif_t *hwif)
 739{
 740        int     d;
 741        struct proc_dir_entry *ent;
 742        struct proc_dir_entry *parent = hwif->proc;
 743        char name[64];
 744
 745        for (d = 0; d < MAX_DRIVES; d++) {
 746                ide_drive_t *drive = &hwif->drives[d];
 747
 748                if (!drive->present)
 749                        continue;
 750                if (drive->proc)
 751                        continue;
 752
 753                drive->proc = proc_mkdir(drive->name, parent);
 754                if (drive->proc)
 755                        ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
 756                sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
 757                ent = proc_symlink(drive->name, proc_ide_root, name);
 758                if (!ent) return;
 759        }
 760}
 761
 762static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 763{
 764        if (drive->proc) {
 765                ide_remove_proc_entries(drive->proc, generic_drive_entries);
 766                remove_proc_entry(drive->name, proc_ide_root);
 767                remove_proc_entry(drive->name, hwif->proc);
 768                drive->proc = NULL;
 769        }
 770}
 771
 772static void destroy_proc_ide_drives(ide_hwif_t *hwif)
 773{
 774        int     d;
 775
 776        for (d = 0; d < MAX_DRIVES; d++) {
 777                ide_drive_t *drive = &hwif->drives[d];
 778                if (drive->proc)
 779                        destroy_proc_ide_device(hwif, drive);
 780        }
 781}
 782
 783static ide_proc_entry_t hwif_entries[] = {
 784        { "channel",    S_IFREG|S_IRUGO,        proc_ide_read_channel,  NULL },
 785        { "mate",       S_IFREG|S_IRUGO,        proc_ide_read_mate,     NULL },
 786        { "model",      S_IFREG|S_IRUGO,        proc_ide_read_imodel,   NULL },
 787        { NULL, 0, NULL, NULL }
 788};
 789
 790void ide_proc_register_port(ide_hwif_t *hwif)
 791{
 792        if (!hwif->present)
 793                return;
 794
 795        if (!hwif->proc) {
 796                hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
 797
 798                if (!hwif->proc)
 799                        return;
 800
 801                ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
 802        }
 803
 804        create_proc_ide_drives(hwif);
 805}
 806
 807#ifdef CONFIG_BLK_DEV_IDEPCI
 808void ide_pci_create_host_proc(const char *name, get_info_t *get_info)
 809{
 810        create_proc_info_entry(name, 0, proc_ide_root, get_info);
 811}
 812
 813EXPORT_SYMBOL_GPL(ide_pci_create_host_proc);
 814#endif
 815
 816void ide_proc_unregister_port(ide_hwif_t *hwif)
 817{
 818        if (hwif->proc) {
 819                destroy_proc_ide_drives(hwif);
 820                ide_remove_proc_entries(hwif->proc, hwif_entries);
 821                remove_proc_entry(hwif->name, proc_ide_root);
 822                hwif->proc = NULL;
 823        }
 824}
 825
 826static int proc_print_driver(struct device_driver *drv, void *data)
 827{
 828        ide_driver_t *ide_drv = container_of(drv, ide_driver_t, gen_driver);
 829        struct seq_file *s = data;
 830
 831        seq_printf(s, "%s version %s\n", drv->name, ide_drv->version);
 832
 833        return 0;
 834}
 835
 836static int ide_drivers_show(struct seq_file *s, void *p)
 837{
 838        int err;
 839
 840        err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
 841        if (err < 0)
 842                printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n",
 843                        __FUNCTION__, err);
 844        return 0;
 845}
 846
 847static int ide_drivers_open(struct inode *inode, struct file *file)
 848{
 849        return single_open(file, &ide_drivers_show, NULL);
 850}
 851
 852static const struct file_operations ide_drivers_operations = {
 853        .open           = ide_drivers_open,
 854        .read           = seq_read,
 855        .llseek         = seq_lseek,
 856        .release        = single_release,
 857};
 858
 859void proc_ide_create(void)
 860{
 861        struct proc_dir_entry *entry;
 862
 863        proc_ide_root = proc_mkdir("ide", NULL);
 864
 865        if (!proc_ide_root)
 866                return;
 867
 868        entry = create_proc_entry("drivers", 0, proc_ide_root);
 869        if (entry)
 870                entry->proc_fops = &ide_drivers_operations;
 871}
 872
 873void proc_ide_destroy(void)
 874{
 875        remove_proc_entry("drivers", proc_ide_root);
 876        remove_proc_entry("ide", NULL);
 877}
 878
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.