1 /***************************************************************************
2  *                                                                         *
3  *    LIBDSK: General floppy and diskimage access library                  *
4  *    Copyright (C) 2001  John Elliott <seasip.webmaster@gmail.com>            *
5  *                                                                         *
6  *    This library is free software; you can redistribute it and/or        *
7  *    modify it under the terms of the GNU Library General Public          *
8  *    License as published by the Free Software Foundation; either         *
9  *    version 2 of the License, or (at your option) any later version.     *
10  *                                                                         *
11  *    This library is distributed in the hope that it will be useful,      *
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of       *
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    *
14  *    Library General Public License for more details.                     *
15  *                                                                         *
16  *    You should have received a copy of the GNU Library General Public    *
17  *    License along with this library; if not, write to the Free           *
18  *    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,      *
19  *    MA 02111-1307, USA                                                   *
20  *                                                                         *
21  ***************************************************************************/
22 
23 /* Functions to convert logical <--> physical tracks/sectors */
24 
25 #include "drvi.h"
26 
27 /* Convert physical sector to logical */
dg_ps2ls(const DSK_GEOMETRY * self,dsk_pcyl_t cyl,dsk_phead_t head,dsk_psect_t sec,dsk_lsect_t * logical)28 LDPUBLIC32 dsk_err_t LDPUBLIC16 dg_ps2ls(const DSK_GEOMETRY *self,
29 	/* in */	dsk_pcyl_t cyl, dsk_phead_t head, dsk_psect_t sec,
30 	/* out */	dsk_lsect_t *logical)
31 {
32 	dsk_ltrack_t track;
33 	dsk_lsect_t sector;
34 	dsk_err_t e;
35 
36 	e = dg_pt2lt(self, cyl, head, &track);
37    if (e) return e;
38 
39 	if (sec  < self->dg_secbase ||
40 	    sec  >= self->dg_secbase + self->dg_sectors) return DSK_ERR_BADPTR;
41 
42 	sector = track * self->dg_sectors;
43 	sector += (sec - self->dg_secbase);
44 
45 	if (logical) *logical = sector;
46 
47 	return DSK_ERR_OK;
48 }
49 
50 /* Convert logical sector to physical */
dg_ls2ps(const DSK_GEOMETRY * self,dsk_lsect_t logical,dsk_pcyl_t * cyl,dsk_phead_t * head,dsk_psect_t * sec)51 LDPUBLIC32 dsk_err_t LDPUBLIC16  dg_ls2ps(const DSK_GEOMETRY *self,
52 	/* in */	dsk_lsect_t logical,
53 	/* out */	dsk_pcyl_t *cyl, dsk_phead_t *head, dsk_psect_t *sec)
54 {
55 	dsk_err_t err;
56 
57 	if (!self) return DSK_ERR_BADPTR;
58 	if (!self->dg_sectors || !self->dg_heads) return DSK_ERR_DIVZERO;
59 
60 	if (logical >= self->dg_cylinders * self->dg_heads * self->dg_sectors)
61 		return DSK_ERR_BADPARM;
62 
63 	if (sec)
64 	{
65 		if (self->dg_sidedness == SIDES_EXTSURFACE)
66 		{
67 			dsk_phead_t h;
68 
69 			logical /= self->dg_sectors;
70 			err = dg_lt2pt(self, (dsk_ltrack_t)logical, cyl, &h);
71 			if (err) return err;
72 
73 			*sec = (dsk_psect_t)((logical % self->dg_sectors)
74 				+ h * self->dg_sectors
75 				+ self->dg_secbase);
76 
77 		}
78 		else
79 		{
80 			*sec = (dsk_psect_t)((logical % self->dg_sectors) + self->dg_secbase);
81 		}
82 	}
83 
84 	logical /= self->dg_sectors;
85 	return dg_lt2pt(self, (dsk_ltrack_t)logical, cyl, head);
86 }
87 
88 
89 
90 
91 /* Convert physical cyl/head to logical track */
dg_pt2lt(const DSK_GEOMETRY * self,dsk_pcyl_t cyl,dsk_phead_t head,dsk_ltrack_t * logical)92 LDPUBLIC32 dsk_err_t LDPUBLIC16  dg_pt2lt(const DSK_GEOMETRY *self,
93 	/* in */	dsk_pcyl_t cyl, dsk_phead_t head,
94 	/* out */	dsk_ltrack_t *logical)
95 {
96 	dsk_ltrack_t track = 0;
97 
98 	if (!self          ) return DSK_ERR_BADPTR;
99 	if (!self->dg_heads) return DSK_ERR_DIVZERO;
100 
101 	if (head >= self->dg_heads ||
102 	    cyl  >= self->dg_cylinders) return DSK_ERR_BADPARM;
103 
104 	switch(self->dg_sidedness)
105 	{
106 		case SIDES_EXTSURFACE:	/* [1.3.7] */
107 		case SIDES_ALT:		track = (cyl * self->dg_heads) + head; break;
108 		case SIDES_OUTBACK:	if (self->dg_heads > 2) return DSK_ERR_BADPARM;
109 					if (!head)	track = cyl;
110 					else		track = (2 * self->dg_cylinders) - (1 + cyl);
111 					break;
112 		case SIDES_OUTOUT:	track = (head * self->dg_cylinders) + cyl;
113 					break;
114 	}
115 
116 	if (logical) *logical = track;
117 
118 	return DSK_ERR_OK;
119 }
120 
121 /* Convert logical track to physical */
dg_lt2pt(const DSK_GEOMETRY * self,dsk_ltrack_t logical,dsk_pcyl_t * cyl,dsk_phead_t * head)122 LDPUBLIC32 dsk_err_t LDPUBLIC16 dg_lt2pt(const DSK_GEOMETRY *self,
123 	/* in */	dsk_ltrack_t logical,
124 	/* out */	dsk_pcyl_t *cyl, dsk_phead_t *head)
125 {
126 	dsk_pcyl_t c = 0;
127 	dsk_phead_t h = 0;
128 
129 	if (!self) return DSK_ERR_BADPTR;
130 	if (!self->dg_heads) return DSK_ERR_DIVZERO;
131 
132 	if (logical >= self->dg_cylinders * self->dg_heads)
133 		return DSK_ERR_BADPARM;
134 
135 	switch(self->dg_sidedness)
136 	{
137 		case SIDES_EXTSURFACE:	/* [1.3.7] */
138 		case SIDES_ALT:		c = (logical / self->dg_heads);
139 					h = (logical % self->dg_heads);
140 					break;
141 		case SIDES_OUTBACK:	if (self->dg_heads > 2) return DSK_ERR_BADPARM;
142 					if (logical < self->dg_cylinders)
143 					{
144 						c = logical;
145 						h = 0;
146 					}
147 					else
148 					{
149 						c = (2 * self->dg_cylinders) - (1 + logical);
150 						h = 1;
151 					}
152 					break;
153 		case SIDES_OUTOUT:	c = (logical % self->dg_cylinders);
154 					h = (logical / self->dg_cylinders);
155 					break;
156 	}
157 	if (cyl)  *cyl  = c;
158 	if (head) *head = h;
159 	return DSK_ERR_OK;
160 }
161 
162 
163 /* "Extended surface" discs have sector IDs that don't match the sectors'
164  * location on disc. This means, anywhere we reflect dsk_read() to dsk_xread(),
165  * we have to translate the physical location to the expected sector ID rather
166  * than assuming a 1:1 mapping. */
167 
dg_x_head(const DSK_GEOMETRY * dg,dsk_phead_t h)168 dsk_phead_t dg_x_head(const DSK_GEOMETRY *dg, dsk_phead_t h)
169 {
170 	if (dg == NULL) return h;
171 
172 	return (dg->dg_sidedness == SIDES_EXTSURFACE) ? 0 : h;
173 }
174 
dg_x_sector(const DSK_GEOMETRY * dg,dsk_phead_t h,dsk_psect_t sec)175 dsk_phead_t dg_x_sector(const DSK_GEOMETRY *dg, dsk_phead_t h, dsk_psect_t sec)
176 {
177 	if (dg == NULL) return sec;
178 
179 	if (dg->dg_sidedness == SIDES_EXTSURFACE)
180 		sec += h * dg->dg_sectors;
181 	return sec;
182 }
183 
184 
185