diff options
-rw-r--r-- | drivers/ide/ide-cd.c | 15 | ||||
-rw-r--r-- | drivers/ide/ide-disk.c | 87 | ||||
-rw-r--r-- | drivers/ide/ide-floppy.c | 35 | ||||
-rw-r--r-- | drivers/ide/ide-probe.c | 2 | ||||
-rw-r--r-- | drivers/ide/ide-proc.c | 279 | ||||
-rw-r--r-- | drivers/ide/ide-tape.c | 74 | ||||
-rw-r--r-- | drivers/ide/ide.c | 21 | ||||
-rw-r--r-- | drivers/scsi/ide-scsi.c | 52 | ||||
-rw-r--r-- | include/linux/ide.h | 110 |
9 files changed, 340 insertions, 335 deletions
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 34a1aeaa15dd..1f5652326489 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c | |||
@@ -1809,13 +1809,12 @@ static ide_proc_entry_t idecd_proc[] = { | |||
1809 | { NULL, 0, NULL, NULL } | 1809 | { NULL, 0, NULL, NULL } |
1810 | }; | 1810 | }; |
1811 | 1811 | ||
1812 | static void ide_cdrom_add_settings(ide_drive_t *drive) | 1812 | ide_devset_rw(dsc_overlap, 0, 1, dsc_overlap); |
1813 | { | 1813 | |
1814 | ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, | 1814 | static const struct ide_devset *idecd_settings[] = { |
1815 | &drive->dsc_overlap, NULL); | 1815 | &ide_devset_dsc_overlap, |
1816 | } | 1816 | NULL |
1817 | #else | 1817 | }; |
1818 | static inline void ide_cdrom_add_settings(ide_drive_t *drive) { ; } | ||
1819 | #endif | 1818 | #endif |
1820 | 1819 | ||
1821 | static const struct cd_list_entry ide_cd_quirks_list[] = { | 1820 | static const struct cd_list_entry ide_cd_quirks_list[] = { |
@@ -1926,7 +1925,6 @@ static int ide_cdrom_setup(ide_drive_t *drive) | |||
1926 | } | 1925 | } |
1927 | 1926 | ||
1928 | ide_proc_register_driver(drive, cd->driver); | 1927 | ide_proc_register_driver(drive, cd->driver); |
1929 | ide_cdrom_add_settings(drive); | ||
1930 | return 0; | 1928 | return 0; |
1931 | } | 1929 | } |
1932 | 1930 | ||
@@ -1977,6 +1975,7 @@ static ide_driver_t ide_cdrom_driver = { | |||
1977 | .error = __ide_error, | 1975 | .error = __ide_error, |
1978 | #ifdef CONFIG_IDE_PROC_FS | 1976 | #ifdef CONFIG_IDE_PROC_FS |
1979 | .proc = idecd_proc, | 1977 | .proc = idecd_proc, |
1978 | .settings = idecd_settings, | ||
1980 | #endif | 1979 | #endif |
1981 | }; | 1980 | }; |
1982 | 1981 | ||
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 7a15907dce1d..2e43ae15fb1b 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c | |||
@@ -599,6 +599,8 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) | |||
599 | rq->special = task; | 599 | rq->special = task; |
600 | } | 600 | } |
601 | 601 | ||
602 | ide_devset_get(multcount, mult_count); | ||
603 | |||
602 | /* | 604 | /* |
603 | * This is tightly woven into the driver->do_special can not touch. | 605 | * This is tightly woven into the driver->do_special can not touch. |
604 | * DON'T do it again until a total personality rewrite is committed. | 606 | * DON'T do it again until a total personality rewrite is committed. |
@@ -625,6 +627,8 @@ static int set_multcount(ide_drive_t *drive, int arg) | |||
625 | return (drive->mult_count == arg) ? 0 : -EIO; | 627 | return (drive->mult_count == arg) ? 0 : -EIO; |
626 | } | 628 | } |
627 | 629 | ||
630 | ide_devset_get(nowerr, nowerr); | ||
631 | |||
628 | static int set_nowerr(ide_drive_t *drive, int arg) | 632 | static int set_nowerr(ide_drive_t *drive, int arg) |
629 | { | 633 | { |
630 | if (arg < 0 || arg > 1) | 634 | if (arg < 0 || arg > 1) |
@@ -673,7 +677,9 @@ static void update_ordered(ide_drive_t *drive) | |||
673 | blk_queue_ordered(drive->queue, ordered, prep_fn); | 677 | blk_queue_ordered(drive->queue, ordered, prep_fn); |
674 | } | 678 | } |
675 | 679 | ||
676 | static int write_cache(ide_drive_t *drive, int arg) | 680 | ide_devset_get(wcache, wcache); |
681 | |||
682 | static int set_wcache(ide_drive_t *drive, int arg) | ||
677 | { | 683 | { |
678 | ide_task_t args; | 684 | ide_task_t args; |
679 | int err = 1; | 685 | int err = 1; |
@@ -710,6 +716,8 @@ static int do_idedisk_flushcache(ide_drive_t *drive) | |||
710 | return ide_no_data_taskfile(drive, &args); | 716 | return ide_no_data_taskfile(drive, &args); |
711 | } | 717 | } |
712 | 718 | ||
719 | ide_devset_get(acoustic, acoustic); | ||
720 | |||
713 | static int set_acoustic(ide_drive_t *drive, int arg) | 721 | static int set_acoustic(ide_drive_t *drive, int arg) |
714 | { | 722 | { |
715 | ide_task_t args; | 723 | ide_task_t args; |
@@ -727,6 +735,8 @@ static int set_acoustic(ide_drive_t *drive, int arg) | |||
727 | return 0; | 735 | return 0; |
728 | } | 736 | } |
729 | 737 | ||
738 | ide_devset_get(lba_addressing, addressing); | ||
739 | |||
730 | /* | 740 | /* |
731 | * drive->addressing: | 741 | * drive->addressing: |
732 | * 0: 28-bit | 742 | * 0: 28-bit |
@@ -750,33 +760,33 @@ static int set_lba_addressing(ide_drive_t *drive, int arg) | |||
750 | } | 760 | } |
751 | 761 | ||
752 | #ifdef CONFIG_IDE_PROC_FS | 762 | #ifdef CONFIG_IDE_PROC_FS |
753 | static void idedisk_add_settings(ide_drive_t *drive) | 763 | ide_devset_rw_nolock(acoustic, 0, 254, acoustic); |
754 | { | 764 | ide_devset_rw_nolock(address, 0, 2, lba_addressing); |
755 | ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 65535, 1, 1, | 765 | ide_devset_rw_nolock(multcount, 0, 16, multcount); |
756 | &drive->bios_cyl, NULL); | 766 | ide_devset_rw_nolock(nowerr, 0, 1, nowerr); |
757 | ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, | 767 | ide_devset_rw_nolock(wcache, 0, 1, wcache); |
758 | &drive->bios_head, NULL); | 768 | |
759 | ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1, | 769 | ide_devset_rw(bios_cyl, 0, 65535, bios_cyl); |
760 | &drive->bios_sect, NULL); | 770 | ide_devset_rw(bios_head, 0, 255, bios_head); |
761 | ide_add_setting(drive, "address", SETTING_RW, TYPE_BYTE, 0, 2, 1, 1, | 771 | ide_devset_rw(bios_sect, 0, 63, bios_sect); |
762 | &drive->addressing, set_lba_addressing); | 772 | ide_devset_rw(failures, 0, 65535, failures); |
763 | ide_add_setting(drive, "multcount", SETTING_RW, TYPE_BYTE, 0, 16, 1, 1, | 773 | ide_devset_rw(lun, 0, 7, lun); |
764 | &drive->mult_count, set_multcount); | 774 | ide_devset_rw(max_failures, 0, 65535, max_failures); |
765 | ide_add_setting(drive, "nowerr", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, | 775 | |
766 | &drive->nowerr, set_nowerr); | 776 | static const struct ide_devset *idedisk_settings[] = { |
767 | ide_add_setting(drive, "lun", SETTING_RW, TYPE_INT, 0, 7, 1, 1, | 777 | &ide_devset_acoustic, |
768 | &drive->lun, NULL); | 778 | &ide_devset_address, |
769 | ide_add_setting(drive, "wcache", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, | 779 | &ide_devset_bios_cyl, |
770 | &drive->wcache, write_cache); | 780 | &ide_devset_bios_head, |
771 | ide_add_setting(drive, "acoustic", SETTING_RW, TYPE_BYTE, 0, 254, 1, 1, | 781 | &ide_devset_bios_sect, |
772 | &drive->acoustic, set_acoustic); | 782 | &ide_devset_failures, |
773 | ide_add_setting(drive, "failures", SETTING_RW, TYPE_INT, 0, 65535, 1, 1, | 783 | &ide_devset_lun, |
774 | &drive->failures, NULL); | 784 | &ide_devset_max_failures, |
775 | ide_add_setting(drive, "max_failures", SETTING_RW, TYPE_INT, 0, 65535, | 785 | &ide_devset_multcount, |
776 | 1, 1, &drive->max_failures, NULL); | 786 | &ide_devset_nowerr, |
777 | } | 787 | &ide_devset_wcache, |
778 | #else | 788 | NULL |
779 | static inline void idedisk_add_settings(ide_drive_t *drive) { ; } | 789 | }; |
780 | #endif | 790 | #endif |
781 | 791 | ||
782 | static void idedisk_setup(ide_drive_t *drive) | 792 | static void idedisk_setup(ide_drive_t *drive) |
@@ -788,7 +798,6 @@ static void idedisk_setup(ide_drive_t *drive) | |||
788 | unsigned long long capacity; | 798 | unsigned long long capacity; |
789 | 799 | ||
790 | ide_proc_register_driver(drive, idkp->driver); | 800 | ide_proc_register_driver(drive, idkp->driver); |
791 | idedisk_add_settings(drive); | ||
792 | 801 | ||
793 | if (drive->id_read == 0) | 802 | if (drive->id_read == 0) |
794 | return; | 803 | return; |
@@ -880,7 +889,7 @@ static void idedisk_setup(ide_drive_t *drive) | |||
880 | if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id)) | 889 | if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id)) |
881 | drive->wcache = 1; | 890 | drive->wcache = 1; |
882 | 891 | ||
883 | write_cache(drive, 1); | 892 | set_wcache(drive, 1); |
884 | } | 893 | } |
885 | 894 | ||
886 | static void ide_cacheflush_p(ide_drive_t *drive) | 895 | static void ide_cacheflush_p(ide_drive_t *drive) |
@@ -976,6 +985,7 @@ static ide_driver_t idedisk_driver = { | |||
976 | .error = __ide_error, | 985 | .error = __ide_error, |
977 | #ifdef CONFIG_IDE_PROC_FS | 986 | #ifdef CONFIG_IDE_PROC_FS |
978 | .proc = idedisk_proc, | 987 | .proc = idedisk_proc, |
988 | .settings = idedisk_settings, | ||
979 | #endif | 989 | #endif |
980 | }; | 990 | }; |
981 | 991 | ||
@@ -1056,19 +1066,18 @@ static int idedisk_ioctl(struct inode *inode, struct file *file, | |||
1056 | struct block_device *bdev = inode->i_bdev; | 1066 | struct block_device *bdev = inode->i_bdev; |
1057 | struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); | 1067 | struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); |
1058 | ide_drive_t *drive = idkp->drive; | 1068 | ide_drive_t *drive = idkp->drive; |
1059 | int err, (*setfunc)(ide_drive_t *, int); | 1069 | int err, (*getfunc)(ide_drive_t *), (*setfunc)(ide_drive_t *, int); |
1060 | u8 *val; | ||
1061 | 1070 | ||
1062 | switch (cmd) { | 1071 | switch (cmd) { |
1063 | case HDIO_GET_ADDRESS: val = &drive->addressing; goto read_val; | 1072 | case HDIO_GET_ADDRESS: getfunc = get_lba_addressing; goto read_val; |
1064 | case HDIO_GET_MULTCOUNT: val = &drive->mult_count; goto read_val; | 1073 | case HDIO_GET_MULTCOUNT: getfunc = get_multcount; goto read_val; |
1065 | case HDIO_GET_NOWERR: val = &drive->nowerr; goto read_val; | 1074 | case HDIO_GET_NOWERR: getfunc = get_nowerr; goto read_val; |
1066 | case HDIO_GET_WCACHE: val = &drive->wcache; goto read_val; | 1075 | case HDIO_GET_WCACHE: getfunc = get_wcache; goto read_val; |
1067 | case HDIO_GET_ACOUSTIC: val = &drive->acoustic; goto read_val; | 1076 | case HDIO_GET_ACOUSTIC: getfunc = get_acoustic; goto read_val; |
1068 | case HDIO_SET_ADDRESS: setfunc = set_lba_addressing; goto set_val; | 1077 | case HDIO_SET_ADDRESS: setfunc = set_lba_addressing; goto set_val; |
1069 | case HDIO_SET_MULTCOUNT: setfunc = set_multcount; goto set_val; | 1078 | case HDIO_SET_MULTCOUNT: setfunc = set_multcount; goto set_val; |
1070 | case HDIO_SET_NOWERR: setfunc = set_nowerr; goto set_val; | 1079 | case HDIO_SET_NOWERR: setfunc = set_nowerr; goto set_val; |
1071 | case HDIO_SET_WCACHE: setfunc = write_cache; goto set_val; | 1080 | case HDIO_SET_WCACHE: setfunc = set_wcache; goto set_val; |
1072 | case HDIO_SET_ACOUSTIC: setfunc = set_acoustic; goto set_val; | 1081 | case HDIO_SET_ACOUSTIC: setfunc = set_acoustic; goto set_val; |
1073 | } | 1082 | } |
1074 | 1083 | ||
@@ -1077,7 +1086,7 @@ static int idedisk_ioctl(struct inode *inode, struct file *file, | |||
1077 | read_val: | 1086 | read_val: |
1078 | mutex_lock(&ide_setting_mtx); | 1087 | mutex_lock(&ide_setting_mtx); |
1079 | spin_lock_irqsave(&ide_lock, flags); | 1088 | spin_lock_irqsave(&ide_lock, flags); |
1080 | err = *val; | 1089 | err = getfunc(drive); |
1081 | spin_unlock_irqrestore(&ide_lock, flags); | 1090 | spin_unlock_irqrestore(&ide_lock, flags); |
1082 | mutex_unlock(&ide_setting_mtx); | 1091 | mutex_unlock(&ide_setting_mtx); |
1083 | return err >= 0 ? put_user(err, (long __user *)arg) : err; | 1092 | return err >= 0 ? put_user(err, (long __user *)arg) : err; |
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 597459c81d5f..673644fdb6f2 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c | |||
@@ -1007,21 +1007,32 @@ static int idefloppy_identify_device(ide_drive_t *drive, u16 *id) | |||
1007 | } | 1007 | } |
1008 | 1008 | ||
1009 | #ifdef CONFIG_IDE_PROC_FS | 1009 | #ifdef CONFIG_IDE_PROC_FS |
1010 | static void idefloppy_add_settings(ide_drive_t *drive) | 1010 | ide_devset_rw(bios_cyl, 0, 1023, bios_cyl); |
1011 | ide_devset_rw(bios_head, 0, 255, bios_head); | ||
1012 | ide_devset_rw(bios_sect, 0, 63, bios_sect); | ||
1013 | |||
1014 | static int get_ticks(ide_drive_t *drive) | ||
1011 | { | 1015 | { |
1012 | idefloppy_floppy_t *floppy = drive->driver_data; | 1016 | idefloppy_floppy_t *floppy = drive->driver_data; |
1017 | return floppy->ticks; | ||
1018 | } | ||
1013 | 1019 | ||
1014 | ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 1023, 1, 1, | 1020 | static int set_ticks(ide_drive_t *drive, int arg) |
1015 | &drive->bios_cyl, NULL); | 1021 | { |
1016 | ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, | 1022 | idefloppy_floppy_t *floppy = drive->driver_data; |
1017 | &drive->bios_head, NULL); | 1023 | floppy->ticks = arg; |
1018 | ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1, | 1024 | return 0; |
1019 | &drive->bios_sect, NULL); | ||
1020 | ide_add_setting(drive, "ticks", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, | ||
1021 | &floppy->ticks, NULL); | ||
1022 | } | 1025 | } |
1023 | #else | 1026 | |
1024 | static inline void idefloppy_add_settings(ide_drive_t *drive) { ; } | 1027 | IDE_DEVSET(ticks, S_RW, 0, 255, get_ticks, set_ticks); |
1028 | |||
1029 | static const struct ide_devset *idefloppy_settings[] = { | ||
1030 | &ide_devset_bios_cyl, | ||
1031 | &ide_devset_bios_head, | ||
1032 | &ide_devset_bios_sect, | ||
1033 | &ide_devset_ticks, | ||
1034 | NULL | ||
1035 | }; | ||
1025 | #endif | 1036 | #endif |
1026 | 1037 | ||
1027 | static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy) | 1038 | static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy) |
@@ -1063,7 +1074,6 @@ static void idefloppy_setup(ide_drive_t *drive, idefloppy_floppy_t *floppy) | |||
1063 | (void) ide_floppy_get_capacity(drive); | 1074 | (void) ide_floppy_get_capacity(drive); |
1064 | 1075 | ||
1065 | ide_proc_register_driver(drive, floppy->driver); | 1076 | ide_proc_register_driver(drive, floppy->driver); |
1066 | idefloppy_add_settings(drive); | ||
1067 | } | 1077 | } |
1068 | 1078 | ||
1069 | static void ide_floppy_remove(ide_drive_t *drive) | 1079 | static void ide_floppy_remove(ide_drive_t *drive) |
@@ -1126,6 +1136,7 @@ static ide_driver_t idefloppy_driver = { | |||
1126 | .error = __ide_error, | 1136 | .error = __ide_error, |
1127 | #ifdef CONFIG_IDE_PROC_FS | 1137 | #ifdef CONFIG_IDE_PROC_FS |
1128 | .proc = idefloppy_proc, | 1138 | .proc = idefloppy_proc, |
1139 | .settings = idefloppy_settings, | ||
1129 | #endif | 1140 | #endif |
1130 | }; | 1141 | }; |
1131 | 1142 | ||
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 9926e12783bb..62f7e1ef10c1 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c | |||
@@ -1332,8 +1332,6 @@ static void hwif_register_devices(ide_hwif_t *hwif) | |||
1332 | if (!drive->present) | 1332 | if (!drive->present) |
1333 | continue; | 1333 | continue; |
1334 | 1334 | ||
1335 | ide_add_generic_settings(drive); | ||
1336 | |||
1337 | snprintf(dev->bus_id, BUS_ID_SIZE, "%u.%u", hwif->index, i); | 1335 | snprintf(dev->bus_id, BUS_ID_SIZE, "%u.%u", hwif->index, i); |
1338 | dev->parent = &hwif->gendev; | 1336 | dev->parent = &hwif->gendev; |
1339 | dev->bus = &ide_bus_type; | 1337 | dev->bus = &ide_bus_type; |
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 7a64aedfa648..5634b3971d21 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c | |||
@@ -114,140 +114,24 @@ static int proc_ide_read_identify | |||
114 | } | 114 | } |
115 | 115 | ||
116 | /** | 116 | /** |
117 | * __ide_add_setting - add an ide setting option | 117 | * ide_find_setting - find a specific setting |
118 | * @drive: drive to use | 118 | * @st: setting table pointer |
119 | * @name: setting name | 119 | * @name: setting name |
120 | * @rw: true if the function is read write | ||
121 | * @data_type: type of data | ||
122 | * @min: range minimum | ||
123 | * @max: range maximum | ||
124 | * @mul_factor: multiplication scale | ||
125 | * @div_factor: divison scale | ||
126 | * @data: private data field | ||
127 | * @set: setting | ||
128 | * @auto_remove: setting auto removal flag | ||
129 | * | 120 | * |
130 | * Removes the setting named from the device if it is present. | 121 | * Scan's the setting table for a matching entry and returns |
131 | * The function takes the settings_lock to protect against | ||
132 | * parallel changes. This function must not be called from IRQ | ||
133 | * context. Returns 0 on success or -1 on failure. | ||
134 | * | ||
135 | * BUGS: This code is seriously over-engineered. There is also | ||
136 | * magic about how the driver specific features are setup. If | ||
137 | * a driver is attached we assume the driver settings are auto | ||
138 | * remove. | ||
139 | */ | ||
140 | |||
141 | static 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) | ||
142 | { | ||
143 | ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; | ||
144 | |||
145 | mutex_lock(&ide_setting_mtx); | ||
146 | while ((*p) && strcmp((*p)->name, name) < 0) | ||
147 | p = &((*p)->next); | ||
148 | if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL) | ||
149 | goto abort; | ||
150 | if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL) | ||
151 | goto abort; | ||
152 | strcpy(setting->name, name); | ||
153 | setting->rw = rw; | ||
154 | setting->data_type = data_type; | ||
155 | setting->min = min; | ||
156 | setting->max = max; | ||
157 | setting->mul_factor = mul_factor; | ||
158 | setting->div_factor = div_factor; | ||
159 | setting->data = data; | ||
160 | setting->set = set; | ||
161 | |||
162 | setting->next = *p; | ||
163 | if (auto_remove) | ||
164 | setting->auto_remove = 1; | ||
165 | *p = setting; | ||
166 | mutex_unlock(&ide_setting_mtx); | ||
167 | return 0; | ||
168 | abort: | ||
169 | mutex_unlock(&ide_setting_mtx); | ||
170 | kfree(setting); | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | 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) | ||
175 | { | ||
176 | return __ide_add_setting(drive, name, rw, data_type, min, max, mul_factor, div_factor, data, set, 1); | ||
177 | } | ||
178 | |||
179 | EXPORT_SYMBOL(ide_add_setting); | ||
180 | |||
181 | /** | ||
182 | * __ide_remove_setting - remove an ide setting option | ||
183 | * @drive: drive to use | ||
184 | * @name: setting name | ||
185 | * | ||
186 | * Removes the setting named from the device if it is present. | ||
187 | * The caller must hold the setting semaphore. | ||
188 | */ | ||
189 | |||
190 | static void __ide_remove_setting(ide_drive_t *drive, char *name) | ||
191 | { | ||
192 | ide_settings_t **p, *setting; | ||
193 | |||
194 | p = (ide_settings_t **) &drive->settings; | ||
195 | |||
196 | while ((*p) && strcmp((*p)->name, name)) | ||
197 | p = &((*p)->next); | ||
198 | setting = (*p); | ||
199 | if (setting == NULL) | ||
200 | return; | ||
201 | |||
202 | (*p) = setting->next; | ||
203 | |||
204 | kfree(setting->name); | ||
205 | kfree(setting); | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * auto_remove_settings - remove driver specific settings | ||
210 | * @drive: drive | ||
211 | * | ||
212 | * Automatically remove all the driver specific settings for this | ||
213 | * drive. This function may not be called from IRQ context. The | ||
214 | * caller must hold ide_setting_mtx. | ||
215 | */ | ||
216 | |||
217 | static void auto_remove_settings(ide_drive_t *drive) | ||
218 | { | ||
219 | ide_settings_t *setting; | ||
220 | repeat: | ||
221 | setting = drive->settings; | ||
222 | while (setting) { | ||
223 | if (setting->auto_remove) { | ||
224 | __ide_remove_setting(drive, setting->name); | ||
225 | goto repeat; | ||
226 | } | ||
227 | setting = setting->next; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /** | ||
232 | * ide_find_setting_by_name - find a drive specific setting | ||
233 | * @drive: drive to scan | ||
234 | * @name: setting name | ||
235 | * | ||
236 | * Scan's the device setting table for a matching entry and returns | ||
237 | * this or NULL if no entry is found. The caller must hold the | 122 | * this or NULL if no entry is found. The caller must hold the |
238 | * setting semaphore | 123 | * setting semaphore |
239 | */ | 124 | */ |
240 | 125 | ||
241 | static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) | 126 | static const struct ide_devset *ide_find_setting(const struct ide_devset **st, |
127 | char *name) | ||
242 | { | 128 | { |
243 | ide_settings_t *setting = drive->settings; | 129 | while (*st) { |
244 | 130 | if (strcmp((*st)->name, name) == 0) | |
245 | while (setting) { | ||
246 | if (strcmp(setting->name, name) == 0) | ||
247 | break; | 131 | break; |
248 | setting = setting->next; | 132 | st++; |
249 | } | 133 | } |
250 | return setting; | 134 | return *st; |
251 | } | 135 | } |
252 | 136 | ||
253 | /** | 137 | /** |
@@ -263,26 +147,19 @@ static ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) | |||
263 | * be told apart | 147 | * be told apart |
264 | */ | 148 | */ |
265 | 149 | ||
266 | static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) | 150 | static int ide_read_setting(ide_drive_t *drive, |
151 | const struct ide_devset *setting) | ||
267 | { | 152 | { |
268 | int val = -EINVAL; | 153 | int val = -EINVAL; |
269 | unsigned long flags; | 154 | |
155 | if ((setting->flags & S_READ)) { | ||
156 | unsigned long flags; | ||
270 | 157 | ||
271 | if ((setting->rw & SETTING_READ)) { | ||
272 | spin_lock_irqsave(&ide_lock, flags); | 158 | spin_lock_irqsave(&ide_lock, flags); |
273 | switch (setting->data_type) { | 159 | val = setting->get(drive); |
274 | case TYPE_BYTE: | ||
275 | val = *((u8 *) setting->data); | ||
276 | break; | ||
277 | case TYPE_SHORT: | ||
278 | val = *((u16 *) setting->data); | ||
279 | break; | ||
280 | case TYPE_INT: | ||
281 | val = *((u32 *) setting->data); | ||
282 | break; | ||
283 | } | ||
284 | spin_unlock_irqrestore(&ide_lock, flags); | 160 | spin_unlock_irqrestore(&ide_lock, flags); |
285 | } | 161 | } |
162 | |||
286 | return val; | 163 | return val; |
287 | } | 164 | } |
288 | 165 | ||
@@ -304,33 +181,26 @@ static int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) | |||
304 | * The current scheme of polling is kludgy, though safe enough. | 181 | * The current scheme of polling is kludgy, though safe enough. |
305 | */ | 182 | */ |
306 | 183 | ||
307 | static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) | 184 | static int ide_write_setting(ide_drive_t *drive, |
185 | const struct ide_devset *setting, int val) | ||
308 | { | 186 | { |
309 | if (!capable(CAP_SYS_ADMIN)) | 187 | if (!capable(CAP_SYS_ADMIN)) |
310 | return -EACCES; | 188 | return -EACCES; |
311 | if (setting->set) | 189 | if (setting->set && (setting->flags & S_NOLOCK)) |
312 | return setting->set(drive, val); | 190 | return setting->set(drive, val); |
313 | if (!(setting->rw & SETTING_WRITE)) | 191 | if (!(setting->flags & S_WRITE)) |
314 | return -EPERM; | 192 | return -EPERM; |
315 | if (val < setting->min || val > setting->max) | 193 | if (val < setting->min || val > setting->max) |
316 | return -EINVAL; | 194 | return -EINVAL; |
317 | if (ide_spin_wait_hwgroup(drive)) | 195 | if (ide_spin_wait_hwgroup(drive)) |
318 | return -EBUSY; | 196 | return -EBUSY; |
319 | switch (setting->data_type) { | 197 | setting->set(drive, val); |
320 | case TYPE_BYTE: | ||
321 | *((u8 *) setting->data) = val; | ||
322 | break; | ||
323 | case TYPE_SHORT: | ||
324 | *((u16 *) setting->data) = val; | ||
325 | break; | ||
326 | case TYPE_INT: | ||
327 | *((u32 *) setting->data) = val; | ||
328 | break; | ||
329 | } | ||
330 | spin_unlock_irq(&ide_lock); | 198 | spin_unlock_irq(&ide_lock); |
331 | return 0; | 199 | return 0; |
332 | } | 200 | } |
333 | 201 | ||
202 | static ide_devset_get(xfer_rate, current_speed); | ||
203 | |||
334 | static int set_xfer_rate (ide_drive_t *drive, int arg) | 204 | static int set_xfer_rate (ide_drive_t *drive, int arg) |
335 | { | 205 | { |
336 | ide_task_t task; | 206 | ide_task_t task; |
@@ -355,29 +225,30 @@ static int set_xfer_rate (ide_drive_t *drive, int arg) | |||
355 | return err; | 225 | return err; |
356 | } | 226 | } |
357 | 227 | ||
358 | /** | 228 | ide_devset_rw_nolock(current_speed, 0, 70, xfer_rate); |
359 | * ide_add_generic_settings - generic ide settings | 229 | ide_devset_rw_nolock(io_32bit, 0, 1 + (SUPPORT_VLB_SYNC << 1), io_32bit); |
360 | * @drive: drive being configured | 230 | ide_devset_rw_nolock(keepsettings, 0, 1, ksettings); |
361 | * | 231 | ide_devset_rw_nolock(unmaskirq, 0, 1, unmaskirq); |
362 | * Add the generic parts of the system settings to the /proc files. | 232 | ide_devset_rw_nolock(using_dma, 0, 1, using_dma); |
363 | * The caller must not be holding the ide_setting_mtx. | 233 | |
364 | */ | 234 | ide_devset_w_nolock(pio_mode, 0, 255, pio_mode); |
365 | 235 | ||
366 | void ide_add_generic_settings (ide_drive_t *drive) | 236 | ide_devset_rw(init_speed, 0, 70, init_speed); |
367 | { | 237 | ide_devset_rw(nice1, 0, 1, nice1); |
368 | /* | 238 | ide_devset_rw(number, 0, 3, dn); |
369 | * drive setting name read/write access data type min max mul_factor div_factor data pointer set function | 239 | |
370 | */ | 240 | static const struct ide_devset *ide_generic_settings[] = { |
371 | __ide_add_setting(drive, "io_32bit", SETTING_RW, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit, 0); | 241 | &ide_devset_current_speed, |
372 | __ide_add_setting(drive, "keepsettings", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, set_ksettings, 0); | 242 | &ide_devset_init_speed, |
373 | __ide_add_setting(drive, "nice1", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL, 0); | 243 | &ide_devset_io_32bit, |
374 | __ide_add_setting(drive, "pio_mode", SETTING_WRITE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode, 0); | 244 | &ide_devset_keepsettings, |
375 | __ide_add_setting(drive, "unmaskirq", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, set_unmaskirq, 0); | 245 | &ide_devset_nice1, |
376 | __ide_add_setting(drive, "using_dma", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma, 0); | 246 | &ide_devset_number, |
377 | __ide_add_setting(drive, "init_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL, 0); | 247 | &ide_devset_pio_mode, |
378 | __ide_add_setting(drive, "current_speed", SETTING_RW, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate, 0); | 248 | &ide_devset_unmaskirq, |
379 | __ide_add_setting(drive, "number", SETTING_RW, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL, 0); | 249 | &ide_devset_using_dma, |
380 | } | 250 | NULL |
251 | }; | ||
381 | 252 | ||
382 | static void proc_ide_settings_warn(void) | 253 | static void proc_ide_settings_warn(void) |
383 | { | 254 | { |
@@ -394,19 +265,31 @@ static void proc_ide_settings_warn(void) | |||
394 | static int proc_ide_read_settings | 265 | static int proc_ide_read_settings |
395 | (char *page, char **start, off_t off, int count, int *eof, void *data) | 266 | (char *page, char **start, off_t off, int count, int *eof, void *data) |
396 | { | 267 | { |
268 | const struct ide_devset *setting, **g, **d; | ||
397 | ide_drive_t *drive = (ide_drive_t *) data; | 269 | ide_drive_t *drive = (ide_drive_t *) data; |
398 | ide_settings_t *setting = (ide_settings_t *) drive->settings; | ||
399 | char *out = page; | 270 | char *out = page; |
400 | int len, rc, mul_factor, div_factor; | 271 | int len, rc, mul_factor, div_factor; |
401 | 272 | ||
402 | proc_ide_settings_warn(); | 273 | proc_ide_settings_warn(); |
403 | 274 | ||
404 | mutex_lock(&ide_setting_mtx); | 275 | mutex_lock(&ide_setting_mtx); |
276 | g = ide_generic_settings; | ||
277 | d = drive->settings; | ||
405 | out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); | 278 | out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); |
406 | out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); | 279 | out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); |
407 | while (setting) { | 280 | while (*g || (d && *d)) { |
408 | mul_factor = setting->mul_factor; | 281 | /* read settings in the alphabetical order */ |
409 | div_factor = setting->div_factor; | 282 | if (*g && d && *d) { |
283 | if (strcmp((*d)->name, (*g)->name) < 0) | ||
284 | setting = *d++; | ||
285 | else | ||
286 | setting = *g++; | ||
287 | } else if (d && *d) { | ||
288 | setting = *d++; | ||
289 | } else | ||
290 | setting = *g++; | ||
291 | mul_factor = setting->mulf ? setting->mulf(drive) : 1; | ||
292 | div_factor = setting->divf ? setting->divf(drive) : 1; | ||
410 | out += sprintf(out, "%-24s", setting->name); | 293 | out += sprintf(out, "%-24s", setting->name); |
411 | rc = ide_read_setting(drive, setting); | 294 | rc = ide_read_setting(drive, setting); |
412 | if (rc >= 0) | 295 | if (rc >= 0) |
@@ -414,12 +297,11 @@ static int proc_ide_read_settings | |||
414 | else | 297 | else |
415 | out += sprintf(out, "%-16s", "write-only"); | 298 | out += sprintf(out, "%-16s", "write-only"); |
416 | out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); | 299 | out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); |
417 | if (setting->rw & SETTING_READ) | 300 | if (setting->flags & S_READ) |
418 | out += sprintf(out, "r"); | 301 | out += sprintf(out, "r"); |
419 | if (setting->rw & SETTING_WRITE) | 302 | if (setting->flags & S_WRITE) |
420 | out += sprintf(out, "w"); | 303 | out += sprintf(out, "w"); |
421 | out += sprintf(out, "\n"); | 304 | out += sprintf(out, "\n"); |
422 | setting = setting->next; | ||
423 | } | 305 | } |
424 | len = out - page; | 306 | len = out - page; |
425 | mutex_unlock(&ide_setting_mtx); | 307 | mutex_unlock(&ide_setting_mtx); |
@@ -433,9 +315,10 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer, | |||
433 | { | 315 | { |
434 | ide_drive_t *drive = (ide_drive_t *) data; | 316 | ide_drive_t *drive = (ide_drive_t *) data; |
435 | char name[MAX_LEN + 1]; | 317 | char name[MAX_LEN + 1]; |
436 | int for_real = 0; | 318 | int for_real = 0, mul_factor, div_factor; |
437 | unsigned long n; | 319 | unsigned long n; |
438 | ide_settings_t *setting; | 320 | |
321 | const struct ide_devset *setting; | ||
439 | char *buf, *s; | 322 | char *buf, *s; |
440 | 323 | ||
441 | if (!capable(CAP_SYS_ADMIN)) | 324 | if (!capable(CAP_SYS_ADMIN)) |
@@ -503,13 +386,21 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer, | |||
503 | } | 386 | } |
504 | 387 | ||
505 | mutex_lock(&ide_setting_mtx); | 388 | mutex_lock(&ide_setting_mtx); |
506 | setting = ide_find_setting_by_name(drive, name); | 389 | /* generic settings first, then driver specific ones */ |
390 | setting = ide_find_setting(ide_generic_settings, name); | ||
507 | if (!setting) { | 391 | if (!setting) { |
508 | mutex_unlock(&ide_setting_mtx); | 392 | if (drive->settings) |
509 | goto parse_error; | 393 | setting = ide_find_setting(drive->settings, name); |
394 | if (!setting) { | ||
395 | mutex_unlock(&ide_setting_mtx); | ||
396 | goto parse_error; | ||
397 | } | ||
398 | } | ||
399 | if (for_real) { | ||
400 | mul_factor = setting->mulf ? setting->mulf(drive) : 1; | ||
401 | div_factor = setting->divf ? setting->divf(drive) : 1; | ||
402 | ide_write_setting(drive, setting, val * div_factor / mul_factor); | ||
510 | } | 403 | } |
511 | if (for_real) | ||
512 | ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor); | ||
513 | mutex_unlock(&ide_setting_mtx); | 404 | mutex_unlock(&ide_setting_mtx); |
514 | } | 405 | } |
515 | } while (!for_real++); | 406 | } while (!for_real++); |
@@ -680,6 +571,10 @@ static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t | |||
680 | 571 | ||
681 | void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) | 572 | void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) |
682 | { | 573 | { |
574 | mutex_lock(&ide_setting_mtx); | ||
575 | drive->settings = driver->settings; | ||
576 | mutex_unlock(&ide_setting_mtx); | ||
577 | |||
683 | ide_add_proc_entries(drive->proc, driver->proc, drive); | 578 | ide_add_proc_entries(drive->proc, driver->proc, drive); |
684 | } | 579 | } |
685 | 580 | ||
@@ -716,7 +611,7 @@ void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) | |||
716 | * OTOH both ide_{read,write}_setting are only ever used under | 611 | * OTOH both ide_{read,write}_setting are only ever used under |
717 | * ide_setting_mtx. | 612 | * ide_setting_mtx. |
718 | */ | 613 | */ |
719 | auto_remove_settings(drive); | 614 | drive->settings = NULL; |
720 | spin_unlock_irqrestore(&ide_lock, flags); | 615 | spin_unlock_irqrestore(&ide_lock, flags); |
721 | mutex_unlock(&ide_setting_mtx); | 616 | mutex_unlock(&ide_setting_mtx); |
722 | } | 617 | } |
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index f41983e4a4e4..7037accb0589 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c | |||
@@ -2410,28 +2410,56 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive) | |||
2410 | } | 2410 | } |
2411 | 2411 | ||
2412 | #ifdef CONFIG_IDE_PROC_FS | 2412 | #ifdef CONFIG_IDE_PROC_FS |
2413 | static void idetape_add_settings(ide_drive_t *drive) | 2413 | #define ide_tape_devset_get(name, field) \ |
2414 | { | 2414 | static int get_##name(ide_drive_t *drive) \ |
2415 | idetape_tape_t *tape = drive->driver_data; | 2415 | { \ |
2416 | 2416 | idetape_tape_t *tape = drive->driver_data; \ | |
2417 | ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff, | 2417 | return tape->field; \ |
2418 | 1, 2, (u16 *)&tape->caps[16], NULL); | 2418 | } |
2419 | ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff, | 2419 | |
2420 | 1, 1, (u16 *)&tape->caps[14], NULL); | 2420 | #define ide_tape_devset_set(name, field) \ |
2421 | ide_add_setting(drive, "buffer_size", SETTING_READ, TYPE_INT, 0, 0xffff, | 2421 | static int set_##name(ide_drive_t *drive, int arg) \ |
2422 | 1, 1024, &tape->buffer_size, NULL); | 2422 | { \ |
2423 | ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN, | 2423 | idetape_tape_t *tape = drive->driver_data; \ |
2424 | IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_freq, | 2424 | tape->field = arg; \ |
2425 | NULL); | 2425 | return 0; \ |
2426 | ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, | 2426 | } |
2427 | 1, &drive->dsc_overlap, NULL); | 2427 | |
2428 | ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff, | 2428 | #define ide_tape_devset_rw(_name, _min, _max, _field, _mulf, _divf) \ |
2429 | 1, 1, &tape->avg_speed, NULL); | 2429 | ide_tape_devset_get(_name, _field) \ |
2430 | ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1, | 2430 | ide_tape_devset_set(_name, _field) \ |
2431 | 1, &tape->debug_mask, NULL); | 2431 | __IDE_DEVSET(_name, S_RW, _min, _max, get_##_name, set_##_name, _mulf, _divf) |
2432 | } | 2432 | |
2433 | #else | 2433 | #define ide_tape_devset_r(_name, _min, _max, _field, _mulf, _divf) \ |
2434 | static inline void idetape_add_settings(ide_drive_t *drive) { ; } | 2434 | ide_tape_devset_get(_name, _field) \ |
2435 | __IDE_DEVSET(_name, S_READ, _min, _max, get_##_name, NULL, _mulf, _divf) | ||
2436 | |||
2437 | static int mulf_tdsc(ide_drive_t *drive) { return 1000; } | ||
2438 | static int divf_tdsc(ide_drive_t *drive) { return HZ; } | ||
2439 | static int divf_buffer(ide_drive_t *drive) { return 2; } | ||
2440 | static int divf_buffer_size(ide_drive_t *drive) { return 1024; } | ||
2441 | |||
2442 | ide_devset_rw(dsc_overlap, 0, 1, dsc_overlap); | ||
2443 | |||
2444 | ide_tape_devset_rw(debug_mask, 0, 0xffff, debug_mask, NULL, NULL); | ||
2445 | ide_tape_devset_rw(tdsc, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, | ||
2446 | best_dsc_rw_freq, mulf_tdsc, divf_tdsc); | ||
2447 | |||
2448 | ide_tape_devset_r(avg_speed, 0, 0xffff, avg_speed, NULL, NULL); | ||
2449 | ide_tape_devset_r(speed, 0, 0xffff, caps[14], NULL, NULL); | ||
2450 | ide_tape_devset_r(buffer, 0, 0xffff, caps[16], NULL, divf_buffer); | ||
2451 | ide_tape_devset_r(buffer_size, 0, 0xffff, buffer_size, NULL, divf_buffer_size); | ||
2452 | |||
2453 | static const struct ide_devset *idetape_settings[] = { | ||
2454 | &ide_devset_avg_speed, | ||
2455 | &ide_devset_buffer, | ||
2456 | &ide_devset_buffer_size, | ||
2457 | &ide_devset_debug_mask, | ||
2458 | &ide_devset_dsc_overlap, | ||
2459 | &ide_devset_speed, | ||
2460 | &ide_devset_tdsc, | ||
2461 | NULL | ||
2462 | }; | ||
2435 | #endif | 2463 | #endif |
2436 | 2464 | ||
2437 | /* | 2465 | /* |
@@ -2515,7 +2543,6 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) | |||
2515 | drive->using_dma ? ", DMA":""); | 2543 | drive->using_dma ? ", DMA":""); |
2516 | 2544 | ||
2517 | ide_proc_register_driver(drive, tape->driver); | 2545 | ide_proc_register_driver(drive, tape->driver); |
2518 | idetape_add_settings(drive); | ||
2519 | } | 2546 | } |
2520 | 2547 | ||
2521 | static void ide_tape_remove(ide_drive_t *drive) | 2548 | static void ide_tape_remove(ide_drive_t *drive) |
@@ -2586,6 +2613,7 @@ static ide_driver_t idetape_driver = { | |||
2586 | .error = __ide_error, | 2613 | .error = __ide_error, |
2587 | #ifdef CONFIG_IDE_PROC_FS | 2614 | #ifdef CONFIG_IDE_PROC_FS |
2588 | .proc = idetape_proc, | 2615 | .proc = idetape_proc, |
2616 | .settings = idetape_settings, | ||
2589 | #endif | 2617 | #endif |
2590 | }; | 2618 | }; |
2591 | 2619 | ||
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 8e0c9f27ae4a..eb64e942f58b 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c | |||
@@ -287,6 +287,8 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive) | |||
287 | 287 | ||
288 | EXPORT_SYMBOL(ide_spin_wait_hwgroup); | 288 | EXPORT_SYMBOL(ide_spin_wait_hwgroup); |
289 | 289 | ||
290 | ide_devset_get(io_32bit, io_32bit); | ||
291 | |||
290 | int set_io_32bit(ide_drive_t *drive, int arg) | 292 | int set_io_32bit(ide_drive_t *drive, int arg) |
291 | { | 293 | { |
292 | if (drive->no_io_32bit) | 294 | if (drive->no_io_32bit) |
@@ -305,6 +307,8 @@ int set_io_32bit(ide_drive_t *drive, int arg) | |||
305 | return 0; | 307 | return 0; |
306 | } | 308 | } |
307 | 309 | ||
310 | ide_devset_get(ksettings, keep_settings); | ||
311 | |||
308 | int set_ksettings(ide_drive_t *drive, int arg) | 312 | int set_ksettings(ide_drive_t *drive, int arg) |
309 | { | 313 | { |
310 | if (arg < 0 || arg > 1) | 314 | if (arg < 0 || arg > 1) |
@@ -318,6 +322,8 @@ int set_ksettings(ide_drive_t *drive, int arg) | |||
318 | return 0; | 322 | return 0; |
319 | } | 323 | } |
320 | 324 | ||
325 | ide_devset_get(using_dma, using_dma); | ||
326 | |||
321 | int set_using_dma(ide_drive_t *drive, int arg) | 327 | int set_using_dma(ide_drive_t *drive, int arg) |
322 | { | 328 | { |
323 | #ifdef CONFIG_BLK_DEV_IDEDMA | 329 | #ifdef CONFIG_BLK_DEV_IDEDMA |
@@ -394,6 +400,8 @@ int set_pio_mode(ide_drive_t *drive, int arg) | |||
394 | return 0; | 400 | return 0; |
395 | } | 401 | } |
396 | 402 | ||
403 | ide_devset_get(unmaskirq, unmask); | ||
404 | |||
397 | int set_unmaskirq(ide_drive_t *drive, int arg) | 405 | int set_unmaskirq(ide_drive_t *drive, int arg) |
398 | { | 406 | { |
399 | if (drive->no_unmask) | 407 | if (drive->no_unmask) |
@@ -555,14 +563,13 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device | |||
555 | { | 563 | { |
556 | unsigned long flags; | 564 | unsigned long flags; |
557 | ide_driver_t *drv; | 565 | ide_driver_t *drv; |
558 | int err = 0, (*setfunc)(ide_drive_t *, int); | 566 | int err = 0, (*getfunc)(ide_drive_t *), (*setfunc)(ide_drive_t *, int); |
559 | u8 *val; | ||
560 | 567 | ||
561 | switch (cmd) { | 568 | switch (cmd) { |
562 | case HDIO_GET_32BIT: val = &drive->io_32bit; goto read_val; | 569 | case HDIO_GET_32BIT: getfunc = get_io_32bit; goto read_val; |
563 | case HDIO_GET_KEEPSETTINGS: val = &drive->keep_settings; goto read_val; | 570 | case HDIO_GET_KEEPSETTINGS: getfunc = get_ksettings; goto read_val; |
564 | case HDIO_GET_UNMASKINTR: val = &drive->unmask; goto read_val; | 571 | case HDIO_GET_UNMASKINTR: getfunc = get_unmaskirq; goto read_val; |
565 | case HDIO_GET_DMA: val = &drive->using_dma; goto read_val; | 572 | case HDIO_GET_DMA: getfunc = get_using_dma; goto read_val; |
566 | case HDIO_SET_32BIT: setfunc = set_io_32bit; goto set_val; | 573 | case HDIO_SET_32BIT: setfunc = set_io_32bit; goto set_val; |
567 | case HDIO_SET_KEEPSETTINGS: setfunc = set_ksettings; goto set_val; | 574 | case HDIO_SET_KEEPSETTINGS: setfunc = set_ksettings; goto set_val; |
568 | case HDIO_SET_PIO_MODE: setfunc = set_pio_mode; goto set_val; | 575 | case HDIO_SET_PIO_MODE: setfunc = set_pio_mode; goto set_val; |
@@ -638,7 +645,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device | |||
638 | read_val: | 645 | read_val: |
639 | mutex_lock(&ide_setting_mtx); | 646 | mutex_lock(&ide_setting_mtx); |
640 | spin_lock_irqsave(&ide_lock, flags); | 647 | spin_lock_irqsave(&ide_lock, flags); |
641 | err = *val; | 648 | err = getfunc(drive); |
642 | spin_unlock_irqrestore(&ide_lock, flags); | 649 | spin_unlock_irqrestore(&ide_lock, flags); |
643 | mutex_unlock(&ide_setting_mtx); | 650 | mutex_unlock(&ide_setting_mtx); |
644 | return err >= 0 ? put_user(err, (long __user *)arg) : err; | 651 | return err >= 0 ? put_user(err, (long __user *)arg) : err; |
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 02bd5c487d1f..65cf84b222c5 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c | |||
@@ -429,21 +429,41 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *r | |||
429 | } | 429 | } |
430 | 430 | ||
431 | #ifdef CONFIG_IDE_PROC_FS | 431 | #ifdef CONFIG_IDE_PROC_FS |
432 | static void idescsi_add_settings(ide_drive_t *drive) | 432 | #define ide_scsi_devset_get(name, field) \ |
433 | { | 433 | static int get_##name(ide_drive_t *drive) \ |
434 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); | 434 | { \ |
435 | 435 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); \ | |
436 | /* | 436 | return scsi->field; \ |
437 | * drive setting name read/write data type min max mul_factor div_factor data pointer set function | 437 | } |
438 | */ | 438 | |
439 | ide_add_setting(drive, "bios_cyl", SETTING_RW, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); | 439 | #define ide_scsi_devset_set(name, field) \ |
440 | ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); | 440 | static int set_##name(ide_drive_t *drive, int arg) \ |
441 | ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); | 441 | { \ |
442 | ide_add_setting(drive, "transform", SETTING_RW, TYPE_INT, 0, 3, 1, 1, &scsi->transform, NULL); | 442 | idescsi_scsi_t *scsi = drive_to_idescsi(drive); \ |
443 | ide_add_setting(drive, "log", SETTING_RW, TYPE_INT, 0, 1, 1, 1, &scsi->log, NULL); | 443 | scsi->field = arg; \ |
444 | } | 444 | return 0; \ |
445 | #else | 445 | } |
446 | static inline void idescsi_add_settings(ide_drive_t *drive) { ; } | 446 | |
447 | #define ide_scsi_devset_rw(_name, _min, _max, _field) \ | ||
448 | ide_scsi_devset_get(_name, _field); \ | ||
449 | ide_scsi_devset_set(_name, _field); \ | ||
450 | IDE_DEVSET(_name, S_RW, _min, _max, get_##_name, set_##_name) | ||
451 | |||
452 | ide_devset_rw(bios_cyl, 0, 1023, bios_cyl); | ||
453 | ide_devset_rw(bios_head, 0, 255, bios_head); | ||
454 | ide_devset_rw(bios_sect, 0, 63, bios_sect); | ||
455 | |||
456 | ide_scsi_devset_rw(transform, 0, 3, transform); | ||
457 | ide_scsi_devset_rw(log, 0, 1, log); | ||
458 | |||
459 | static const struct ide_devset *idescsi_settings[] = { | ||
460 | &ide_devset_bios_cyl, | ||
461 | &ide_devset_bios_head, | ||
462 | &ide_devset_bios_sect, | ||
463 | &ide_devset_log, | ||
464 | &ide_devset_transform, | ||
465 | NULL | ||
466 | }; | ||
447 | #endif | 467 | #endif |
448 | 468 | ||
449 | /* | 469 | /* |
@@ -461,7 +481,6 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi) | |||
461 | drive->pc_callback = ide_scsi_callback; | 481 | drive->pc_callback = ide_scsi_callback; |
462 | 482 | ||
463 | ide_proc_register_driver(drive, scsi->driver); | 483 | ide_proc_register_driver(drive, scsi->driver); |
464 | idescsi_add_settings(drive); | ||
465 | } | 484 | } |
466 | 485 | ||
467 | static void ide_scsi_remove(ide_drive_t *drive) | 486 | static void ide_scsi_remove(ide_drive_t *drive) |
@@ -509,6 +528,7 @@ static ide_driver_t idescsi_driver = { | |||
509 | .error = idescsi_atapi_error, | 528 | .error = idescsi_atapi_error, |
510 | #ifdef CONFIG_IDE_PROC_FS | 529 | #ifdef CONFIG_IDE_PROC_FS |
511 | .proc = idescsi_proc, | 530 | .proc = idescsi_proc, |
531 | .settings = idescsi_settings, | ||
512 | #endif | 532 | #endif |
513 | }; | 533 | }; |
514 | 534 | ||
diff --git a/include/linux/ide.h b/include/linux/ide.h index ad09e7c81ae9..4667ec8aeebb 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
@@ -304,8 +304,8 @@ typedef enum { | |||
304 | ide_started, /* a drive operation was started, handler was set */ | 304 | ide_started, /* a drive operation was started, handler was set */ |
305 | } ide_startstop_t; | 305 | } ide_startstop_t; |
306 | 306 | ||
307 | struct ide_devset; | ||
307 | struct ide_driver_s; | 308 | struct ide_driver_s; |
308 | struct ide_settings_s; | ||
309 | 309 | ||
310 | #ifdef CONFIG_BLK_DEV_IDEACPI | 310 | #ifdef CONFIG_BLK_DEV_IDEACPI |
311 | struct ide_acpi_drive_link; | 311 | struct ide_acpi_drive_link; |
@@ -384,7 +384,7 @@ struct ide_drive_s { | |||
384 | u16 *id; /* identification info */ | 384 | u16 *id; /* identification info */ |
385 | #ifdef CONFIG_IDE_PROC_FS | 385 | #ifdef CONFIG_IDE_PROC_FS |
386 | struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ | 386 | struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ |
387 | struct ide_settings_s *settings;/* /proc/ide/ drive settings */ | 387 | const struct ide_devset **settings; /* /proc/ide/ drive settings */ |
388 | #endif | 388 | #endif |
389 | struct hwif_s *hwif; /* actually (ide_hwif_t *) */ | 389 | struct hwif_s *hwif; /* actually (ide_hwif_t *) */ |
390 | 390 | ||
@@ -396,16 +396,16 @@ struct ide_drive_s { | |||
396 | special_t special; /* special action flags */ | 396 | special_t special; /* special action flags */ |
397 | select_t select; /* basic drive/head select reg value */ | 397 | select_t select; /* basic drive/head select reg value */ |
398 | 398 | ||
399 | u8 keep_settings; /* restore settings after drive reset */ | ||
400 | u8 using_dma; /* disk is using dma for read/write */ | ||
401 | u8 retry_pio; /* retrying dma capable host in pio */ | 399 | u8 retry_pio; /* retrying dma capable host in pio */ |
402 | u8 state; /* retry state */ | 400 | u8 state; /* retry state */ |
403 | u8 waiting_for_dma; /* dma currently in progress */ | 401 | u8 waiting_for_dma; /* dma currently in progress */ |
404 | u8 unmask; /* okay to unmask other irqs */ | ||
405 | u8 noflush; /* don't attempt flushes */ | ||
406 | u8 dsc_overlap; /* DSC overlap */ | ||
407 | u8 nice1; /* give potential excess bandwidth */ | ||
408 | 402 | ||
403 | unsigned keep_settings : 1; /* restore settings after drive reset */ | ||
404 | unsigned using_dma : 1; /* disk is using dma for read/write */ | ||
405 | unsigned unmask : 1; /* okay to unmask other irqs */ | ||
406 | unsigned noflush : 1; /* don't attempt flushes */ | ||
407 | unsigned dsc_overlap : 1; /* DSC overlap */ | ||
408 | unsigned nice1 : 1; /* give potential excess bandwidth */ | ||
409 | unsigned present : 1; /* drive is physically present */ | 409 | unsigned present : 1; /* drive is physically present */ |
410 | unsigned dead : 1; /* device ejected hint */ | 410 | unsigned dead : 1; /* device ejected hint */ |
411 | unsigned id_read : 1; /* 1=id read from disk 0 = synthetic */ | 411 | unsigned id_read : 1; /* 1=id read from disk 0 = synthetic */ |
@@ -423,14 +423,15 @@ struct ide_drive_s { | |||
423 | unsigned sleeping : 1; /* 1=sleeping & sleep field valid */ | 423 | unsigned sleeping : 1; /* 1=sleeping & sleep field valid */ |
424 | unsigned post_reset : 1; | 424 | unsigned post_reset : 1; |
425 | unsigned udma33_warned : 1; | 425 | unsigned udma33_warned : 1; |
426 | unsigned addressing : 2; /* 0=28-bit, 1=48-bit, 2=48-bit doing 28-bit */ | ||
427 | unsigned wcache : 1; /* status of write cache */ | ||
428 | unsigned nowerr : 1; /* used for ignoring ATA_DF */ | ||
426 | 429 | ||
427 | u8 addressing; /* 0=28-bit, 1=48-bit, 2=48-bit doing 28-bit */ | ||
428 | u8 quirk_list; /* considered quirky, set for a specific host */ | 430 | u8 quirk_list; /* considered quirky, set for a specific host */ |
429 | u8 init_speed; /* transfer rate set at boot */ | 431 | u8 init_speed; /* transfer rate set at boot */ |
430 | u8 current_speed; /* current transfer rate set */ | 432 | u8 current_speed; /* current transfer rate set */ |
431 | u8 desired_speed; /* desired transfer rate set */ | 433 | u8 desired_speed; /* desired transfer rate set */ |
432 | u8 dn; /* now wide spread use */ | 434 | u8 dn; /* now wide spread use */ |
433 | u8 wcache; /* status of write cache */ | ||
434 | u8 acoustic; /* acoustic management */ | 435 | u8 acoustic; /* acoustic management */ |
435 | u8 media; /* disk, cdrom, tape, floppy, ... */ | 436 | u8 media; /* disk, cdrom, tape, floppy, ... */ |
436 | u8 ready_stat; /* min status value for drive ready */ | 437 | u8 ready_stat; /* min status value for drive ready */ |
@@ -439,7 +440,6 @@ struct ide_drive_s { | |||
439 | u8 tune_req; /* requested drive tuning setting */ | 440 | u8 tune_req; /* requested drive tuning setting */ |
440 | u8 io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ | 441 | u8 io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ |
441 | u8 bad_wstat; /* used for ignoring ATA_DF */ | 442 | u8 bad_wstat; /* used for ignoring ATA_DF */ |
442 | u8 nowerr; /* used for ignoring ATA_DF */ | ||
443 | u8 head; /* "real" number of heads */ | 443 | u8 head; /* "real" number of heads */ |
444 | u8 sect; /* "real" sectors per track */ | 444 | u8 sect; /* "real" sectors per track */ |
445 | u8 bios_head; /* BIOS/fdisk/LILO number of heads */ | 445 | u8 bios_head; /* BIOS/fdisk/LILO number of heads */ |
@@ -687,12 +687,29 @@ typedef struct ide_driver_s ide_driver_t; | |||
687 | 687 | ||
688 | extern struct mutex ide_setting_mtx; | 688 | extern struct mutex ide_setting_mtx; |
689 | 689 | ||
690 | int get_io_32bit(ide_drive_t *); | ||
690 | int set_io_32bit(ide_drive_t *, int); | 691 | int set_io_32bit(ide_drive_t *, int); |
692 | int get_ksettings(ide_drive_t *); | ||
691 | int set_ksettings(ide_drive_t *, int); | 693 | int set_ksettings(ide_drive_t *, int); |
692 | int set_pio_mode(ide_drive_t *, int); | 694 | int set_pio_mode(ide_drive_t *, int); |
695 | int get_unmaskirq(ide_drive_t *); | ||
693 | int set_unmaskirq(ide_drive_t *, int); | 696 | int set_unmaskirq(ide_drive_t *, int); |
697 | int get_using_dma(ide_drive_t *); | ||
694 | int set_using_dma(ide_drive_t *, int); | 698 | int set_using_dma(ide_drive_t *, int); |
695 | 699 | ||
700 | #define ide_devset_get(name, field) \ | ||
701 | int get_##name(ide_drive_t *drive) \ | ||
702 | { \ | ||
703 | return drive->field; \ | ||
704 | } | ||
705 | |||
706 | #define ide_devset_set(name, field) \ | ||
707 | int set_##name(ide_drive_t *drive, int arg) \ | ||
708 | { \ | ||
709 | drive->field = arg; \ | ||
710 | return 0; \ | ||
711 | } | ||
712 | |||
696 | /* ATAPI packet command flags */ | 713 | /* ATAPI packet command flags */ |
697 | enum { | 714 | enum { |
698 | /* set when an error is considered normal - no retry (ide-tape) */ | 715 | /* set when an error is considered normal - no retry (ide-tape) */ |
@@ -757,30 +774,53 @@ struct ide_atapi_pc { | |||
757 | * configurable drive settings | 774 | * configurable drive settings |
758 | */ | 775 | */ |
759 | 776 | ||
760 | #define TYPE_INT 0 | 777 | #define S_READ (1 << 0) |
761 | #define TYPE_BYTE 1 | 778 | #define S_WRITE (1 << 1) |
762 | #define TYPE_SHORT 2 | 779 | #define S_RW (S_READ | S_WRITE) |
780 | #define S_NOLOCK (1 << 2) | ||
763 | 781 | ||
764 | #define SETTING_READ (1 << 0) | 782 | struct ide_devset { |
765 | #define SETTING_WRITE (1 << 1) | 783 | const char *name; |
766 | #define SETTING_RW (SETTING_READ | SETTING_WRITE) | 784 | unsigned int flags; |
785 | int min, max; | ||
786 | int (*get)(ide_drive_t *); | ||
787 | int (*set)(ide_drive_t *, int); | ||
788 | int (*mulf)(ide_drive_t *); | ||
789 | int (*divf)(ide_drive_t *); | ||
790 | }; | ||
767 | 791 | ||
768 | typedef int (ide_procset_t)(ide_drive_t *, int); | 792 | #define __DEVSET(_name, _flags, _min, _max, _get, _set, _mulf, _divf) { \ |
769 | typedef struct ide_settings_s { | 793 | .name = __stringify(_name), \ |
770 | char *name; | 794 | .flags = _flags, \ |
771 | int rw; | 795 | .min = _min, \ |
772 | int data_type; | 796 | .max = _max, \ |
773 | int min; | 797 | .get = _get, \ |
774 | int max; | 798 | .set = _set, \ |
775 | int mul_factor; | 799 | .mulf = _mulf, \ |
776 | int div_factor; | 800 | .divf = _divf, \ |
777 | void *data; | 801 | } |
778 | ide_procset_t *set; | 802 | |
779 | int auto_remove; | 803 | #define __IDE_DEVSET(_name, _flags, _min, _max, _get, _set, _mulf, _divf) \ |
780 | struct ide_settings_s *next; | 804 | static const struct ide_devset ide_devset_##_name = \ |
781 | } ide_settings_t; | 805 | __DEVSET(_name, _flags, _min, _max, _get, _set, _mulf, _divf) |
782 | 806 | ||
783 | int ide_add_setting(ide_drive_t *, const char *, int, int, int, int, int, int, void *, ide_procset_t *set); | 807 | #define IDE_DEVSET(_name, _flags, _min, _max, _get, _set) \ |
808 | __IDE_DEVSET(_name, _flags, _min, _max, _get, _set, NULL, NULL) | ||
809 | |||
810 | #define ide_devset_rw_nolock(_name, _min, _max, _func) \ | ||
811 | IDE_DEVSET(_name, S_RW | S_NOLOCK, _min, _max, get_##_func, set_##_func) | ||
812 | |||
813 | #define ide_devset_w_nolock(_name, _min, _max, _func) \ | ||
814 | IDE_DEVSET(_name, S_WRITE | S_NOLOCK, _min, _max, NULL, set_##_func) | ||
815 | |||
816 | #define ide_devset_rw(_name, _min, _max, _field) \ | ||
817 | static ide_devset_get(_name, _field); \ | ||
818 | static ide_devset_set(_name, _field); \ | ||
819 | IDE_DEVSET(_name, S_RW, _min, _max, get_##_name, set_##_name) | ||
820 | |||
821 | #define ide_devset_r(_name, _min, _max, _field) \ | ||
822 | ide_devset_get(_name, _field) \ | ||
823 | IDE_DEVSET(_name, S_READ, _min, _max, get_##_name, NULL) | ||
784 | 824 | ||
785 | /* | 825 | /* |
786 | * /proc/ide interface | 826 | * /proc/ide interface |
@@ -801,8 +841,6 @@ void ide_proc_unregister_port(ide_hwif_t *); | |||
801 | void ide_proc_register_driver(ide_drive_t *, ide_driver_t *); | 841 | void ide_proc_register_driver(ide_drive_t *, ide_driver_t *); |
802 | void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *); | 842 | void ide_proc_unregister_driver(ide_drive_t *, ide_driver_t *); |
803 | 843 | ||
804 | void ide_add_generic_settings(ide_drive_t *); | ||
805 | |||
806 | read_proc_t proc_ide_read_capacity; | 844 | read_proc_t proc_ide_read_capacity; |
807 | read_proc_t proc_ide_read_geometry; | 845 | read_proc_t proc_ide_read_geometry; |
808 | 846 | ||
@@ -830,7 +868,6 @@ static inline void ide_proc_unregister_device(ide_drive_t *drive) { ; } | |||
830 | static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; } | 868 | static inline void ide_proc_unregister_port(ide_hwif_t *hwif) { ; } |
831 | static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; } | 869 | static inline void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver) { ; } |
832 | static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; } | 870 | static inline void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver) { ; } |
833 | static inline void ide_add_generic_settings(ide_drive_t *drive) { ; } | ||
834 | #define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0; | 871 | #define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) return 0; |
835 | #endif | 872 | #endif |
836 | 873 | ||
@@ -887,6 +924,7 @@ struct ide_driver_s { | |||
887 | void (*shutdown)(ide_drive_t *); | 924 | void (*shutdown)(ide_drive_t *); |
888 | #ifdef CONFIG_IDE_PROC_FS | 925 | #ifdef CONFIG_IDE_PROC_FS |
889 | ide_proc_entry_t *proc; | 926 | ide_proc_entry_t *proc; |
927 | const struct ide_devset **settings; | ||
890 | #endif | 928 | #endif |
891 | }; | 929 | }; |
892 | 930 | ||