* projects 1572D, 1484D, 1386D, 1226DT
* disk signature read by Matt Domsch <Matt_Domsch@dell.com>
* and Andrew Wilks <Andrew_Wilks@dell.com> September 2003
+ * legacy CHS retreival by Patrick J. LoPresti <patl@users.sourceforge.net>
+ * March 2004
*/
#include <linux/config.h>
pushw %ds
popw %es
movw $EDDBUF, %bx
- int $0x13
+ pushw %dx # work around buggy BIOSes
+ stc # work around buggy BIOSes
+ int $0x13
+ sti # work around buggy BIOSes
+ popw %dx
jc disk_sig_done
movl (EDDBUF+MBR_SIG_OFFSET), %eax
movl %eax, (DISK80_SIG_BUFFER) # store success
# This consists of two calls:
# int 13h ah=41h "Check Extensions Present"
# int 13h ah=48h "Get Device Parameters"
+# int 13h ah=08h "Legacy Get Device Parameters"
#
# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
# in the empty_zero_page at EDDBUF. The first four bytes of which are
# used to store the device number, interface support map and version
-# results from fn41. The following 74 bytes are used to store
-# the results from fn48. Starting from device 80h, fn41, then fn48
+# results from fn41. The next four bytes are used to store the legacy
+# cylinders, heads, and sectors from fn08. The following 74 bytes are used to
+# store the results from fn48. Starting from device 80h, fn41, then fn48
# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
# Then the pointer is incremented to store the data for the next call.
# This repeats until either a device doesn't exist, or until EDDMAXNR
# devices have been stored.
-# The one tricky part is that ds:si always points four bytes into
-# the structure, and the fn41 results are stored at offsets
+# The one tricky part is that ds:si always points EDDEXTSIZE bytes into
+# the structure, and the fn41 and fn08 results are stored at offsets
# from there. This removes the need to increment the pointer for
# every store, and leaves it ready for the fn48 call.
# A second one-byte buffer, EDDNR, in the empty_zero_page stores
# the number of BIOS devices which exist, up to EDDMAXNR.
# In setup.c, copy_edd() stores both empty_zero_page buffers away
-# for later use, as they would get overwritten otherwise.
+# for later use, as they would get overwritten otherwise.
# This code is sensitive to the size of the structs in edd.h
-edd_start:
+edd_start:
# %ds points to the bootsector
# result buffer for fn48
- movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results
- # kept just before that
+ movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results
+ # kept just before that
movb $0, (EDDNR) # zero value at EDDNR
- movb $0x80, %dl # BIOS device 0x80
+ movb $0x80, %dl # BIOS device 0x80
edd_check_ext:
movb $CHECKEXTENSIONSPRESENT, %ah # Function 41
int $0x13 # make the call
jc edd_done # no more BIOS devices
- cmpw $EDDMAGIC2, %bx # is magic right?
+ cmpw $EDDMAGIC2, %bx # is magic right?
jne edd_next # nope, next...
- movb %dl, %ds:-4(%si) # store device number
- movb %ah, %ds:-3(%si) # store version
- movw %cx, %ds:-2(%si) # store extensions
+ movb %dl, %ds:-8(%si) # store device number
+ movb %ah, %ds:-7(%si) # store version
+ movw %cx, %ds:-6(%si) # store extensions
incb (EDDNR) # note that we stored something
-
-edd_get_device_params:
+
+edd_get_device_params:
movw $EDDPARMSIZE, %ds:(%si) # put size
- movb $GETDEVICEPARAMETERS, %ah # Function 48
+ movw $0x0, %ds:2(%si) # work around buggy BIOSes
+ movb $GETDEVICEPARAMETERS, %ah # Function 48
int $0x13 # make the call
# Don't check for fail return
# it doesn't matter.
+edd_get_legacy_chs:
+ xorw %ax, %ax
+ movw %ax, %ds:-4(%si)
+ movw %ax, %ds:-2(%si)
+ # Ralf Brown's Interrupt List says to set ES:DI to
+ # 0000h:0000h "to guard against BIOS bugs"
+ pushw %es
+ movw %ax, %es
+ movw %ax, %di
+ pushw %dx # legacy call clobbers %dl
+ movb $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
+ int $0x13 # make the call
+ jc edd_legacy_done # failed
+ movb %cl, %al # Low 6 bits are max
+ andb $0x3F, %al # sector number
+ movb %al, %ds:-1(%si) # Record max sect
+ movb %dh, %ds:-2(%si) # Record max head number
+ movb %ch, %al # Low 8 bits of max cyl
+ shr $6, %cl
+ movb %cl, %ah # High 2 bits of max cyl
+ movw %ax, %ds:-4(%si)
+
+edd_legacy_done:
+ popw %dx
+ popw %es
movw %si, %ax # increment si
addw $EDDPARMSIZE+EDDEXTSIZE, %ax
movw %ax, %si
edd_next:
- incb %dl # increment to next device
- cmpb $EDDMAXNR, (EDDNR) # Out of space?
+ incb %dl # increment to next device
+ cmpb $EDDMAXNR, (EDDNR) # Out of space?
jb edd_check_ext # keep looping
-
-edd_done:
+
+edd_done:
#endif
# Now we want to move to protected mode ...
/*
* linux/arch/i386/kernel/edd.c
- * Copyright (C) 2002, 2003 Dell Inc.
+ * Copyright (C) 2002, 2003, 2004 Dell Inc.
* by Matt Domsch <Matt_Domsch@dell.com>
* disk80 signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
+ * legacy CHS by Patrick J. LoPresti <patl@users.sourceforge.net>
*
* BIOS Enhanced Disk Drive Services (EDD)
* conformant to T13 Committee www.t13.org
MODULE_DESCRIPTION("sysfs interface to BIOS EDD information");
MODULE_LICENSE("GPL");
-#define EDD_VERSION "0.12 2004-Jan-26"
+#define EDD_VERSION "0.13 2004-Mar-09"
#define EDD_DEVICE_NAME_SIZE 16
#define REPORT_URL "http://linux.dell.com/edd/results.html"
edd_show_raw_data(struct edd_device *edev, char *buf)
{
struct edd_info *info = edd_dev_get_info(edev);
- ssize_t len = sizeof (*info) - 4;
+ ssize_t len = sizeof (info->params);
if (!edev || !info || !buf) {
return -EINVAL;
}
len = info->params.length;
/* In case of buggy BIOSs */
- if (len > (sizeof(*info) - 4))
- len = sizeof(*info) - 4;
+ if (len > (sizeof(info->params)))
+ len = sizeof(info->params);
- memcpy(buf, ((char *)info) + 4, len);
+ memcpy(buf, &info->params, len);
return len;
}
return (p - buf);
}
+static ssize_t
+edd_show_legacy_cylinders(struct edd_device *edev, char *buf)
+{
+ struct edd_info *info = edd_dev_get_info(edev);
+ char *p = buf;
+ if (!edev || !info || !buf) {
+ return -EINVAL;
+ }
+
+ p += snprintf(p, left, "0x%x\n", info->legacy_cylinders);
+ return (p - buf);
+}
+
+static ssize_t
+edd_show_legacy_heads(struct edd_device *edev, char *buf)
+{
+ struct edd_info *info = edd_dev_get_info(edev);
+ char *p = buf;
+ if (!edev || !info || !buf) {
+ return -EINVAL;
+ }
+
+ p += snprintf(p, left, "0x%x\n", info->legacy_heads);
+ return (p - buf);
+}
+
+static ssize_t
+edd_show_legacy_sectors(struct edd_device *edev, char *buf)
+{
+ struct edd_info *info = edd_dev_get_info(edev);
+ char *p = buf;
+ if (!edev || !info || !buf) {
+ return -EINVAL;
+ }
+
+ p += snprintf(p, left, "0x%x\n", info->legacy_sectors);
+ return (p - buf);
+}
+
static ssize_t
edd_show_default_cylinders(struct edd_device *edev, char *buf)
{
* creating files for them either.
*/
+static int
+edd_has_legacy_cylinders(struct edd_device *edev)
+{
+ struct edd_info *info = edd_dev_get_info(edev);
+ if (!edev || !info)
+ return -EINVAL;
+ return info->legacy_cylinders > 0;
+}
+
+static int
+edd_has_legacy_heads(struct edd_device *edev)
+{
+ struct edd_info *info = edd_dev_get_info(edev);
+ if (!edev || !info)
+ return -EINVAL;
+ return info->legacy_heads > 0;
+}
+
+static int
+edd_has_legacy_sectors(struct edd_device *edev)
+{
+ struct edd_info *info = edd_dev_get_info(edev);
+ if (!edev || !info)
+ return -EINVAL;
+ return info->legacy_sectors > 0;
+}
+
static int
edd_has_default_cylinders(struct edd_device *edev)
{
static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, NULL);
static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, NULL);
static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, NULL);
+static EDD_DEVICE_ATTR(legacy_cylinders, 0444, edd_show_legacy_cylinders,
+ edd_has_legacy_cylinders);
+static EDD_DEVICE_ATTR(legacy_heads, 0444, edd_show_legacy_heads,
+ edd_has_legacy_heads);
+static EDD_DEVICE_ATTR(legacy_sectors, 0444, edd_show_legacy_sectors,
+ edd_has_legacy_sectors);
static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders,
edd_has_default_cylinders);
static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads,
/* These attributes are conditional and only added for some devices. */
static struct edd_attribute * edd_attrs[] = {
+ &edd_attr_legacy_cylinders,
+ &edd_attr_legacy_heads,
+ &edd_attr_legacy_sectors,
&edd_attr_default_cylinders,
&edd_attr_default_heads,
&edd_attr_default_sectors_per_track,