hdt: Implement DEL behavior in cli mode
[profile/ivi/syslinux.git] / com32 / hdt / hdt-ata.c
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2009 Erwan Velu - All Rights Reserved
4  *
5  *   Permission is hereby granted, free of charge, to any person
6  *   obtaining a copy of this software and associated documentation
7  *   files (the "Software"), to deal in the Software without
8  *   restriction, including without limitation the rights to use,
9  *   copy, modify, merge, publish, distribute, sublicense, and/or
10  *   sell copies of the Software, and to permit persons to whom
11  *   the Software is furnished to do so, subject to the following
12  *   conditions:
13  *
14  *   The above copyright notice and this permission notice shall
15  *   be included in all copies or substantial portions of the Software.
16  *
17  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  *   OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * -----------------------------------------------------------------------
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <console.h>
33 #include <getkey.h>
34
35 #include "com32io.h"
36 #include "hdt-common.h"
37 #include "hdt-ata.h"
38
39 #ifdef ATA
40 /**
41  *      ata_id_string - Convert IDENTIFY DEVICE page into string
42  *      @id: IDENTIFY DEVICE results we will examine
43  *      @s: string into which data is output
44  *      @ofs: offset into identify device page
45  *      @len: length of string to return. must be an even number.
46  *
47  *      The strings in the IDENTIFY DEVICE page are broken up into
48  *      16-bit chunks.  Run through the string, and output each
49  *      8-bit chunk linearly, regardless of platform.
50  *
51  *      LOCKING:
52  *      caller.
53  */
54 void ata_id_string(const uint16_t * id, unsigned char *s,
55        unsigned int ofs, unsigned int len)
56 {
57   unsigned int c;
58
59   while (len > 0) {
60     c = id[ofs] >> 8;
61     *s = c;
62     s++;
63
64     c = id[ofs] & 0xff;
65     *s = c;
66     s++;
67
68     ofs++;
69     len -= 2;
70   }
71 }
72
73 /**
74  *      ata_id_c_string - Convert IDENTIFY DEVICE page into C string
75  *      @id: IDENTIFY DEVICE results we will examine
76  *      @s: string into which data is output
77  *      @ofs: offset into identify device page
78  *      @len: length of string to return. must be an odd number.
79  *
80  *      This function is identical to ata_id_string except that it
81  *      trims trailing spaces and terminates the resulting string with
82  *      null.  @len must be actual maximum length (even number) + 1.
83  *
84  *      LOCKING:
85  *      caller.
86  */
87 void ata_id_c_string(const uint16_t * id, unsigned char *s,
88          unsigned int ofs, unsigned int len)
89 {
90   unsigned char *p;
91
92   //WARN_ON(!(len & 1));
93
94   ata_id_string(id, s, ofs, len - 1);
95
96   p = s + strnlen(s, len - 1);
97   while (p > s && p[-1] == ' ')
98     p--;
99   *p = '\0';
100 }
101 #endif
102
103 /**
104  * Call int 13h, but with retry on failure.  Especially floppies need this.
105  */
106 int int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
107 {
108   int retry = 6;    /* Number of retries */
109   com32sys_t tmpregs;
110
111   if (!outreg)
112     outreg = &tmpregs;
113
114   while (retry--) {
115     __intcall(0x13, inreg, outreg);
116     if (!(outreg->eflags.l & EFLAGS_CF))
117       return 0; /* CF=0, OK */
118   }
119
120   return -1;    /* Error */
121 }
122
123 /* Display CPU registers for debugging purposes */
124 void printregs(const com32sys_t * r)
125 {
126   printf("eflags = %08x  ds = %04x  es = %04x  fs = %04x  gs = %04x\n"
127          "eax = %08x  ebx = %08x  ecx = %08x  edx = %08x\n"
128          "ebp = %08x  esi = %08x  edi = %08x  esp = %08x\n",
129          r->eflags.l, r->ds, r->es, r->fs, r->gs,
130          r->eax.l, r->ebx.l, r->ecx.l, r->edx.l,
131          r->ebp.l, r->esi.l, r->edi.l, r->_unused_esp.l);
132 }
133
134 /* Try to get information for a given disk */
135 int get_disk_params(int disk, struct diskinfo *disk_info)
136 {
137   static com32sys_t getparm, parm, getebios, ebios, inreg, outreg;
138   struct device_parameter dp;
139 #ifdef ATA
140   struct ata_identify_device aid;
141 #endif
142
143   memset(&(disk_info[disk]), 0, sizeof(struct diskinfo));
144
145   disk_info[disk].disk = disk;
146   disk_info[disk].ebios = disk_info[disk].cbios = 0;
147
148   /* Sending int 13h func 41h to query EBIOS information */
149   memset(&getebios, 0, sizeof(com32sys_t));
150   memset(&ebios, 0, sizeof(com32sys_t));
151
152   /* Get EBIOS support */
153   getebios.eax.w[0] = 0x4100;
154   getebios.ebx.w[0] = 0x55aa;
155   getebios.edx.b[0] = disk;
156   getebios.eflags.b[0] = 0x3; /* CF set */
157
158   __intcall(0x13, &getebios, &ebios);
159
160   /* Detecting EDD support */
161   if (!(ebios.eflags.l & EFLAGS_CF) &&
162       ebios.ebx.w[0] == 0xaa55 && (ebios.ecx.b[0] & 1)) {
163     disk_info[disk].ebios = 1;
164     switch (ebios.eax.b[1]) {
165     case 32:
166       strlcpy(disk_info[disk].edd_version, "1.0", 3);
167       break;
168     case 33:
169       strlcpy(disk_info[disk].edd_version, "1.1", 3);
170       break;
171     case 48:
172       strlcpy(disk_info[disk].edd_version, "3.0", 3);
173       break;
174     default:
175       strlcpy(disk_info[disk].edd_version, "0", 1);
176       break;
177     }
178   }
179   /* Get disk parameters -- really only useful for
180    * hard disks, but if we have a partitioned floppy
181    * it's actually our best chance...
182    */
183   memset(&getparm, 0, sizeof(com32sys_t));
184   memset(&parm, 0, sizeof(com32sys_t));
185   getparm.eax.b[1] = 0x08;
186   getparm.edx.b[0] = disk;
187
188   __intcall(0x13, &getparm, &parm);
189
190   if (parm.eflags.l & EFLAGS_CF)
191     return disk_info[disk].ebios ? 0 : -1;
192
193   disk_info[disk].heads = parm.edx.b[1] + 1;
194   disk_info[disk].sectors_per_track = parm.ecx.b[0] & 0x3f;
195   if (disk_info[disk].sectors_per_track == 0) {
196     disk_info[disk].sectors_per_track = 1;
197   } else {
198     disk_info[disk].cbios = 1;  /* Valid geometry */
199   }
200
201 /* FIXME: memset to 0 make it fails
202  * memset(__com32.cs_bounce, 0, sizeof(struct device_pairameter)); */
203   memset(&dp, 0, sizeof(struct device_parameter));
204   memset(&inreg, 0, sizeof(com32sys_t));
205
206   /* Requesting Extended Read Drive Parameters via int13h func 48h */
207   inreg.esi.w[0] = OFFS(__com32.cs_bounce);
208   inreg.ds = SEG(__com32.cs_bounce);
209   inreg.eax.w[0] = 0x4800;
210   inreg.edx.b[0] = disk;
211
212   __intcall(0x13, &inreg, &outreg);
213
214   /* Saving bounce buffer before anything corrupt it */
215   memcpy(&dp, __com32.cs_bounce, sizeof(struct device_parameter));
216
217   if (outreg.eflags.l & EFLAGS_CF) {
218     more_printf("Disk 0x%X doesn't supports EDD 3.0\n", disk);
219     return -1;
220   }
221
222   /* Copying result to the disk_info structure
223    * host_bus_type, interface_type, sectors & cylinders */
224   snprintf(disk_info[disk].host_bus_type,
225      sizeof disk_info[disk].host_bus_type, "%c%c%c%c",
226      dp.host_bus_type[0], dp.host_bus_type[1], dp.host_bus_type[2],
227      dp.host_bus_type[3]);
228   snprintf(disk_info[disk].interface_type,
229      sizeof disk_info[disk].interface_type, "%c%c%c%c%c%c%c%c",
230      dp.interface_type[0], dp.interface_type[1],
231      dp.interface_type[2], dp.interface_type[3],
232      dp.interface_type[4], dp.interface_type[5],
233      dp.interface_type[6], dp.interface_type[7]);
234   disk_info[disk].sectors = dp.sectors;
235   disk_info[disk].cylinders = dp.cylinders;
236
237   /*FIXME: we have to find a way to grab the model & fw
238    * We do put dummy data until we found a solution */
239   snprintf(disk_info[disk].aid.model, sizeof disk_info[disk].aid.model,
240      "0x%X", disk);
241   snprintf(disk_info[disk].aid.fw_rev, sizeof disk_info[disk].aid.fw_rev,
242      "%s", "N/A");
243   snprintf(disk_info[disk].aid.serial_no,
244      sizeof disk_info[disk].aid.serial_no, "%s", "N/A");
245
246   /* Useless stuff before I figure how to send ata packets */
247 #ifdef ATA
248   memset(__com32.cs_bounce, 0, sizeof(struct device_parameter));
249   memset(&aid, 0, sizeof(struct ata_identify_device));
250   memset(&inreg, 0, sizeof inreg);
251   inreg.ebx.w[0] = OFFS(__com32.cs_bounce + 1024);
252   inreg.es = SEG(__com32.cs_bounce + 1024);
253   inreg.eax.w[0] = 0x2500;
254   inreg.edx.b[0] = disk;
255
256   __intcall(0x13, &inreg, &outreg);
257
258   memcpy(&aid, __com32.cs_bounce, sizeof(struct ata_identify_device));
259
260   if (outreg.eflags.l & EFLAGS_CF) {
261     more_printf("Disk 0x%X: Failed to Identify Device\n", disk);
262     //FIXME
263     return 0;
264   }
265 //   ata_id_c_string(aid, disk_info[disk].fwrev, ATA_ID_FW_REV, sizeof(disk_info[disk].fwrev));
266 //   ata_id_c_string(aid, disk_info[disk].model, ATA_ID_PROD,  sizeof(disk_info[disk].model));
267
268   char buff[sizeof(struct ata_identify_device)];
269   memcpy(buff, &aid, sizeof(struct ata_identify_device));
270   for (int j = 0; j < sizeof(struct ata_identify_device); j++)
271     more_printf("model=|%c|\n", buff[j]);
272   more_printf("Disk 0x%X : %s %s %s\n", disk, aid.model, aid.fw_rev,
273          aid.serial_no);
274 #endif
275
276   return 0;
277 }