OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [firmware/] [edd.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * linux/drivers/firmware/edd.c
3
 *  Copyright (C) 2002, 2003, 2004 Dell Inc.
4
 *  by Matt Domsch <Matt_Domsch@dell.com>
5
 *  disk signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
6
 *  legacy CHS by Patrick J. LoPresti <patl@users.sourceforge.net>
7
 *
8
 * BIOS Enhanced Disk Drive Services (EDD)
9
 * conformant to T13 Committee www.t13.org
10
 *   projects 1572D, 1484D, 1386D, 1226DT
11
 *
12
 * This code takes information provided by BIOS EDD calls
13
 * fn41 - Check Extensions Present and
14
 * fn48 - Get Device Parametes with EDD extensions
15
 * made in setup.S, copied to safe structures in setup.c,
16
 * and presents it in sysfs.
17
 *
18
 * Please see http://linux.dell.com/edd30/results.html for
19
 * the list of BIOSs which have been reported to implement EDD.
20
 *
21
 * This program is free software; you can redistribute it and/or modify
22
 * it under the terms of the GNU General Public License v2.0 as published by
23
 * the Free Software Foundation
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28
 * GNU General Public License for more details.
29
 *
30
 */
31
 
32
#include <linux/module.h>
33
#include <linux/string.h>
34
#include <linux/types.h>
35
#include <linux/init.h>
36
#include <linux/stat.h>
37
#include <linux/err.h>
38
#include <linux/ctype.h>
39
#include <linux/slab.h>
40
#include <linux/limits.h>
41
#include <linux/device.h>
42
#include <linux/pci.h>
43
#include <linux/blkdev.h>
44
#include <linux/edd.h>
45
 
46
#define EDD_VERSION "0.16"
47
#define EDD_DATE    "2004-Jun-25"
48
 
49
MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
50
MODULE_DESCRIPTION("sysfs interface to BIOS EDD information");
51
MODULE_LICENSE("GPL");
52
MODULE_VERSION(EDD_VERSION);
53
 
54
#define left (PAGE_SIZE - (p - buf) - 1)
55
 
56
struct edd_device {
57
        unsigned int index;
58
        unsigned int mbr_signature;
59
        struct edd_info *info;
60
        struct kobject kobj;
61
};
62
 
63
struct edd_attribute {
64
        struct attribute attr;
65
        ssize_t(*show) (struct edd_device * edev, char *buf);
66
        int (*test) (struct edd_device * edev);
67
};
68
 
69
/* forward declarations */
70
static int edd_dev_is_type(struct edd_device *edev, const char *type);
71
static struct pci_dev *edd_get_pci_dev(struct edd_device *edev);
72
 
73
static struct edd_device *edd_devices[EDD_MBR_SIG_MAX];
74
 
75
#define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
76
struct edd_attribute edd_attr_##_name = {       \
77
        .attr = {.name = __stringify(_name), .mode = _mode },   \
78
        .show   = _show,                                \
79
        .test   = _test,                                \
80
};
81
 
82
static int
83
edd_has_mbr_signature(struct edd_device *edev)
84
{
85
        return edev->index < min_t(unsigned char, edd.mbr_signature_nr, EDD_MBR_SIG_MAX);
86
}
87
 
88
static int
89
edd_has_edd_info(struct edd_device *edev)
90
{
91
        return edev->index < min_t(unsigned char, edd.edd_info_nr, EDDMAXNR);
92
}
93
 
94
static inline struct edd_info *
95
edd_dev_get_info(struct edd_device *edev)
96
{
97
        return edev->info;
98
}
99
 
100
static inline void
101
edd_dev_set_info(struct edd_device *edev, int i)
102
{
103
        edev->index = i;
104
        if (edd_has_mbr_signature(edev))
105
                edev->mbr_signature = edd.mbr_signature[i];
106
        if (edd_has_edd_info(edev))
107
                edev->info = &edd.edd_info[i];
108
}
109
 
110
#define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr)
111
#define to_edd_device(obj) container_of(obj,struct edd_device,kobj)
112
 
113
static ssize_t
114
edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
115
{
116
        struct edd_device *dev = to_edd_device(kobj);
117
        struct edd_attribute *edd_attr = to_edd_attr(attr);
118
        ssize_t ret = -EIO;
119
 
120
        if (edd_attr->show)
121
                ret = edd_attr->show(dev, buf);
122
        return ret;
123
}
124
 
125
static struct sysfs_ops edd_attr_ops = {
126
        .show = edd_attr_show,
127
};
128
 
129
static ssize_t
130
edd_show_host_bus(struct edd_device *edev, char *buf)
131
{
132
        struct edd_info *info;
133
        char *p = buf;
134
        int i;
135
 
136
        if (!edev)
137
                return -EINVAL;
138
        info = edd_dev_get_info(edev);
139
        if (!info || !buf)
140
                return -EINVAL;
141
 
142
        for (i = 0; i < 4; i++) {
143
                if (isprint(info->params.host_bus_type[i])) {
144
                        p += scnprintf(p, left, "%c", info->params.host_bus_type[i]);
145
                } else {
146
                        p += scnprintf(p, left, " ");
147
                }
148
        }
149
 
150
        if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
151
                p += scnprintf(p, left, "\tbase_address: %x\n",
152
                             info->params.interface_path.isa.base_address);
153
        } else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
154
                   !strncmp(info->params.host_bus_type, "PCI", 3)) {
155
                p += scnprintf(p, left,
156
                             "\t%02x:%02x.%d  channel: %u\n",
157
                             info->params.interface_path.pci.bus,
158
                             info->params.interface_path.pci.slot,
159
                             info->params.interface_path.pci.function,
160
                             info->params.interface_path.pci.channel);
161
        } else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
162
                   !strncmp(info->params.host_bus_type, "XPRS", 4) ||
163
                   !strncmp(info->params.host_bus_type, "HTPT", 4)) {
164
                p += scnprintf(p, left,
165
                             "\tTBD: %llx\n",
166
                             info->params.interface_path.ibnd.reserved);
167
 
168
        } else {
169
                p += scnprintf(p, left, "\tunknown: %llx\n",
170
                             info->params.interface_path.unknown.reserved);
171
        }
172
        return (p - buf);
173
}
174
 
175
static ssize_t
176
edd_show_interface(struct edd_device *edev, char *buf)
177
{
178
        struct edd_info *info;
179
        char *p = buf;
180
        int i;
181
 
182
        if (!edev)
183
                return -EINVAL;
184
        info = edd_dev_get_info(edev);
185
        if (!info || !buf)
186
                return -EINVAL;
187
 
188
        for (i = 0; i < 8; i++) {
189
                if (isprint(info->params.interface_type[i])) {
190
                        p += scnprintf(p, left, "%c", info->params.interface_type[i]);
191
                } else {
192
                        p += scnprintf(p, left, " ");
193
                }
194
        }
195
        if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
196
                p += scnprintf(p, left, "\tdevice: %u  lun: %u\n",
197
                             info->params.device_path.atapi.device,
198
                             info->params.device_path.atapi.lun);
199
        } else if (!strncmp(info->params.interface_type, "ATA", 3)) {
200
                p += scnprintf(p, left, "\tdevice: %u\n",
201
                             info->params.device_path.ata.device);
202
        } else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
203
                p += scnprintf(p, left, "\tid: %u  lun: %llu\n",
204
                             info->params.device_path.scsi.id,
205
                             info->params.device_path.scsi.lun);
206
        } else if (!strncmp(info->params.interface_type, "USB", 3)) {
207
                p += scnprintf(p, left, "\tserial_number: %llx\n",
208
                             info->params.device_path.usb.serial_number);
209
        } else if (!strncmp(info->params.interface_type, "1394", 4)) {
210
                p += scnprintf(p, left, "\teui: %llx\n",
211
                             info->params.device_path.i1394.eui);
212
        } else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
213
                p += scnprintf(p, left, "\twwid: %llx lun: %llx\n",
214
                             info->params.device_path.fibre.wwid,
215
                             info->params.device_path.fibre.lun);
216
        } else if (!strncmp(info->params.interface_type, "I2O", 3)) {
217
                p += scnprintf(p, left, "\tidentity_tag: %llx\n",
218
                             info->params.device_path.i2o.identity_tag);
219
        } else if (!strncmp(info->params.interface_type, "RAID", 4)) {
220
                p += scnprintf(p, left, "\tidentity_tag: %x\n",
221
                             info->params.device_path.raid.array_number);
222
        } else if (!strncmp(info->params.interface_type, "SATA", 4)) {
223
                p += scnprintf(p, left, "\tdevice: %u\n",
224
                             info->params.device_path.sata.device);
225
        } else {
226
                p += scnprintf(p, left, "\tunknown: %llx %llx\n",
227
                             info->params.device_path.unknown.reserved1,
228
                             info->params.device_path.unknown.reserved2);
229
        }
230
 
231
        return (p - buf);
232
}
233
 
234
/**
235
 * edd_show_raw_data() - copies raw data to buffer for userspace to parse
236
 * @edev: target edd_device
237
 * @buf: output buffer
238
 *
239
 * Returns: number of bytes written, or -EINVAL on failure
240
 */
241
static ssize_t
242
edd_show_raw_data(struct edd_device *edev, char *buf)
243
{
244
        struct edd_info *info;
245
        ssize_t len = sizeof (info->params);
246
        if (!edev)
247
                return -EINVAL;
248
        info = edd_dev_get_info(edev);
249
        if (!info || !buf)
250
                return -EINVAL;
251
 
252
        if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
253
                len = info->params.length;
254
 
255
        /* In case of buggy BIOSs */
256
        if (len > (sizeof(info->params)))
257
                len = sizeof(info->params);
258
 
259
        memcpy(buf, &info->params, len);
260
        return len;
261
}
262
 
263
static ssize_t
264
edd_show_version(struct edd_device *edev, char *buf)
265
{
266
        struct edd_info *info;
267
        char *p = buf;
268
        if (!edev)
269
                return -EINVAL;
270
        info = edd_dev_get_info(edev);
271
        if (!info || !buf)
272
                return -EINVAL;
273
 
274
        p += scnprintf(p, left, "0x%02x\n", info->version);
275
        return (p - buf);
276
}
277
 
278
static ssize_t
279
edd_show_mbr_signature(struct edd_device *edev, char *buf)
280
{
281
        char *p = buf;
282
        p += scnprintf(p, left, "0x%08x\n", edev->mbr_signature);
283
        return (p - buf);
284
}
285
 
286
static ssize_t
287
edd_show_extensions(struct edd_device *edev, char *buf)
288
{
289
        struct edd_info *info;
290
        char *p = buf;
291
        if (!edev)
292
                return -EINVAL;
293
        info = edd_dev_get_info(edev);
294
        if (!info || !buf)
295
                return -EINVAL;
296
 
297
        if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
298
                p += scnprintf(p, left, "Fixed disk access\n");
299
        }
300
        if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
301
                p += scnprintf(p, left, "Device locking and ejecting\n");
302
        }
303
        if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
304
                p += scnprintf(p, left, "Enhanced Disk Drive support\n");
305
        }
306
        if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
307
                p += scnprintf(p, left, "64-bit extensions\n");
308
        }
309
        return (p - buf);
310
}
311
 
312
static ssize_t
313
edd_show_info_flags(struct edd_device *edev, char *buf)
314
{
315
        struct edd_info *info;
316
        char *p = buf;
317
        if (!edev)
318
                return -EINVAL;
319
        info = edd_dev_get_info(edev);
320
        if (!info || !buf)
321
                return -EINVAL;
322
 
323
        if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT)
324
                p += scnprintf(p, left, "DMA boundary error transparent\n");
325
        if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
326
                p += scnprintf(p, left, "geometry valid\n");
327
        if (info->params.info_flags & EDD_INFO_REMOVABLE)
328
                p += scnprintf(p, left, "removable\n");
329
        if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
330
                p += scnprintf(p, left, "write verify\n");
331
        if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
332
                p += scnprintf(p, left, "media change notification\n");
333
        if (info->params.info_flags & EDD_INFO_LOCKABLE)
334
                p += scnprintf(p, left, "lockable\n");
335
        if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
336
                p += scnprintf(p, left, "no media present\n");
337
        if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
338
                p += scnprintf(p, left, "use int13 fn50\n");
339
        return (p - buf);
340
}
341
 
342
static ssize_t
343
edd_show_legacy_max_cylinder(struct edd_device *edev, char *buf)
344
{
345
        struct edd_info *info;
346
        char *p = buf;
347
        if (!edev)
348
                return -EINVAL;
349
        info = edd_dev_get_info(edev);
350
        if (!info || !buf)
351
                return -EINVAL;
352
 
353
        p += snprintf(p, left, "%u\n", info->legacy_max_cylinder);
354
        return (p - buf);
355
}
356
 
357
static ssize_t
358
edd_show_legacy_max_head(struct edd_device *edev, char *buf)
359
{
360
        struct edd_info *info;
361
        char *p = buf;
362
        if (!edev)
363
                return -EINVAL;
364
        info = edd_dev_get_info(edev);
365
        if (!info || !buf)
366
                return -EINVAL;
367
 
368
        p += snprintf(p, left, "%u\n", info->legacy_max_head);
369
        return (p - buf);
370
}
371
 
372
static ssize_t
373
edd_show_legacy_sectors_per_track(struct edd_device *edev, char *buf)
374
{
375
        struct edd_info *info;
376
        char *p = buf;
377
        if (!edev)
378
                return -EINVAL;
379
        info = edd_dev_get_info(edev);
380
        if (!info || !buf)
381
                return -EINVAL;
382
 
383
        p += snprintf(p, left, "%u\n", info->legacy_sectors_per_track);
384
        return (p - buf);
385
}
386
 
387
static ssize_t
388
edd_show_default_cylinders(struct edd_device *edev, char *buf)
389
{
390
        struct edd_info *info;
391
        char *p = buf;
392
        if (!edev)
393
                return -EINVAL;
394
        info = edd_dev_get_info(edev);
395
        if (!info || !buf)
396
                return -EINVAL;
397
 
398
        p += scnprintf(p, left, "%u\n", info->params.num_default_cylinders);
399
        return (p - buf);
400
}
401
 
402
static ssize_t
403
edd_show_default_heads(struct edd_device *edev, char *buf)
404
{
405
        struct edd_info *info;
406
        char *p = buf;
407
        if (!edev)
408
                return -EINVAL;
409
        info = edd_dev_get_info(edev);
410
        if (!info || !buf)
411
                return -EINVAL;
412
 
413
        p += scnprintf(p, left, "%u\n", info->params.num_default_heads);
414
        return (p - buf);
415
}
416
 
417
static ssize_t
418
edd_show_default_sectors_per_track(struct edd_device *edev, char *buf)
419
{
420
        struct edd_info *info;
421
        char *p = buf;
422
        if (!edev)
423
                return -EINVAL;
424
        info = edd_dev_get_info(edev);
425
        if (!info || !buf)
426
                return -EINVAL;
427
 
428
        p += scnprintf(p, left, "%u\n", info->params.sectors_per_track);
429
        return (p - buf);
430
}
431
 
432
static ssize_t
433
edd_show_sectors(struct edd_device *edev, char *buf)
434
{
435
        struct edd_info *info;
436
        char *p = buf;
437
        if (!edev)
438
                return -EINVAL;
439
        info = edd_dev_get_info(edev);
440
        if (!info || !buf)
441
                return -EINVAL;
442
 
443
        p += scnprintf(p, left, "%llu\n", info->params.number_of_sectors);
444
        return (p - buf);
445
}
446
 
447
 
448
/*
449
 * Some device instances may not have all the above attributes,
450
 * or the attribute values may be meaningless (i.e. if
451
 * the device is < EDD 3.0, it won't have host_bus and interface
452
 * information), so don't bother making files for them.  Likewise
453
 * if the default_{cylinders,heads,sectors_per_track} values
454
 * are zero, the BIOS doesn't provide sane values, don't bother
455
 * creating files for them either.
456
 */
457
 
458
static int
459
edd_has_legacy_max_cylinder(struct edd_device *edev)
460
{
461
        struct edd_info *info;
462
        if (!edev)
463
                return 0;
464
        info = edd_dev_get_info(edev);
465
        if (!info)
466
                return 0;
467
        return info->legacy_max_cylinder > 0;
468
}
469
 
470
static int
471
edd_has_legacy_max_head(struct edd_device *edev)
472
{
473
        struct edd_info *info;
474
        if (!edev)
475
                return 0;
476
        info = edd_dev_get_info(edev);
477
        if (!info)
478
                return 0;
479
        return info->legacy_max_head > 0;
480
}
481
 
482
static int
483
edd_has_legacy_sectors_per_track(struct edd_device *edev)
484
{
485
        struct edd_info *info;
486
        if (!edev)
487
                return 0;
488
        info = edd_dev_get_info(edev);
489
        if (!info)
490
                return 0;
491
        return info->legacy_sectors_per_track > 0;
492
}
493
 
494
static int
495
edd_has_default_cylinders(struct edd_device *edev)
496
{
497
        struct edd_info *info;
498
        if (!edev)
499
                return 0;
500
        info = edd_dev_get_info(edev);
501
        if (!info)
502
                return 0;
503
        return info->params.num_default_cylinders > 0;
504
}
505
 
506
static int
507
edd_has_default_heads(struct edd_device *edev)
508
{
509
        struct edd_info *info;
510
        if (!edev)
511
                return 0;
512
        info = edd_dev_get_info(edev);
513
        if (!info)
514
                return 0;
515
        return info->params.num_default_heads > 0;
516
}
517
 
518
static int
519
edd_has_default_sectors_per_track(struct edd_device *edev)
520
{
521
        struct edd_info *info;
522
        if (!edev)
523
                return 0;
524
        info = edd_dev_get_info(edev);
525
        if (!info)
526
                return 0;
527
        return info->params.sectors_per_track > 0;
528
}
529
 
530
static int
531
edd_has_edd30(struct edd_device *edev)
532
{
533
        struct edd_info *info;
534
        int i, nonzero_path = 0;
535
        char c;
536
 
537
        if (!edev)
538
                return 0;
539
        info = edd_dev_get_info(edev);
540
        if (!info)
541
                return 0;
542
 
543
        if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
544
                return 0;
545
        }
546
 
547
        for (i = 30; i <= 73; i++) {
548
                c = *(((uint8_t *) info) + i + 4);
549
                if (c) {
550
                        nonzero_path++;
551
                        break;
552
                }
553
        }
554
        if (!nonzero_path) {
555
                return 0;
556
        }
557
 
558
        return 1;
559
}
560
 
561
 
562
static EDD_DEVICE_ATTR(raw_data, 0444, edd_show_raw_data, edd_has_edd_info);
563
static EDD_DEVICE_ATTR(version, 0444, edd_show_version, edd_has_edd_info);
564
static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, edd_has_edd_info);
565
static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, edd_has_edd_info);
566
static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, edd_has_edd_info);
567
static EDD_DEVICE_ATTR(legacy_max_cylinder, 0444,
568
                       edd_show_legacy_max_cylinder,
569
                       edd_has_legacy_max_cylinder);
570
static EDD_DEVICE_ATTR(legacy_max_head, 0444, edd_show_legacy_max_head,
571
                       edd_has_legacy_max_head);
572
static EDD_DEVICE_ATTR(legacy_sectors_per_track, 0444,
573
                       edd_show_legacy_sectors_per_track,
574
                       edd_has_legacy_sectors_per_track);
575
static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders,
576
                       edd_has_default_cylinders);
577
static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads,
578
                       edd_has_default_heads);
579
static EDD_DEVICE_ATTR(default_sectors_per_track, 0444,
580
                       edd_show_default_sectors_per_track,
581
                       edd_has_default_sectors_per_track);
582
static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30);
583
static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30);
584
static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_mbr_signature, edd_has_mbr_signature);
585
 
586
 
587
/* These are default attributes that are added for every edd
588
 * device discovered.  There are none.
589
 */
590
static struct attribute * def_attrs[] = {
591
        NULL,
592
};
593
 
594
/* These attributes are conditional and only added for some devices. */
595
static struct edd_attribute * edd_attrs[] = {
596
        &edd_attr_raw_data,
597
        &edd_attr_version,
598
        &edd_attr_extensions,
599
        &edd_attr_info_flags,
600
        &edd_attr_sectors,
601
        &edd_attr_legacy_max_cylinder,
602
        &edd_attr_legacy_max_head,
603
        &edd_attr_legacy_sectors_per_track,
604
        &edd_attr_default_cylinders,
605
        &edd_attr_default_heads,
606
        &edd_attr_default_sectors_per_track,
607
        &edd_attr_interface,
608
        &edd_attr_host_bus,
609
        &edd_attr_mbr_signature,
610
        NULL,
611
};
612
 
613
/**
614
 *      edd_release - free edd structure
615
 *      @kobj:  kobject of edd structure
616
 *
617
 *      This is called when the refcount of the edd structure
618
 *      reaches 0. This should happen right after we unregister,
619
 *      but just in case, we use the release callback anyway.
620
 */
621
 
622
static void edd_release(struct kobject * kobj)
623
{
624
        struct edd_device * dev = to_edd_device(kobj);
625
        kfree(dev);
626
}
627
 
628
static struct kobj_type edd_ktype = {
629
        .release        = edd_release,
630
        .sysfs_ops      = &edd_attr_ops,
631
        .default_attrs  = def_attrs,
632
};
633
 
634
static decl_subsys(edd, &edd_ktype, NULL);
635
 
636
 
637
/**
638
 * edd_dev_is_type() - is this EDD device a 'type' device?
639
 * @edev: target edd_device
640
 * @type: a host bus or interface identifier string per the EDD spec
641
 *
642
 * Returns 1 (TRUE) if it is a 'type' device, 0 otherwise.
643
 */
644
static int
645
edd_dev_is_type(struct edd_device *edev, const char *type)
646
{
647
        struct edd_info *info;
648
        if (!edev)
649
                return 0;
650
        info = edd_dev_get_info(edev);
651
 
652
        if (type && info) {
653
                if (!strncmp(info->params.host_bus_type, type, strlen(type)) ||
654
                    !strncmp(info->params.interface_type, type, strlen(type)))
655
                        return 1;
656
        }
657
        return 0;
658
}
659
 
660
/**
661
 * edd_get_pci_dev() - finds pci_dev that matches edev
662
 * @edev: edd_device
663
 *
664
 * Returns pci_dev if found, or NULL
665
 */
666
static struct pci_dev *
667
edd_get_pci_dev(struct edd_device *edev)
668
{
669
        struct edd_info *info = edd_dev_get_info(edev);
670
 
671
        if (edd_dev_is_type(edev, "PCI")) {
672
                return pci_get_bus_and_slot(info->params.interface_path.pci.bus,
673
                                     PCI_DEVFN(info->params.interface_path.pci.slot,
674
                                               info->params.interface_path.pci.
675
                                               function));
676
        }
677
        return NULL;
678
}
679
 
680
static int
681
edd_create_symlink_to_pcidev(struct edd_device *edev)
682
{
683
 
684
        struct pci_dev *pci_dev = edd_get_pci_dev(edev);
685
        int ret;
686
        if (!pci_dev)
687
                return 1;
688
        ret = sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
689
        pci_dev_put(pci_dev);
690
        return ret;
691
}
692
 
693
static inline void
694
edd_device_unregister(struct edd_device *edev)
695
{
696
        kobject_unregister(&edev->kobj);
697
}
698
 
699
static void edd_populate_dir(struct edd_device * edev)
700
{
701
        struct edd_attribute * attr;
702
        int error = 0;
703
        int i;
704
 
705
        for (i = 0; (attr = edd_attrs[i]) && !error; i++) {
706
                if (!attr->test ||
707
                    (attr->test && attr->test(edev)))
708
                        error = sysfs_create_file(&edev->kobj,&attr->attr);
709
        }
710
 
711
        if (!error) {
712
                edd_create_symlink_to_pcidev(edev);
713
        }
714
}
715
 
716
static int
717
edd_device_register(struct edd_device *edev, int i)
718
{
719
        int error;
720
 
721
        if (!edev)
722
                return 1;
723
        edd_dev_set_info(edev, i);
724
        kobject_set_name(&edev->kobj, "int13_dev%02x",
725
                         0x80 + i);
726
        kobj_set_kset_s(edev,edd_subsys);
727
        error = kobject_register(&edev->kobj);
728
        if (!error)
729
                edd_populate_dir(edev);
730
        return error;
731
}
732
 
733
static inline int edd_num_devices(void)
734
{
735
        return max_t(unsigned char,
736
                     min_t(unsigned char, EDD_MBR_SIG_MAX, edd.mbr_signature_nr),
737
                     min_t(unsigned char, EDDMAXNR, edd.edd_info_nr));
738
}
739
 
740
/**
741
 * edd_init() - creates sysfs tree of EDD data
742
 */
743
static int __init
744
edd_init(void)
745
{
746
        unsigned int i;
747
        int rc=0;
748
        struct edd_device *edev;
749
 
750
        printk(KERN_INFO "BIOS EDD facility v%s %s, %d devices found\n",
751
               EDD_VERSION, EDD_DATE, edd_num_devices());
752
 
753
        if (!edd_num_devices()) {
754
                printk(KERN_INFO "EDD information not available.\n");
755
                return 1;
756
        }
757
 
758
        rc = firmware_register(&edd_subsys);
759
        if (rc)
760
                return rc;
761
 
762
        for (i = 0; i < edd_num_devices() && !rc; i++) {
763
                edev = kzalloc(sizeof (*edev), GFP_KERNEL);
764
                if (!edev)
765
                        return -ENOMEM;
766
 
767
                rc = edd_device_register(edev, i);
768
                if (rc) {
769
                        kfree(edev);
770
                        break;
771
                }
772
                edd_devices[i] = edev;
773
        }
774
 
775
        if (rc)
776
                firmware_unregister(&edd_subsys);
777
        return rc;
778
}
779
 
780
static void __exit
781
edd_exit(void)
782
{
783
        int i;
784
        struct edd_device *edev;
785
 
786
        for (i = 0; i < edd_num_devices(); i++) {
787
                if ((edev = edd_devices[i]))
788
                        edd_device_unregister(edev);
789
        }
790
        firmware_unregister(&edd_subsys);
791
}
792
 
793
late_initcall(edd_init);
794
module_exit(edd_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.