Subversion Repositories Kolibri OS

Rev

Rev 2257 | Rev 2381 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2257 Rev 2288
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2011. All rights reserved.      ;;
3
;; Copyright (C) KolibriOS team 2011. All rights reserved.      ;;
4
;; Distributed under terms of the GNU General Public License    ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
7
 
8
$Revision: 2257 $
8
$Revision: 2288 $
9
 
9
 
10
; =============================================================================
10
; =============================================================================
11
; ================================= Constants =================================
11
; ================================= Constants =================================
12
; =============================================================================
12
; =============================================================================
13
; Error codes for callback functions.
13
; Error codes for callback functions.
14
DISK_STATUS_OK		    = 0 ; success
14
DISK_STATUS_OK              = 0 ; success
15
DISK_STATUS_GENERAL_ERROR   = -1; if no other code is suitable
15
DISK_STATUS_GENERAL_ERROR   = -1; if no other code is suitable
16
DISK_STATUS_INVALID_CALL    = 1 ; invalid input parameters
16
DISK_STATUS_INVALID_CALL    = 1 ; invalid input parameters
17
DISK_STATUS_NO_MEDIA	    = 2 ; no media present
17
DISK_STATUS_NO_MEDIA        = 2 ; no media present
18
DISK_STATUS_END_OF_MEDIA    = 3 ; end of media while reading/writing data
18
DISK_STATUS_END_OF_MEDIA    = 3 ; end of media while reading/writing data
19
; Driver flags. Represent bits in DISK.DriverFlags.
19
; Driver flags. Represent bits in DISK.DriverFlags.
20
DISK_NO_INSERT_NOTIFICATION = 1
20
DISK_NO_INSERT_NOTIFICATION = 1
21
; Media flags. Represent bits in DISKMEDIAINFO.Flags.
21
; Media flags. Represent bits in DISKMEDIAINFO.Flags.
22
DISK_MEDIA_READONLY = 1
22
DISK_MEDIA_READONLY = 1
23
 
23
 
24
; If too many partitions are detected,there is probably an error on the disk.
24
; If too many partitions are detected,there is probably an error on the disk.
25
; 256 partitions should be enough for any reasonable use.
25
; 256 partitions should be enough for any reasonable use.
26
; Also, the same number is limiting the number of MBRs to process; if
26
; Also, the same number is limiting the number of MBRs to process; if
27
; too many MBRs are visible,there probably is a loop in the MBR structure.
27
; too many MBRs are visible,there probably is a loop in the MBR structure.
28
MAX_NUM_PARTITIONS = 256
28
MAX_NUM_PARTITIONS = 256
29
 
29
 
30
; =============================================================================
30
; =============================================================================
31
; ================================ Structures =================================
31
; ================================ Structures =================================
32
; =============================================================================
32
; =============================================================================
33
; This structure defines all callback functions for working with the physical
33
; This structure defines all callback functions for working with the physical
34
; device. They are implemented by a driver. Objects with this structure reside
34
; device. They are implemented by a driver. Objects with this structure reside
35
; in a driver.
35
; in a driver.
36
struct DISKFUNC
36
struct DISKFUNC
37
.strucsize	dd	?
37
.strucsize      dd      ?
38
; Size of the structure. This field is intended for possible extensions of
38
; Size of the structure. This field is intended for possible extensions of
39
; this structure. If a new function is added to this structure and a driver
39
; this structure. If a new function is added to this structure and a driver
40
; implements an old version, the caller can detect this by checking .strucsize,
40
; implements an old version, the caller can detect this by checking .strucsize,
41
; so the driver remains compatible.
41
; so the driver remains compatible.
42
.close		dd	?
42
.close          dd      ?
43
; The pointer to the function which frees all driver-specific resources for
43
; The pointer to the function which frees all driver-specific resources for
44
; the disk.
44
; the disk.
45
; Optional, may be NULL.
45
; Optional, may be NULL.
46
; void close(void* userdata);
46
; void close(void* userdata);
47
.closemedia	dd	?
47
.closemedia     dd      ?
48
; The pointer to the function which informs the driver that the kernel has
48
; The pointer to the function which informs the driver that the kernel has
49
; finished all processing with the current media. If media is removed, the
49
; finished all processing with the current media. If media is removed, the
50
; driver should decline all requests to that media with DISK_STATUS_NO_MEDIA,
50
; driver should decline all requests to that media with DISK_STATUS_NO_MEDIA,
51
; even if new media is inserted, until this function is called. If media is
51
; even if new media is inserted, until this function is called. If media is
52
; removed, a new call to 'disk_media_changed' is not allowed until this
52
; removed, a new call to 'disk_media_changed' is not allowed until this
53
; function is called.
53
; function is called.
54
; Optional, may be NULL (if media is not removable).
54
; Optional, may be NULL (if media is not removable).
55
; void closemedia(void* userdata);
55
; void closemedia(void* userdata);
56
.querymedia	dd	?
56
.querymedia     dd      ?
57
; The pointer to the function which determines capabilities of the media.
57
; The pointer to the function which determines capabilities of the media.
58
; int querymedia(void* userdata, DISKMEDIAINFO* info);
58
; int querymedia(void* userdata, DISKMEDIAINFO* info);
59
; Return value: one of DISK_STATUS_*
59
; Return value: one of DISK_STATUS_*
60
.read		dd	?
60
.read           dd      ?
61
; The pointer to the function which reads data from the device.
61
; The pointer to the function which reads data from the device.
62
; int read(void* userdata, void* buffer, __int64 startsector, int* numsectors);
62
; int read(void* userdata, void* buffer, __int64 startsector, int* numsectors);
63
; input: *numsectors = number of sectors to read
63
; input: *numsectors = number of sectors to read
64
; output: *numsectors = number of sectors which were successfully read
64
; output: *numsectors = number of sectors which were successfully read
65
; Return value: one of DISK_STATUS_*
65
; Return value: one of DISK_STATUS_*
66
.write		dd	?
66
.write          dd      ?
67
; The pointer to the function which writes data to the device.
67
; The pointer to the function which writes data to the device.
68
; Optional, may be NULL.
68
; Optional, may be NULL.
69
; int write(void* userdata, void* buffer, __int64 startsector, int* numsectors);
69
; int write(void* userdata, void* buffer, __int64 startsector, int* numsectors);
70
; input: *numsectors = number of sectors to write
70
; input: *numsectors = number of sectors to write
71
; output: *numsectors = number of sectors which were successfully written
71
; output: *numsectors = number of sectors which were successfully written
72
; Return value: one of DISK_STATUS_*
72
; Return value: one of DISK_STATUS_*
73
.flush		dd	?
73
.flush          dd      ?
74
; The pointer to the function which flushes the internal device cache.
74
; The pointer to the function which flushes the internal device cache.
75
; Optional, may be NULL.
75
; Optional, may be NULL.
76
; int flush(void* userdata);
76
; int flush(void* userdata);
77
; Return value: one of DISK_STATUS_*
77
; Return value: one of DISK_STATUS_*
78
; Note that read/write are called by the cache manager, so a driver should not
78
; Note that read/write are called by the cache manager, so a driver should not
79
; create a software cache. This function is implemented for flushing a hardware
79
; create a software cache. This function is implemented for flushing a hardware
80
; cache, if it exists.
80
; cache, if it exists.
81
.adjust_cache_size	dd	?
81
.adjust_cache_size      dd      ?
82
; The pointer to the function which returns the cache size for this device.
82
; The pointer to the function which returns the cache size for this device.
83
; Optional, may be NULL.
83
; Optional, may be NULL.
84
; unsigned int adjust_cache_size(unsigned int suggested_size);
84
; unsigned int adjust_cache_size(unsigned int suggested_size);
85
; Return value: 0 = disable cache, otherwise = used cache size in bytes.
85
; Return value: 0 = disable cache, otherwise = used cache size in bytes.
86
ends
86
ends
87
 
87
 
88
; This structure holds information on a medium.
88
; This structure holds information on a medium.
89
; Objects with this structure are allocated by the kernel as a part of the DISK
89
; Objects with this structure are allocated by the kernel as a part of the DISK
90
; structure and are filled by a driver in the 'querymedia' callback.
90
; structure and are filled by a driver in the 'querymedia' callback.
91
struct DISKMEDIAINFO
91
struct DISKMEDIAINFO
92
.Flags		dd	?
92
.Flags          dd      ?
93
; Combination of DISK_MEDIA_* bits.
93
; Combination of DISK_MEDIA_* bits.
94
.SectorSize	dd	?
94
.SectorSize     dd      ?
95
; Size of the sector.
95
; Size of the sector.
96
.Capacity	dq	?
96
.Capacity       dq      ?
97
; Size of the media in sectors.
97
; Size of the media in sectors.
98
ends
98
ends
99
 
99
 
100
; This structure represents the disk cache. To follow the old implementation,
100
; This structure represents the disk cache. To follow the old implementation,
101
; there are two distinct caches for a disk, one for "system" data,and the other
101
; there are two distinct caches for a disk, one for "system" data,and the other
102
; for "application" data.
102
; for "application" data.
103
struct DISKCACHE
103
struct DISKCACHE
104
.Lock		MUTEX
104
.Lock           MUTEX
105
; Lock to protect the cache.
105
; Lock to protect the cache.
106
; The following fields are inherited from data32.inc:cache_ideX.
106
; The following fields are inherited from data32.inc:cache_ideX.
107
.pointer     rd 1
107
.pointer     rd 1
108
.data_size   rd 1   ; not use
108
.data_size   rd 1   ; not use
109
.data	     rd 1
109
.data        rd 1
110
.sad_size    rd 1
110
.sad_size    rd 1
111
.search_start	    rd 1
111
.search_start       rd 1
112
ends
112
ends
113
 
113
 
114
; This structure represents a disk device and its media for the kernel.
114
; This structure represents a disk device and its media for the kernel.
115
; This structure is allocated by the kernel in the 'disk_add' function,
115
; This structure is allocated by the kernel in the 'disk_add' function,
116
; freed in the 'disk_dereference' function.
116
; freed in the 'disk_dereference' function.
117
struct DISK
117
struct DISK
118
; Fields of disk object
118
; Fields of disk object
119
.Next		dd	?
119
.Next           dd      ?
120
.Prev		dd	?
120
.Prev           dd      ?
121
; All disk devices are linked in one list with these two fields.
121
; All disk devices are linked in one list with these two fields.
122
; Head of the list is the 'disk_list' variable.
122
; Head of the list is the 'disk_list' variable.
123
.Functions	dd	?
123
.Functions      dd      ?
124
; Pointer to the 'DISKFUNC' structure with driver functions.
124
; Pointer to the 'DISKFUNC' structure with driver functions.
125
.Name		dd	?
125
.Name           dd      ?
126
; Pointer to the string used for accesses through the global filesystem.
126
; Pointer to the string used for accesses through the global filesystem.
127
.UserData	dd	?
127
.UserData       dd      ?
128
; This field is passed to all callback functions so a driver can decide which
128
; This field is passed to all callback functions so a driver can decide which
129
; physical device is addressed.
129
; physical device is addressed.
130
.DriverFlags	dd	?
130
.DriverFlags    dd      ?
131
; Bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit is defined.
131
; Bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit is defined.
132
; If it is set, the driver will never issue 'disk_media_changed' notification
132
; If it is set, the driver will never issue 'disk_media_changed' notification
133
; with argument set to true, so the kernel must try to detect media during
133
; with argument set to true, so the kernel must try to detect media during
134
; requests from the file system.
134
; requests from the file system.
135
.RefCount	dd	?
135
.RefCount       dd      ?
136
; Count of active references to this structure. One reference is kept during
136
; Count of active references to this structure. One reference is kept during
137
; the lifetime of the structure between 'disk_add' and 'disk_del'.
137
; the lifetime of the structure between 'disk_add' and 'disk_del'.
138
; Another reference is taken during any filesystem operation for this disk.
138
; Another reference is taken during any filesystem operation for this disk.
139
; One reference is added if media is inserted.
139
; One reference is added if media is inserted.
140
; The structure is destroyed when the reference count decrements to zero:
140
; The structure is destroyed when the reference count decrements to zero:
141
; this usually occurs in 'disk_del', but can be delayed to the end of last
141
; this usually occurs in 'disk_del', but can be delayed to the end of last
142
; filesystem operation, if one is active.
142
; filesystem operation, if one is active.
143
.MediaLock		MUTEX
143
.MediaLock              MUTEX
144
; Lock to protect the MEDIA structure. See the description after
144
; Lock to protect the MEDIA structure. See the description after
145
; 'disk_list_mutex' for the locking strategy.
145
; 'disk_list_mutex' for the locking strategy.
146
; Fields of media object
146
; Fields of media object
147
.MediaInserted		db	?
147
.MediaInserted          db      ?
148
; 0 if media is not inserted, nonzero otherwise.
148
; 0 if media is not inserted, nonzero otherwise.
149
.MediaUsed		db	?
149
.MediaUsed              db      ?
150
; 0 if media fields are not used, nonzero otherwise. If .MediaRefCount is
150
; 0 if media fields are not used, nonzero otherwise. If .MediaRefCount is
151
; nonzero, this field is nonzero too; however, when .MediaRefCount goes
151
; nonzero, this field is nonzero too; however, when .MediaRefCount goes
152
; to zero, there is some time interval during which media object is still used.
152
; to zero, there is some time interval during which media object is still used.
153
		align 4
153
                align 4
154
; The following fields are not valid unless either .MediaInserted is nonzero
154
; The following fields are not valid unless either .MediaInserted is nonzero
155
; or they are accessed from a code which has obtained the reference when
155
; or they are accessed from a code which has obtained the reference when
156
; .MediaInserted was nonzero.
156
; .MediaInserted was nonzero.
157
.MediaRefCount		dd	?
157
.MediaRefCount          dd      ?
158
; Count of active references to the media object. One reference is kept during
158
; Count of active references to the media object. One reference is kept during
159
; the lifetime of the media between two calls to 'disk_media_changed'.
159
; the lifetime of the media between two calls to 'disk_media_changed'.
160
; Another reference is taken during any filesystem operation for this media.
160
; Another reference is taken during any filesystem operation for this media.
161
; The callback 'closemedia' is called when the reference count decrements to
161
; The callback 'closemedia' is called when the reference count decrements to
162
; zero: this usually occurs in 'disk_media_changed', but can be delayed to the
162
; zero: this usually occurs in 'disk_media_changed', but can be delayed to the
163
; end of the last filesystem operation, if one is active.
163
; end of the last filesystem operation, if one is active.
164
.MediaInfo		DISKMEDIAINFO
164
.MediaInfo              DISKMEDIAINFO
165
; This field keeps information on the current media.
165
; This field keeps information on the current media.
166
.NumPartitions	dd	?
166
.NumPartitions  dd      ?
167
; Number of partitions on this media.
167
; Number of partitions on this media.
168
.Partitions	dd	?
168
.Partitions     dd      ?
169
; Pointer to array of .NumPartitions pointers to PARTITION structures.
169
; Pointer to array of .NumPartitions pointers to PARTITION structures.
170
.cache_size	dd	?
170
.cache_size     dd      ?
171
; inherited from cache_ideX_size
171
; inherited from cache_ideX_size
172
.SysCache	DISKCACHE
172
.SysCache       DISKCACHE
173
.AppCache	DISKCACHE
173
.AppCache       DISKCACHE
174
; Two caches for the disk.
174
; Two caches for the disk.
175
ends
175
ends
176
 
176
 
177
; This structure represents one partition for the kernel. This is a base
177
; This structure represents one partition for the kernel. This is a base
178
; template, the actual contents after common fields is determined by the
178
; template, the actual contents after common fields is determined by the
179
; file system code for this partition.
179
; file system code for this partition.
180
struct PARTITION
180
struct PARTITION
181
.FirstSector	dq	?
181
.FirstSector    dq      ?
182
; First sector of the partition.
182
; First sector of the partition.
183
.Length 	dq	?
183
.Length         dq      ?
184
; Length of the partition in sectors.
184
; Length of the partition in sectors.
185
.Disk		dd	?
185
.Disk           dd      ?
186
; Pointer to parent DISK structure.
186
; Pointer to parent DISK structure.
187
.FSUserFunctions	dd	?
187
.FSUserFunctions        dd      ?
188
; Handlers for the sysfunction 70h. This field is a pointer to the following
188
; Handlers for the sysfunction 70h. This field is a pointer to the following
189
; array. The first dword is a number of supported subfunctions, other dwords
189
; array. The first dword is a number of supported subfunctions, other dwords
190
; point to handlers of corresponding subfunctions.
190
; point to handlers of corresponding subfunctions.
191
; This field is 0 if file system is not recognized.
191
; This field is 0 if file system is not recognized.
192
; ...fs-specific data may follow...
192
; ...fs-specific data may follow...
193
ends
193
ends
194
 
194
 
195
; This is an external structure, it represents an entry in the partition table.
195
; This is an external structure, it represents an entry in the partition table.
196
struct PARTITION_TABLE_ENTRY
196
struct PARTITION_TABLE_ENTRY
197
.Bootable	db	?
197
.Bootable       db      ?
198
; 80h = bootable partition, 0 = non-bootable partition, other values = invalid
198
; 80h = bootable partition, 0 = non-bootable partition, other values = invalid
199
.FirstHead	db	?
199
.FirstHead      db      ?
200
.FirstSector	db	?
200
.FirstSector    db      ?
201
.FirstTrack	db	?
201
.FirstTrack     db      ?
202
; Coordinates of first sector in CHS.
202
; Coordinates of first sector in CHS.
203
.Type		db	?
203
.Type           db      ?
204
; Partition type, one of predefined constants. 0 = empty, several types denote
204
; Partition type, one of predefined constants. 0 = empty, several types denote
205
; extended partition (see process_partition_table_entry), we are not interested
205
; extended partition (see process_partition_table_entry), we are not interested
206
; in other values.
206
; in other values.
207
.LastHead	db	?
207
.LastHead       db      ?
208
.LastSector	db	?
208
.LastSector     db      ?
209
.LastTrack	db	?
209
.LastTrack      db      ?
210
; Coordinates of last sector in CHS.
210
; Coordinates of last sector in CHS.
211
.FirstAbsSector dd	?
211
.FirstAbsSector dd      ?
212
; Coordinate of first sector in LBA.
212
; Coordinate of first sector in LBA.
213
.Length 	dd	?
213
.Length         dd      ?
214
; Length of the partition in sectors.
214
; Length of the partition in sectors.
215
ends
215
ends
216
 
216
 
217
; =============================================================================
217
; =============================================================================
218
; ================================ Global data ================================
218
; ================================ Global data ================================
219
; =============================================================================
219
; =============================================================================
220
iglobal
220
iglobal
221
; The pseudo-item for the list of all DISK structures.
221
; The pseudo-item for the list of all DISK structures.
222
; Initialized to the empty list.
222
; Initialized to the empty list.
223
disk_list:
223
disk_list:
224
	dd	disk_list
224
        dd      disk_list
225
	dd	disk_list
225
        dd      disk_list
226
endg
226
endg
227
uglobal
227
uglobal
228
; This mutex guards all operations with the global list of DISK structures.
228
; This mutex guards all operations with the global list of DISK structures.
229
disk_list_mutex MUTEX
229
disk_list_mutex MUTEX
230
; * There are two dependent objects, a disk and a media. In the simplest case,
230
; * There are two dependent objects, a disk and a media. In the simplest case,
231
;   disk and media are both non-removable. However, in the general case both
231
;   disk and media are both non-removable. However, in the general case both
232
;   can be removed at any time, simultaneously or only media,and this makes things
232
;   can be removed at any time, simultaneously or only media,and this makes things
233
;   complicated.
233
;   complicated.
234
; * For efficiency, both disk and media objects are located in the one
234
; * For efficiency, both disk and media objects are located in the one
235
;   structure named DISK. However, logically they are different.
235
;   structure named DISK. However, logically they are different.
236
; * The following operations use data of disk object: adding (disk_add);
236
; * The following operations use data of disk object: adding (disk_add);
237
;   deleting (disk_del); filesystem (fs_lfn which eventually calls
237
;   deleting (disk_del); filesystem (fs_lfn which eventually calls
238
;   dyndisk_handler or dyndisk_enum_root).
238
;   dyndisk_handler or dyndisk_enum_root).
239
; * The following operations use data of media object: adding/removing
239
; * The following operations use data of media object: adding/removing
240
;   (disk_media_changed); filesystem (fs_lfn which eventually calls
240
;   (disk_media_changed); filesystem (fs_lfn which eventually calls
241
;   dyndisk_handler; dyndisk_enum_root doesn't work with media).
241
;   dyndisk_handler; dyndisk_enum_root doesn't work with media).
242
; * Notifications disk_add, disk_media_changed, disk_del are synchronized
242
; * Notifications disk_add, disk_media_changed, disk_del are synchronized
243
;   between themselves, this is a requirement for the driver. However, file
243
;   between themselves, this is a requirement for the driver. However, file
244
;   system operations are asynchronous, can be issued at any time by any
244
;   system operations are asynchronous, can be issued at any time by any
245
;   thread.
245
;   thread.
246
; * We must prevent a situation when a filesystem operation thinks that the
246
; * We must prevent a situation when a filesystem operation thinks that the
247
;   object is still valid but in fact the notification has destroyed the
247
;   object is still valid but in fact the notification has destroyed the
248
;   object. So we keep a reference counter for both disk and media and destroy
248
;   object. So we keep a reference counter for both disk and media and destroy
249
;   the object when this counter goes to zero.
249
;   the object when this counter goes to zero.
250
; * The driver must know when it is safe to free driver-allocated resources.
250
; * The driver must know when it is safe to free driver-allocated resources.
251
;   The object can be alive even after death notification has completed.
251
;   The object can be alive even after death notification has completed.
252
;   We use special callbacks to satisfy both assertions: 'close' for the disk
252
;   We use special callbacks to satisfy both assertions: 'close' for the disk
253
;   and 'closemedia' for the media. The destruction of the object includes
253
;   and 'closemedia' for the media. The destruction of the object includes
254
;   calling the corresponding callback.
254
;   calling the corresponding callback.
255
; * Each filesystem operation keeps one reference for the disk and one
255
; * Each filesystem operation keeps one reference for the disk and one
256
;   reference for the media. Notification disk_del forces notification on the
256
;   reference for the media. Notification disk_del forces notification on the
257
;   media death, so the reference counter for the disk is always not less than
257
;   media death, so the reference counter for the disk is always not less than
258
;   the reference counter for the media.
258
;   the reference counter for the media.
259
; * Two operations "get the object" and "increment the reference counter" can
259
; * Two operations "get the object" and "increment the reference counter" can
260
;   not be done simultaneously. We use a mutex to guard the consistency here.
260
;   not be done simultaneously. We use a mutex to guard the consistency here.
261
;   It must be a part of the container for the object, so that this mutex can
261
;   It must be a part of the container for the object, so that this mutex can
262
;   be acquired as a part of getting the object from the container. The
262
;   be acquired as a part of getting the object from the container. The
263
;   container for disk object is the global list, and this list is guarded by
263
;   container for disk object is the global list, and this list is guarded by
264
;   'disk_list_mutex'. The container for media object is the disk object, and
264
;   'disk_list_mutex'. The container for media object is the disk object, and
265
;   the corresponding mutex is DISK.MediaLock.
265
;   the corresponding mutex is DISK.MediaLock.
266
; * Notifications do not change the data of objects, they can only remove
266
; * Notifications do not change the data of objects, they can only remove
267
;   objects. Thus we don't need another synchronization at this level. If two
267
;   objects. Thus we don't need another synchronization at this level. If two
268
;   filesystem operations are referencing the same filesystem data, this is
268
;   filesystem operations are referencing the same filesystem data, this is
269
;   better resolved at the level of the filesystem.
269
;   better resolved at the level of the filesystem.
270
endg
270
endg
271
 
271
 
272
iglobal
272
iglobal
273
; The function 'disk_scan_partitions' needs three 512-byte buffers for
273
; The function 'disk_scan_partitions' needs three 512-byte buffers for
274
; MBR, bootsector and fs-temporary sector data. It can not use the static
274
; MBR, bootsector and fs-temporary sector data. It can not use the static
275
; buffers always, since it can be called for two or more disks in parallel.
275
; buffers always, since it can be called for two or more disks in parallel.
276
; However, this case is not typical. We reserve three static 512-byte buffers
276
; However, this case is not typical. We reserve three static 512-byte buffers
277
; and a flag that these buffers are currently used. If 'disk_scan_partitions'
277
; and a flag that these buffers are currently used. If 'disk_scan_partitions'
278
; detects that the buffers are currently used, it allocates buffers from the
278
; detects that the buffers are currently used, it allocates buffers from the
279
; heap.
279
; heap.
280
; The flag is implemented as a global dword variable. When the static buffers
280
; The flag is implemented as a global dword variable. When the static buffers
281
; are not used, the value is -1. When the static buffers are used, the value
281
; are not used, the value is -1. When the static buffers are used, the value
282
; is normally 0 and temporarily can become greater. The function increments
282
; is normally 0 and temporarily can become greater. The function increments
283
; this value. If the resulting value is zero, it uses the buffers and
283
; this value. If the resulting value is zero, it uses the buffers and
284
; decrements the value when the job is done. Otherwise, it immediately
284
; decrements the value when the job is done. Otherwise, it immediately
285
; decrements the value and uses buffers from the heap, allocated in the
285
; decrements the value and uses buffers from the heap, allocated in the
286
; beginning and freed in the end.
286
; beginning and freed in the end.
287
partition_buffer_users	dd	-1
287
partition_buffer_users  dd      -1
288
endg
288
endg
289
uglobal
289
uglobal
290
; The static buffers for MBR, bootsector and fs-temporary sector data.
290
; The static buffers for MBR, bootsector and fs-temporary sector data.
291
align 16
291
align 16
292
mbr_buffer	rb	512
292
mbr_buffer      rb      512
293
bootsect_buffer rb	512
293
bootsect_buffer rb      512
294
fs_tmp_buffer	rb	512
294
fs_tmp_buffer   rb      512
295
endg
295
endg
296
 
296
 
297
iglobal
297
iglobal
298
; This is the array of default implementations of driver callbacks.
298
; This is the array of default implementations of driver callbacks.
299
; Same as DRIVERFUNC structure except for the first field; all functions must
299
; Same as DRIVERFUNC structure except for the first field; all functions must
300
; have the default implementations.
300
; have the default implementations.
301
align 4
301
align 4
302
disk_default_callbacks:
302
disk_default_callbacks:
303
	dd	disk_default_close
303
        dd      disk_default_close
304
	dd	disk_default_closemedia
304
        dd      disk_default_closemedia
305
	dd	disk_default_querymedia
305
        dd      disk_default_querymedia
306
	dd	disk_default_read
306
        dd      disk_default_read
307
	dd	disk_default_write
307
        dd      disk_default_write
308
	dd	disk_default_flush
308
        dd      disk_default_flush
309
	dd	disk_default_adjust_cache_size
309
        dd      disk_default_adjust_cache_size
310
endg
310
endg
311
 
311
 
312
; =============================================================================
312
; =============================================================================
313
; ================================= Functions =================================
313
; ================================= Functions =================================
314
; =============================================================================
314
; =============================================================================
315
 
315
 
316
; This function registers a disk device.
316
; This function registers a disk device.
317
; This includes:
317
; This includes:
318
; - allocating an internal structure describing this device;
318
; - allocating an internal structure describing this device;
319
; - registering this structure in the global filesystem.
319
; - registering this structure in the global filesystem.
320
; The function initializes the disk as if there is no media. If a media is
320
; The function initializes the disk as if there is no media. If a media is
321
; present, the function 'disk_media_changed' should be called after this
321
; present, the function 'disk_media_changed' should be called after this
322
; function succeeds.
322
; function succeeds.
323
; Parameters:
323
; Parameters:
324
; [esp+4] = pointer to DISKFUNC structure with the callbacks
324
; [esp+4] = pointer to DISKFUNC structure with the callbacks
325
; [esp+8] = pointer to name (ASCIIZ string)
325
; [esp+8] = pointer to name (ASCIIZ string)
326
; [esp+12] = userdata to be passed to the callbacks as is.
326
; [esp+12] = userdata to be passed to the callbacks as is.
327
; [esp+16] = flags, bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit
327
; [esp+16] = flags, bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit
328
;            is defined.
328
;            is defined.
329
; Return value:
329
; Return value:
330
; NULL = operation has failed
330
; NULL = operation has failed
331
; non-NULL = handle of the disk. This handle can be used
331
; non-NULL = handle of the disk. This handle can be used
332
; in the operations with other Disk* functions.
332
; in the operations with other Disk* functions.
333
; The handle is the pointer to the internal structure DISK.
333
; The handle is the pointer to the internal structure DISK.
334
disk_add:
334
disk_add:
335
	push	ebx esi 	; save used registers to be stdcall
335
        push    ebx esi         ; save used registers to be stdcall
336
; 1. Allocate the DISK structure.
336
; 1. Allocate the DISK structure.
337
; 1a. Call the heap manager.
337
; 1a. Call the heap manager.
338
	push	sizeof.DISK
338
        push    sizeof.DISK
339
	pop	eax
339
        pop     eax
340
	call	malloc
340
        call    malloc
341
; 1b. Check the result. If allocation failed, return (go to 9) with eax = 0.
341
; 1b. Check the result. If allocation failed, return (go to 9) with eax = 0.
342
	test	eax, eax
342
        test    eax, eax
343
	jz	.nothing
343
        jz      .nothing
344
; 2. Copy the disk name to the DISK structure.
344
; 2. Copy the disk name to the DISK structure.
345
; 2a. Get length of the name, including the terminating zero.
345
; 2a. Get length of the name, including the terminating zero.
346
	mov	ebx, [esp+8+8]	; ebx = pointer to name
346
        mov     ebx, [esp+8+8]  ; ebx = pointer to name
347
	push	eax		; save allocated pointer to DISK
347
        push    eax             ; save allocated pointer to DISK
348
	xor	eax, eax	; the argument of malloc() is in eax
348
        xor     eax, eax        ; the argument of malloc() is in eax
349
@@:
349
@@:
350
	inc	eax
350
        inc     eax
351
	cmp	byte [ebx+eax-1], 0
351
        cmp     byte [ebx+eax-1], 0
352
	jnz	@b
352
        jnz     @b
353
; 2b. Call the heap manager.
353
; 2b. Call the heap manager.
354
	call	malloc
354
        call    malloc
355
; 2c. Check the result. If allocation failed, go to 7.
355
; 2c. Check the result. If allocation failed, go to 7.
356
	pop	esi		; restore allocated pointer to DISK
356
        pop     esi             ; restore allocated pointer to DISK
357
	test	eax, eax
357
        test    eax, eax
358
	jz	.free
358
        jz      .free
359
; 2d. Store the allocated pointer to the DISK structure.
359
; 2d. Store the allocated pointer to the DISK structure.
360
	mov	[esi+DISK.Name], eax
360
        mov     [esi+DISK.Name], eax
361
; 2e. Copy the name.
361
; 2e. Copy the name.
362
@@:
362
@@:
363
	mov	dl, [ebx]
363
        mov     dl, [ebx]
364
	mov	[eax], dl
364
        mov     [eax], dl
365
	inc	ebx
365
        inc     ebx
366
	inc	eax
366
        inc     eax
367
	test	dl, dl
367
        test    dl, dl
368
	jnz	@b
368
        jnz     @b
369
; 3. Copy other arguments of the function to the DISK structure.
369
; 3. Copy other arguments of the function to the DISK structure.
370
	mov	eax, [esp+4+8]
370
        mov     eax, [esp+4+8]
371
	mov	[esi+DISK.Functions], eax
371
        mov     [esi+DISK.Functions], eax
372
	mov	eax, [esp+12+8]
372
        mov     eax, [esp+12+8]
373
	mov	[esi+DISK.UserData], eax
373
        mov     [esi+DISK.UserData], eax
374
	mov	eax, [esp+16+8]
374
        mov     eax, [esp+16+8]
375
	mov	[esi+DISK.DriverFlags], eax
375
        mov     [esi+DISK.DriverFlags], eax
376
; 4. Initialize other fields of the DISK structure.
376
; 4. Initialize other fields of the DISK structure.
377
; Media is not inserted, reference counter is 1.
377
; Media is not inserted, reference counter is 1.
378
	lea	ecx, [esi+DISK.MediaLock]
378
        lea     ecx, [esi+DISK.MediaLock]
379
	call	mutex_init
379
        call    mutex_init
380
	xor	eax, eax
380
        xor     eax, eax
381
	mov	dword [esi+DISK.MediaInserted], eax
381
        mov     dword [esi+DISK.MediaInserted], eax
382
	inc	eax
382
        inc     eax
383
	mov	[esi+DISK.RefCount], eax
383
        mov     [esi+DISK.RefCount], eax
384
; The DISK structure is initialized.
384
; The DISK structure is initialized.
385
; 5. Insert the new structure to the global list.
385
; 5. Insert the new structure to the global list.
386
; 5a. Acquire the mutex.
386
; 5a. Acquire the mutex.
387
	mov	ecx, disk_list_mutex
387
        mov     ecx, disk_list_mutex
388
	call	mutex_lock
388
        call    mutex_lock
389
; 5b. Insert item to the tail of double-linked list.
389
; 5b. Insert item to the tail of double-linked list.
390
	mov	edx, disk_list
390
        mov     edx, disk_list
391
	list_add_tail esi, edx	   ;esi= new edx= list head
391
        list_add_tail esi, edx     ;esi= new edx= list head
392
; 5c. Release the mutex.
392
; 5c. Release the mutex.
393
	call	mutex_unlock
393
        call    mutex_unlock
394
; 6. Return with eax = pointer to DISK.
394
; 6. Return with eax = pointer to DISK.
395
	xchg	eax, esi
395
        xchg    eax, esi
396
	jmp	.nothing
396
        jmp     .nothing
397
.free:
397
.free:
398
; Memory allocation for DISK structure succeeded, but for disk name failed.
398
; Memory allocation for DISK structure succeeded, but for disk name failed.
399
; 7. Free the DISK structure.
399
; 7. Free the DISK structure.
400
	xchg	eax, esi
400
        xchg    eax, esi
401
	call	free
401
        call    free
402
; 8. Return with eax = 0.
402
; 8. Return with eax = 0.
403
	xor	eax, eax
403
        xor     eax, eax
404
.nothing:
404
.nothing:
405
; 9. Return.
405
; 9. Return.
406
	pop	esi ebx 	; restore used registers to be stdcall
406
        pop     esi ebx         ; restore used registers to be stdcall
407
	ret	16		; purge 4 dword arguments to be stdcall
407
        ret     16              ; purge 4 dword arguments to be stdcall
408
 
408
 
409
; This function deletes a disk device from the global filesystem.
409
; This function deletes a disk device from the global filesystem.
410
; This includes:
410
; This includes:
411
; - removing a media including all partitions;
411
; - removing a media including all partitions;
412
; - deleting this structure from the global filesystem;
412
; - deleting this structure from the global filesystem;
413
; - dereferencing the DISK structure and possibly destroying it.
413
; - dereferencing the DISK structure and possibly destroying it.
414
; Parameters:
414
; Parameters:
415
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
415
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
416
; Return value: none.
416
; Return value: none.
417
disk_del:
417
disk_del:
418
	push	esi	    ; save used registers to be stdcall
418
        push    esi         ; save used registers to be stdcall
419
; 1. Force media to be removed. If the media is already removed, the
419
; 1. Force media to be removed. If the media is already removed, the
420
; call does nothing.
420
; call does nothing.
421
	mov	esi, [esp+4+8]	; esi = handle of the disk
421
        mov     esi, [esp+4+8]  ; esi = handle of the disk
422
	stdcall disk_media_changed, esi, 0
422
        stdcall disk_media_changed, esi, 0
423
; 2. Delete the structure from the global list.
423
; 2. Delete the structure from the global list.
424
; 2a. Acquire the mutex.
424
; 2a. Acquire the mutex.
425
	mov	ecx, disk_list_mutex
425
        mov     ecx, disk_list_mutex
426
	call	mutex_lock
426
        call    mutex_lock
427
; 2b. Delete item from double-linked list.
427
; 2b. Delete item from double-linked list.
428
	mov	eax, [esi+DISK.Next]
428
        mov     eax, [esi+DISK.Next]
429
	mov	edx, [esi+DISK.Prev]
429
        mov     edx, [esi+DISK.Prev]
430
	mov	[eax+DISK.Prev], edx
430
        mov     [eax+DISK.Prev], edx
431
	mov	[edx+DISK.Next], eax
431
        mov     [edx+DISK.Next], eax
432
; 2c. Release the mutex.
432
; 2c. Release the mutex.
433
	call	mutex_unlock
433
        call    mutex_unlock
434
; 3. The structure still has one reference created in disk_add. Remove this
434
; 3. The structure still has one reference created in disk_add. Remove this
435
; reference. If there are no other references, disk_dereference will free the
435
; reference. If there are no other references, disk_dereference will free the
436
; structure.
436
; structure.
437
	call	disk_dereference
437
        call    disk_dereference
438
; 4. Return.
438
; 4. Return.
439
	pop	esi		; restore used registers to be stdcall
439
        pop     esi             ; restore used registers to be stdcall
440
	ret	4		; purge 1 dword argument to be stdcall
440
        ret     4               ; purge 1 dword argument to be stdcall
441
 
441
 
442
; This is an internal function which removes a previously obtained reference
442
; This is an internal function which removes a previously obtained reference
443
; to the disk. If this is the last reference, this function lets the driver
443
; to the disk. If this is the last reference, this function lets the driver
444
; finalize all associated data, and afterwards frees the DISK structure.
444
; finalize all associated data, and afterwards frees the DISK structure.
445
; esi = pointer to DISK structure
445
; esi = pointer to DISK structure
446
disk_dereference:
446
disk_dereference:
447
; 1. Decrement reference counter. Use atomic operation to correctly handle
447
; 1. Decrement reference counter. Use atomic operation to correctly handle
448
; possible simultaneous calls.
448
; possible simultaneous calls.
449
lock	dec	[esi+DISK.RefCount]
449
        lock dec [esi+DISK.RefCount]
450
; 2. If the result is nonzero, there are other references, so nothing to do.
450
; 2. If the result is nonzero, there are other references, so nothing to do.
451
; In this case, return (go to 4).
451
; In this case, return (go to 4).
452
	jnz	.nothing
452
        jnz     .nothing
453
; 3. If we are here, we just removed the last reference and must destroy the
453
; 3. If we are here, we just removed the last reference and must destroy the
454
; disk object.
454
; disk object.
455
; 3a. Call the driver.
455
; 3a. Call the driver.
456
	mov	al, DISKFUNC.close
456
        mov     al, DISKFUNC.close
457
	stdcall disk_call_driver
457
        stdcall disk_call_driver
458
; 3b. Free the structure.
458
; 3b. Free the structure.
459
	xchg	eax, esi
459
        xchg    eax, esi
460
	call	free
460
        call    free
461
; 4. Return.
461
; 4. Return.
462
.nothing:
462
.nothing:
463
	ret
463
        ret
464
 
464
 
465
; This is an internal function which removes a previously obtained reference
465
; This is an internal function which removes a previously obtained reference
466
; to the media. If this is the last reference, this function calls 'closemedia'
466
; to the media. If this is the last reference, this function calls 'closemedia'
467
; callback to signal the driver that the processing has finished and it is safe
467
; callback to signal the driver that the processing has finished and it is safe
468
; to inform about a new media.
468
; to inform about a new media.
469
; esi = pointer to DISK structure
469
; esi = pointer to DISK structure
470
disk_media_dereference:
470
disk_media_dereference:
471
; 1. Decrement reference counter. Use atomic operation to correctly handle
471
; 1. Decrement reference counter. Use atomic operation to correctly handle
472
; possible simultaneous calls.
472
; possible simultaneous calls.
473
lock	dec	[esi+DISK.MediaRefCount]
473
        lock dec [esi+DISK.MediaRefCount]
474
; 2. If the result is nonzero, there are other references, so nothing to do.
474
; 2. If the result is nonzero, there are other references, so nothing to do.
475
; In this case, return (go to 4).
475
; In this case, return (go to 4).
476
	jnz	.nothing
476
        jnz     .nothing
477
; 3. If we are here, we just removed the last reference and must destroy the
477
; 3. If we are here, we just removed the last reference and must destroy the
478
; media object.
478
; media object.
479
; Note that the same place inside the DISK structure is reused for all media
479
; Note that the same place inside the DISK structure is reused for all media
480
; objects, so we must guarantee that reusing does not happen while freeing.
480
; objects, so we must guarantee that reusing does not happen while freeing.
481
; Reusing is only possible when someone processes a new media. There are two
481
; Reusing is only possible when someone processes a new media. There are two
482
; mutually exclusive variants:
482
; mutually exclusive variants:
483
; * driver issues media insert notifications (DISK_NO_INSERT_NOTIFICATION bit
483
; * driver issues media insert notifications (DISK_NO_INSERT_NOTIFICATION bit
484
;   in DISK.DriverFlags is not set). In this case, we require from the driver
484
;   in DISK.DriverFlags is not set). In this case, we require from the driver
485
;   that such notification (except for the first one) can occur only after a
485
;   that such notification (except for the first one) can occur only after a
486
;   call to 'closemedia' callback.
486
;   call to 'closemedia' callback.
487
; * driver does not issue media insert notifications. In this case, the kernel
487
; * driver does not issue media insert notifications. In this case, the kernel
488
;   itself must sometimes check whether media is inserted. We have the flag
488
;   itself must sometimes check whether media is inserted. We have the flag
489
;   DISK.MediaUsed, visible to the kernel. This flag signals to the other parts
489
;   DISK.MediaUsed, visible to the kernel. This flag signals to the other parts
490
;   of kernel that the way is free.
490
;   of kernel that the way is free.
491
; In the first case other parts of the kernel do not use DISK.MediaUsed, so it
491
; In the first case other parts of the kernel do not use DISK.MediaUsed, so it
492
; does not matter when this flag is cleared. In the second case this flag must
492
; does not matter when this flag is cleared. In the second case this flag must
493
; be cleared after all other actions, including call to 'closemedia'.
493
; be cleared after all other actions, including call to 'closemedia'.
494
; 3a. Free all partitions.
494
; 3a. Free all partitions.
495
	push	esi edi
495
        push    esi edi
496
	mov	edi, [esi+DISK.NumPartitions]
496
        mov     edi, [esi+DISK.NumPartitions]
497
	mov	esi, [esi+DISK.Partitions]
497
        mov     esi, [esi+DISK.Partitions]
498
	test	edi, edi
498
        test    edi, edi
499
	jz	.nofree
499
        jz      .nofree
500
.freeloop:
500
.freeloop:
501
	lodsd
501
        lodsd
502
	call	free
502
        call    free
503
	dec	edi
503
        dec     edi
504
	jnz	.freeloop
504
        jnz     .freeloop
505
.nofree:
505
.nofree:
506
	pop	edi esi
506
        pop     edi esi
507
; 3b. Free the cache.
507
; 3b. Free the cache.
508
	call	disk_free_cache
508
        call    disk_free_cache
509
; 3c. Call the driver.
509
; 3c. Call the driver.
510
	mov	al, DISKFUNC.closemedia
510
        mov     al, DISKFUNC.closemedia
511
	stdcall disk_call_driver
511
        stdcall disk_call_driver
512
; 3d. Clear the flag.
512
; 3d. Clear the flag.
513
	mov	[esi+DISK.MediaUsed], 0
513
        mov     [esi+DISK.MediaUsed], 0
514
.nothing:
514
.nothing:
515
	ret
515
        ret
516
 
516
 
517
; This function is called by the driver and informs the kernel that the media
517
; This function is called by the driver and informs the kernel that the media
518
; has changed. If the media is non-removable, it is called exactly once
518
; has changed. If the media is non-removable, it is called exactly once
519
; immediately after 'disk_add' and once from 'disk_del'.
519
; immediately after 'disk_add' and once from 'disk_del'.
520
; Parameters:
520
; Parameters:
521
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
521
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
522
; [esp+8] = new status of the media: zero = no media, nonzero = media inserted.
522
; [esp+8] = new status of the media: zero = no media, nonzero = media inserted.
523
disk_media_changed:
523
disk_media_changed:
524
	push	ebx esi edi		; save used registers to be stdcall
524
        push    ebx esi edi             ; save used registers to be stdcall
525
; 1. Remove the existing media, if it is present.
525
; 1. Remove the existing media, if it is present.
526
	mov	esi, [esp+4+12] 	; esi = pointer to DISK
526
        mov     esi, [esp+4+12]         ; esi = pointer to DISK
527
; 1a. Check whether it is present. Since DISK.MediaInserted is changed only
527
; 1a. Check whether it is present. Since DISK.MediaInserted is changed only
528
; in this function and calls to this function are synchronized, no lock is
528
; in this function and calls to this function are synchronized, no lock is
529
; required for checking.
529
; required for checking.
530
	cmp	[esi+DISK.MediaInserted], 0
530
        cmp     [esi+DISK.MediaInserted], 0
531
	jz	.noremove
531
        jz      .noremove
532
; We really need to remove the media.
532
; We really need to remove the media.
533
; 1b. Acquire mutex.
533
; 1b. Acquire mutex.
534
	lea	ecx, [esi+DISK.MediaLock]
534
        lea     ecx, [esi+DISK.MediaLock]
535
	call	mutex_lock
535
        call    mutex_lock
536
; 1c. Clear the flag.
536
; 1c. Clear the flag.
537
	mov	[esi+DISK.MediaInserted], 0
537
        mov     [esi+DISK.MediaInserted], 0
538
; 1d. Release mutex.
538
; 1d. Release mutex.
539
	call	mutex_unlock
539
        call    mutex_unlock
540
; 1e. Remove the "lifetime" reference and possibly destroy the structure.
540
; 1e. Remove the "lifetime" reference and possibly destroy the structure.
541
	call	disk_media_dereference
541
        call    disk_media_dereference
542
.noremove:
542
.noremove:
543
; 2. Test whether there is new media.
543
; 2. Test whether there is new media.
544
	cmp	dword [esp+8+12], 0
544
        cmp     dword [esp+8+12], 0
545
	jz	.noinsert
545
        jz      .noinsert
546
; Yep, there is.
546
; Yep, there is.
547
; 3. Process the new media. We assume that all media fields are available to
547
; 3. Process the new media. We assume that all media fields are available to
548
; use, see comments in 'disk_media_dereference' (this covers using by previous
548
; use, see comments in 'disk_media_dereference' (this covers using by previous
549
; media referencers) and note that calls to this function are synchronized
549
; media referencers) and note that calls to this function are synchronized
550
; (this covers using by new media referencers).
550
; (this covers using by new media referencers).
551
; 3a. Call the 'querymedia' callback.
551
; 3a. Call the 'querymedia' callback.
552
; .Flags are set to zero for possible future extensions.
552
; .Flags are set to zero for possible future extensions.
553
	lea	edx, [esi+DISK.MediaInfo]
553
        lea     edx, [esi+DISK.MediaInfo]
554
	and	[edx+DISKMEDIAINFO.Flags], 0
554
        and     [edx+DISKMEDIAINFO.Flags], 0
555
	mov	al, DISKFUNC.querymedia
555
        mov     al, DISKFUNC.querymedia
556
	stdcall disk_call_driver, edx
556
        stdcall disk_call_driver, edx
557
; 3b. Check the result of the callback. Abort if it failed.
557
; 3b. Check the result of the callback. Abort if it failed.
558
	test	eax, eax
558
        test    eax, eax
559
	jnz	.noinsert
559
        jnz     .noinsert
560
; 3c. Allocate the cache unless disabled by the driver. Abort if failed.
560
; 3c. Allocate the cache unless disabled by the driver. Abort if failed.
561
	call	disk_init_cache
561
        call    disk_init_cache
562
	test	al, al
562
        test    al, al
563
	jz	.noinsert
563
        jz      .noinsert
564
; 3d. Acquire the lifetime reference for the media object.
564
; 3d. Acquire the lifetime reference for the media object.
565
	inc	[esi+DISK.MediaRefCount]
565
        inc     [esi+DISK.MediaRefCount]
566
; 3e. Scan for partitions. Ignore result; the list of partitions is valid even
566
; 3e. Scan for partitions. Ignore result; the list of partitions is valid even
567
; on errors.
567
; on errors.
568
	call	disk_scan_partitions
568
        call    disk_scan_partitions
569
; 3f. Media is inserted and available for use.
569
; 3f. Media is inserted and available for use.
570
	inc	[esi+DISK.MediaInserted]
570
        inc     [esi+DISK.MediaInserted]
571
.noinsert:
571
.noinsert:
572
; 4. Return.
572
; 4. Return.
573
	pop	edi esi ebx		; restore used registers to be stdcall
573
        pop     edi esi ebx             ; restore used registers to be stdcall
574
	ret	8			; purge 2 dword arguments to be stdcall
574
        ret     8                       ; purge 2 dword arguments to be stdcall
575
 
575
 
576
; This function is a thunk for all functions of a disk driver.
576
; This function is a thunk for all functions of a disk driver.
577
; It checks whether the referenced function is implemented in the driver.
577
; It checks whether the referenced function is implemented in the driver.
578
; If so, this function jumps to the function in the driver.
578
; If so, this function jumps to the function in the driver.
579
; Otherwise, it jumps to the default implementation.
579
; Otherwise, it jumps to the default implementation.
580
; al = offset of function in the DISKFUNC structure;
580
; al = offset of function in the DISKFUNC structure;
581
; esi = pointer to the DISK structure;
581
; esi = pointer to the DISK structure;
582
; stack is the same as for the corresponding function except that the
582
; stack is the same as for the corresponding function except that the
583
; first parameter (void* userdata) is prepended automatically.
583
; first parameter (void* userdata) is prepended automatically.
584
disk_call_driver:
584
disk_call_driver:
585
	movzx	eax, al ; eax = offset of function in the DISKFUNC structure
585
        movzx   eax, al ; eax = offset of function in the DISKFUNC structure
586
; 1. Prepend the first argument to the stack.
586
; 1. Prepend the first argument to the stack.
587
	pop	ecx	; ecx = return address
587
        pop     ecx     ; ecx = return address
588
	push	[esi+DISK.UserData]	; add argument
588
        push    [esi+DISK.UserData]     ; add argument
589
	push	ecx	; save return address
589
        push    ecx     ; save return address
590
; 2. Check that the required function is inside the table. If not, go to 5.
590
; 2. Check that the required function is inside the table. If not, go to 5.
591
	mov	ecx, [esi+DISK.Functions]
591
        mov     ecx, [esi+DISK.Functions]
592
	cmp	eax, [ecx+DISKFUNC.strucsize]
592
        cmp     eax, [ecx+DISKFUNC.strucsize]
593
	jae	.default
593
        jae     .default
594
; 3. Check that the required function is implemented. If not, go to 5.
594
; 3. Check that the required function is implemented. If not, go to 5.
595
	mov	ecx, [ecx+eax]
595
        mov     ecx, [ecx+eax]
596
	test	ecx, ecx
596
        test    ecx, ecx
597
	jz	.default
597
        jz      .default
598
; 4. Jump to the required function.
598
; 4. Jump to the required function.
599
	jmp	ecx
599
        jmp     ecx
600
.default:
600
.default:
601
; 5. Driver does not implement the required function; use default implementation.
601
; 5. Driver does not implement the required function; use default implementation.
602
	jmp	dword [disk_default_callbacks+eax-4]
602
        jmp     dword [disk_default_callbacks+eax-4]
603
 
603
 
604
; The default implementation of DISKFUNC.querymedia.
604
; The default implementation of DISKFUNC.querymedia.
605
disk_default_querymedia:
605
disk_default_querymedia:
606
	push	DISK_STATUS_INVALID_CALL
606
        push    DISK_STATUS_INVALID_CALL
607
	pop	eax
607
        pop     eax
608
	ret	8
608
        ret     8
609
 
609
 
610
; The default implementation of DISKFUNC.read and DISKFUNC.write.
610
; The default implementation of DISKFUNC.read and DISKFUNC.write.
611
disk_default_read:
611
disk_default_read:
612
disk_default_write:
612
disk_default_write:
613
	push	DISK_STATUS_INVALID_CALL
613
        push    DISK_STATUS_INVALID_CALL
614
	pop	eax
614
        pop     eax
615
	ret	20
615
        ret     20
616
 
616
 
617
; The default implementation of DISKFUNC.close, DISKFUNC.closemedia and
617
; The default implementation of DISKFUNC.close, DISKFUNC.closemedia and
618
; DISKFUNC.flush.
618
; DISKFUNC.flush.
619
disk_default_close:
619
disk_default_close:
620
disk_default_closemedia:
620
disk_default_closemedia:
621
disk_default_flush:
621
disk_default_flush:
622
	xor	eax, eax
622
        xor     eax, eax
623
	ret	4
623
        ret     4
624
 
624
 
625
; The default implementation of DISKFUNC.adjust_cache_size.
625
; The default implementation of DISKFUNC.adjust_cache_size.
626
disk_default_adjust_cache_size:
626
disk_default_adjust_cache_size:
627
	mov	eax, [esp+4]
627
        mov     eax, [esp+4]
628
	ret	4
628
        ret     4
629
 
629
 
630
; This is an internal function called from 'disk_media_changed' when a new media
630
; This is an internal function called from 'disk_media_changed' when a new media
631
; is detected. It creates the list of partitions for the media.
631
; is detected. It creates the list of partitions for the media.
632
; If media is not partitioned, then the list consists of one partition which
632
; If media is not partitioned, then the list consists of one partition which
633
; covers all the media.
633
; covers all the media.
634
; esi = pointer to the DISK structure.
634
; esi = pointer to the DISK structure.
635
disk_scan_partitions:
635
disk_scan_partitions:
636
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list.
636
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list.
637
	and	[esi+DISK.NumPartitions], 0
637
        and     [esi+DISK.NumPartitions], 0
638
	and	[esi+DISK.Partitions], 0
638
        and     [esi+DISK.Partitions], 0
639
; 2. Currently we can work only with 512-bytes sectors. Check this restriction.
639
; 2. Currently we can work only with 512-bytes sectors. Check this restriction.
640
; The only exception is 2048-bytes CD/DVD, but they are not supported yet by
640
; The only exception is 2048-bytes CD/DVD, but they are not supported yet by
641
; this code.
641
; this code.
642
	cmp	[esi+DISK.MediaInfo.SectorSize], 512
642
        cmp     [esi+DISK.MediaInfo.SectorSize], 512
643
	jz	.doscan
643
        jz      .doscan
644
	DEBUGF 1,'K : sector size is %d, only 512 is supported\n',[esi+DISK.MediaInfo.SectorSize]
644
        DEBUGF 1,'K : sector size is %d, only 512 is supported\n',[esi+DISK.MediaInfo.SectorSize]
645
	ret
645
        ret
646
.doscan:
646
.doscan:
647
; 3. Acquire the buffer for MBR and bootsector tests. See the comment before
647
; 3. Acquire the buffer for MBR and bootsector tests. See the comment before
648
; the 'partition_buffer_users' variable.
648
; the 'partition_buffer_users' variable.
649
	mov	ebx, mbr_buffer 	; assume the global buffer is free
649
        mov     ebx, mbr_buffer         ; assume the global buffer is free
650
lock	inc	[partition_buffer_users]
650
        lock inc [partition_buffer_users]
651
	jz	.buffer_acquired	; yes, it is free
651
        jz      .buffer_acquired        ; yes, it is free
652
lock	dec	[partition_buffer_users]	; no, we must allocate
652
        lock dec [partition_buffer_users]       ; no, we must allocate
653
	stdcall kernel_alloc, 512*3
653
        stdcall kernel_alloc, 512*3
654
	test	eax, eax
654
        test    eax, eax
655
	jz	.nothing
655
        jz      .nothing
656
	xchg	eax, ebx
656
        xchg    eax, ebx
657
.buffer_acquired:
657
.buffer_acquired:
658
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no
658
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no
659
; more than MAX_NUM_PARTITION times.
659
; more than MAX_NUM_PARTITION times.
660
; 4. Prepare things for the loop.
660
; 4. Prepare things for the loop.
661
; ebp will hold the sector number for current MBR/EBR.
661
; ebp will hold the sector number for current MBR/EBR.
662
; [esp] will hold the sector number for current extended partition, if there
662
; [esp] will hold the sector number for current extended partition, if there
663
; is one.
663
; is one.
664
; [esp+4] will hold the counter that prevents long loops.
664
; [esp+4] will hold the counter that prevents long loops.
665
	push	ebp		; save ebp
665
        push    ebp             ; save ebp
666
	push	MAX_NUM_PARTITIONS	; the counter of max MBRs to process
666
        push    MAX_NUM_PARTITIONS      ; the counter of max MBRs to process
667
	xor	ebp, ebp	; start from sector zero
667
        xor     ebp, ebp        ; start from sector zero
668
	push	ebp		; no extended partition yet
668
        push    ebp             ; no extended partition yet
669
.new_mbr:
669
.new_mbr:
670
; 5. Read the current sector.
670
; 5. Read the current sector.
671
; Note that 'read' callback operates with 64-bit sector numbers, so we must
671
; Note that 'read' callback operates with 64-bit sector numbers, so we must
672
; push additional zero as a high dword of sector number.
672
; push additional zero as a high dword of sector number.
673
	mov	al, DISKFUNC.read
673
        mov     al, DISKFUNC.read
674
	push	1
674
        push    1
675
	stdcall disk_call_driver, ebx, ebp, 0, esp
675
        stdcall disk_call_driver, ebx, ebp, 0, esp
676
	pop	ecx
676
        pop     ecx
677
; 6. If the read has failed, abort the loop.
677
; 6. If the read has failed, abort the loop.
678
	dec	ecx
678
        dec     ecx
679
	jnz	.mbr_failed
679
        jnz     .mbr_failed
680
; 7. Check the MBR/EBR signature. If it is wrong, abort the loop.
680
; 7. Check the MBR/EBR signature. If it is wrong, abort the loop.
681
; Soon we will access the partition table which starts at ebx+0x1BE,
681
; Soon we will access the partition table which starts at ebx+0x1BE,
682
; so we can fill its address right now. If we do it now, then the addressing
682
; so we can fill its address right now. If we do it now, then the addressing
683
; [ecx+0x40] is shorter than [ebx+0x1fe]: one-byte offset vs 4-bytes offset.
683
; [ecx+0x40] is shorter than [ebx+0x1fe]: one-byte offset vs 4-bytes offset.
684
	lea	ecx, [ebx+0x1be]	; ecx -> partition table
684
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
685
	cmp	word [ecx+0x40], 0xaa55
685
        cmp     word [ecx+0x40], 0xaa55
686
	jnz	.mbr_failed
686
        jnz     .mbr_failed
687
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
687
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
688
; execute step 9 and possibly step 10.
688
; execute step 9 and possibly step 10.
689
	test	ebp, ebp
689
        test    ebp, ebp
690
	jnz	.mbr
690
        jnz     .mbr
691
; The partition table can be present or not present. In the first case, we just
691
; The partition table can be present or not present. In the first case, we just
692
; read the MBR. In the second case, we just read the bootsector for a
692
; read the MBR. In the second case, we just read the bootsector for a
693
; filesystem.
693
; filesystem.
694
; The following algorithm is used to distinguish between these cases.
694
; The following algorithm is used to distinguish between these cases.
695
; A. If at least one entry of the partition table is invalid, this is
695
; A. If at least one entry of the partition table is invalid, this is
696
;    a bootsector. See the description of 'is_partition_table_entry' for
696
;    a bootsector. See the description of 'is_partition_table_entry' for
697
;    definition of validity.
697
;    definition of validity.
698
; B. If all entries are empty (filesystem type field is zero) and the first
698
; B. If all entries are empty (filesystem type field is zero) and the first
699
;    byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
699
;    byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
700
;    have zeros in the place of partition table.
700
;    have zeros in the place of partition table.
701
; C. Otherwise, this is an MBR.
701
; C. Otherwise, this is an MBR.
702
; 9. Test for MBR vs bootsector.
702
; 9. Test for MBR vs bootsector.
703
; 9a. Check entries. If any is invalid, go to 10 (rule A).
703
; 9a. Check entries. If any is invalid, go to 10 (rule A).
704
	call	is_partition_table_entry
704
        call    is_partition_table_entry
705
	jc	.notmbr
705
        jc      .notmbr
706
	add	ecx, 10h
706
        add     ecx, 10h
707
	call	is_partition_table_entry
707
        call    is_partition_table_entry
708
	jc	.notmbr
708
        jc      .notmbr
709
	add	ecx, 10h
709
        add     ecx, 10h
710
	call	is_partition_table_entry
710
        call    is_partition_table_entry
711
	jc	.notmbr
711
        jc      .notmbr
712
	add	ecx, 10h
712
        add     ecx, 10h
713
	call	is_partition_table_entry
713
        call    is_partition_table_entry
714
	jc	.notmbr
714
        jc      .notmbr
715
; 9b. Check types of the entries. If at least one is nonzero, go to 11 (rule C).
715
; 9b. Check types of the entries. If at least one is nonzero, go to 11 (rule C).
716
	mov	al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
716
        mov     al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
717
	or	al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
717
        or      al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
718
	or	al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
718
        or      al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
719
	or	al, [ecx+PARTITION_TABLE_ENTRY.Type]
719
        or      al, [ecx+PARTITION_TABLE_ENTRY.Type]
720
	jnz	.mbr
720
        jnz     .mbr
721
; 9c. Empty partition table or bootsector with many zeroes? (rule B)
721
; 9c. Empty partition table or bootsector with many zeroes? (rule B)
722
	cmp	byte [ebx], 0EBh
722
        cmp     byte [ebx], 0EBh
723
	jz	.notmbr
723
        jz      .notmbr
724
	cmp	byte [ebx], 0E9h
724
        cmp     byte [ebx], 0E9h
725
	jnz	.mbr
725
        jnz     .mbr
726
.notmbr:
726
.notmbr:
727
; 10. This is not an  MBR. The media is not partitioned. Create one partition
727
; 10. This is not an  MBR. The media is not partitioned. Create one partition
728
; which covers all the media and abort the loop.
728
; which covers all the media and abort the loop.
729
	stdcall disk_add_partition, 0, 0, \
729
        stdcall disk_add_partition, 0, 0, \
730
		dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4]
730
                dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4]
731
	jmp	.done
731
        jmp     .done
732
.mbr:
732
.mbr:
733
; 11. Process all entries of the new MBR/EBR
733
; 11. Process all entries of the new MBR/EBR
734
	lea	ecx, [ebx+0x1be]	; ecx -> partition table
734
        lea     ecx, [ebx+0x1be]        ; ecx -> partition table
735
	push	0	; assume no extended partition
735
        push    0       ; assume no extended partition
736
	call	process_partition_table_entry
736
        call    process_partition_table_entry
737
	add	ecx, 10h
737
        add     ecx, 10h
738
	call	process_partition_table_entry
738
        call    process_partition_table_entry
739
	add	ecx, 10h
739
        add     ecx, 10h
740
	call	process_partition_table_entry
740
        call    process_partition_table_entry
741
	add	ecx, 10h
741
        add     ecx, 10h
742
	call	process_partition_table_entry
742
        call    process_partition_table_entry
743
	pop	ebp
743
        pop     ebp
744
; 12. Test whether we found a new EBR and should continue the loop.
744
; 12. Test whether we found a new EBR and should continue the loop.
745
; 12a. If there was no next EBR, return.
745
; 12a. If there was no next EBR, return.
746
	test	ebp, ebp
746
        test    ebp, ebp
747
	jz	.done
747
        jz      .done
748
; Ok, we have EBR.
748
; Ok, we have EBR.
749
; 12b. EBRs addresses are relative to the start of extended partition.
749
; 12b. EBRs addresses are relative to the start of extended partition.
750
; For simplicity, just abort if an 32-bit overflow occurs; large disks
750
; For simplicity, just abort if an 32-bit overflow occurs; large disks
751
; are most likely partitioned with GPT, not MBR scheme, since the precise
751
; are most likely partitioned with GPT, not MBR scheme, since the precise
752
; calculation here would increase limit just twice at the price of big
752
; calculation here would increase limit just twice at the price of big
753
; compatibility problems.
753
; compatibility problems.
754
	pop	eax	; load extended partition
754
        pop     eax     ; load extended partition
755
	add	ebp, eax
755
        add     ebp, eax
756
	jc	.mbr_failed
756
        jc      .mbr_failed
757
; 12c. If extended partition has not yet started, start it.
757
; 12c. If extended partition has not yet started, start it.
758
	test	eax, eax
758
        test    eax, eax
759
	jnz	@f
759
        jnz     @f
760
	mov	eax, ebp
760
        mov     eax, ebp
761
@@:
761
@@:
762
; 12c. If the limit is not exceeded, continue the loop.
762
; 12c. If the limit is not exceeded, continue the loop.
763
	dec	dword [esp]
763
        dec     dword [esp]
764
	push	eax	; store extended partition
764
        push    eax     ; store extended partition
765
	jnz	.new_mbr
765
        jnz     .new_mbr
766
.mbr_failed:
766
.mbr_failed:
767
.done:
767
.done:
768
; 13. Cleanup after the loop.
768
; 13. Cleanup after the loop.
769
	pop	eax	; not important anymore
769
        pop     eax     ; not important anymore
770
	pop	eax	; not important anymore
770
        pop     eax     ; not important anymore
771
	pop	ebp	; restore ebp
771
        pop     ebp     ; restore ebp
772
; 14. Release the buffer.
772
; 14. Release the buffer.
773
; 14a. Test whether it is the global buffer or we have allocated it.
773
; 14a. Test whether it is the global buffer or we have allocated it.
774
	cmp	ebx, mbr_buffer
774
        cmp     ebx, mbr_buffer
775
	jz	.release_partition_buffer
775
        jz      .release_partition_buffer
776
; 14b. If we have allocated it, free it.
776
; 14b. If we have allocated it, free it.
777
	xchg	eax, ebx
777
        xchg    eax, ebx
778
	call	free
778
        call    free
779
	jmp	.nothing
779
        jmp     .nothing
780
; 14c. Otherwise, release reference.
780
; 14c. Otherwise, release reference.
781
.release_partition_buffer:
781
.release_partition_buffer:
782
lock	dec	[partition_buffer_users]
782
        lock dec [partition_buffer_users]
783
.nothing:
783
.nothing:
784
; 15. Return.
784
; 15. Return.
785
	ret
785
        ret
786
 
786
 
787
; This is an internal function called from disk_scan_partitions. It checks
787
; This is an internal function called from disk_scan_partitions. It checks
788
; whether the entry pointed to by ecx is a valid entry of partition table.
788
; whether the entry pointed to by ecx is a valid entry of partition table.
789
; The entry is valid if the first byte is 0 or 80h, the first sector plus the
789
; The entry is valid if the first byte is 0 or 80h, the first sector plus the
790
; length is less than twice the size of media. Multiplication by two is
790
; length is less than twice the size of media. Multiplication by two is
791
; required since the size mentioned in the partition table can be slightly
791
; required since the size mentioned in the partition table can be slightly
792
; greater than the real size.
792
; greater than the real size.
793
is_partition_table_entry:
793
is_partition_table_entry:
794
; 1. Check .Bootable field.
794
; 1. Check .Bootable field.
795
	mov	al, [ecx+PARTITION_TABLE_ENTRY.Bootable]
795
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Bootable]
796
	and	al, 7Fh
796
        and     al, 7Fh
797
	jnz	.invalid
797
        jnz     .invalid
798
; 3. Calculate first sector + length. Note that .FirstAbsSector is relative
798
; 3. Calculate first sector + length. Note that .FirstAbsSector is relative
799
; to the MBR/EBR, so the real sum is ebp + .FirstAbsSector + .Length.
799
; to the MBR/EBR, so the real sum is ebp + .FirstAbsSector + .Length.
800
	mov	eax, ebp
800
        mov     eax, ebp
801
	xor	edx, edx
801
        xor     edx, edx
802
	add	eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
802
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
803
	adc	edx, 0
803
        adc     edx, 0
804
	add	eax, [ecx+PARTITION_TABLE_ENTRY.Length]
804
        add     eax, [ecx+PARTITION_TABLE_ENTRY.Length]
805
	adc	edx, 0
805
        adc     edx, 0
806
; 4. Divide by two.
806
; 4. Divide by two.
807
	shr	edx, 1
807
        shr     edx, 1
808
	rcr	eax, 1
808
        rcr     eax, 1
809
; 5. Compare with capacity. If the subtraction (edx:eax) - .Capacity does not
809
; 5. Compare with capacity. If the subtraction (edx:eax) - .Capacity does not
810
; overflow, this is bad.
810
; overflow, this is bad.
811
	sub	eax, dword [esi+DISK.MediaInfo.Capacity]
811
        sub     eax, dword [esi+DISK.MediaInfo.Capacity]
812
	sbb	edx, dword [esi+DISK.MediaInfo.Capacity+4]
812
        sbb     edx, dword [esi+DISK.MediaInfo.Capacity+4]
813
	jnc	.invalid
813
        jnc     .invalid
814
.valid:
814
.valid:
815
; 5. Return success: CF is cleared.
815
; 5. Return success: CF is cleared.
816
	clc
816
        clc
817
	ret
817
        ret
818
.invalid:
818
.invalid:
819
; 6. Return fail: CF is set.
819
; 6. Return fail: CF is set.
820
	stc
820
        stc
821
	ret
821
        ret
822
 
822
 
823
; This is an internal function called from disk_scan_partitions. It processes
823
; This is an internal function called from disk_scan_partitions. It processes
824
; the entry pointed to by ecx.
824
; the entry pointed to by ecx.
825
; * If the entry is invalid, just ignore this entry.
825
; * If the entry is invalid, just ignore this entry.
826
; * If the type is zero, just ignore this entry.
826
; * If the type is zero, just ignore this entry.
827
; * If the type is one of types for extended partition, store the address
827
; * If the type is one of types for extended partition, store the address
828
;   of this partition as the new MBR in [esp+4].
828
;   of this partition as the new MBR in [esp+4].
829
; * Otherwise, add the partition to the list of partitions for this disk.
829
; * Otherwise, add the partition to the list of partitions for this disk.
830
;   We don't use the type from the entry to identify the file system;
830
;   We don't use the type from the entry to identify the file system;
831
;   fs-specific checks do this more reliably.
831
;   fs-specific checks do this more reliably.
832
process_partition_table_entry:
832
process_partition_table_entry:
833
; 1. Check for valid entry. If invalid, return (go to 5).
833
; 1. Check for valid entry. If invalid, return (go to 5).
834
	call	is_partition_table_entry
834
        call    is_partition_table_entry
835
	jc	.nothing
835
        jc      .nothing
836
; 2. Check for empty entry. If invalid, return (go to 5).
836
; 2. Check for empty entry. If invalid, return (go to 5).
837
	mov	al, [ecx+PARTITION_TABLE_ENTRY.Type]
837
        mov     al, [ecx+PARTITION_TABLE_ENTRY.Type]
838
	test	al, al
838
        test    al, al
839
	jz	.nothing
839
        jz      .nothing
840
; 3. Check for extended partition. If extended, go to 6.
840
; 3. Check for extended partition. If extended, go to 6.
841
irp type,\
841
irp type,\
842
    0x05,\		   ; DOS: extended partition
842
    0x05,\                 ; DOS: extended partition
843
    0x0f,\		   ; WIN95: extended partition, LBA-mapped
843
    0x0f,\                 ; WIN95: extended partition, LBA-mapped
844
    0xc5,\		   ; DRDOS/secured: extended partition
844
    0xc5,\                 ; DRDOS/secured: extended partition
845
    0xd5		   ; Old Multiuser DOS secured: extended partition
845
    0xd5                   ; Old Multiuser DOS secured: extended partition
846
{
846
{
847
	cmp	al, type
847
        cmp     al, type
848
	jz	.extended
848
        jz      .extended
849
}
849
}
850
; 4. If we are here, that is a normal partition. Add it to the list.
850
; 4. If we are here, that is a normal partition. Add it to the list.
851
; Note that the first sector is relative to MBR/EBR.
851
; Note that the first sector is relative to MBR/EBR.
852
	mov	eax, ebp
852
        mov     eax, ebp
853
	xor	edx, edx
853
        xor     edx, edx
854
	add	eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
854
        add     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
855
	adc	edx, 0
855
        adc     edx, 0
856
	push	ecx
856
        push    ecx
857
	stdcall disk_add_partition, eax, edx, \
857
        stdcall disk_add_partition, eax, edx, \
858
		[ecx+PARTITION_TABLE_ENTRY.Length], 0
858
                [ecx+PARTITION_TABLE_ENTRY.Length], 0
859
	pop	ecx
859
        pop     ecx
860
.nothing:
860
.nothing:
861
; 5. Return.
861
; 5. Return.
862
	ret
862
        ret
863
.extended:
863
.extended:
864
; 6. If we are here, that is an extended partition. Store the address.
864
; 6. If we are here, that is an extended partition. Store the address.
865
	mov	eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
865
        mov     eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
866
	mov	[esp+4], eax
866
        mov     [esp+4], eax
867
	ret
867
        ret
868
 
868
 
869
; This is an internal function called from disk_scan_partitions and
869
; This is an internal function called from disk_scan_partitions and
870
; process_partition_table_entry. It adds one partition to the list of
870
; process_partition_table_entry. It adds one partition to the list of
871
; partitions for the media.
871
; partitions for the media.
872
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword
872
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword
873
; 1. Check that this partition will not exceed the limit on total number.
873
; 1. Check that this partition will not exceed the limit on total number.
874
	cmp	[esi+DISK.NumPartitions], MAX_NUM_PARTITIONS
874
        cmp     [esi+DISK.NumPartitions], MAX_NUM_PARTITIONS
875
	jae	.nothing
875
        jae     .nothing
876
; 2. Check that this partition does not overlap with any already registered
876
; 2. Check that this partition does not overlap with any already registered
877
; partition. Since any file system assumes that the disk data will not change
877
; partition. Since any file system assumes that the disk data will not change
878
; outside of its control, such overlap could be destructive.
878
; outside of its control, such overlap could be destructive.
879
; Since the number of partitions is usually very small and is guaranteed not
879
; Since the number of partitions is usually very small and is guaranteed not
880
; to be large, the simple linear search is sufficient.
880
; to be large, the simple linear search is sufficient.
881
; 2a. Prepare the loop: edi will point to the current item of .Partitions
881
; 2a. Prepare the loop: edi will point to the current item of .Partitions
882
; array, ecx will be the current item, ebx will hold number of items left.
882
; array, ecx will be the current item, ebx will hold number of items left.
883
	mov	edi, [esi+DISK.Partitions]
883
        mov     edi, [esi+DISK.Partitions]
884
	mov	ebx, [esi+DISK.NumPartitions]
884
        mov     ebx, [esi+DISK.NumPartitions]
885
	test	ebx, ebx
885
        test    ebx, ebx
886
	jz	.partitionok
886
        jz      .partitionok
887
.scan_existing:
887
.scan_existing:
888
; 2b. Get the next partition.
888
; 2b. Get the next partition.
889
	mov	ecx, [edi]
889
        mov     ecx, [edi]
890
	add	edi, 4
890
        add     edi, 4
891
; The range [.FirstSector, .FirstSector+.Length) must be either entirely to
891
; The range [.FirstSector, .FirstSector+.Length) must be either entirely to
892
; the left of [start, start+length) or entirely to the right.
892
; the left of [start, start+length) or entirely to the right.
893
; 2c. Subtract .FirstSector - start. The possible overflow distinguish between
893
; 2c. Subtract .FirstSector - start. The possible overflow distinguish between
894
; cases "to the left" (2e) and "to the right" (2d).
894
; cases "to the left" (2e) and "to the right" (2d).
895
	mov	eax, dword [ecx+PARTITION.FirstSector]
895
        mov     eax, dword [ecx+PARTITION.FirstSector]
896
	mov	edx, dword [ecx+PARTITION.FirstSector+4]
896
        mov     edx, dword [ecx+PARTITION.FirstSector+4]
897
	sub	eax, dword [start]
897
        sub     eax, dword [start]
898
	sbb	edx, dword [start+4]
898
        sbb     edx, dword [start+4]
899
	jb	.less
899
        jb      .less
900
; 2d. .FirstSector is greater than or equal to start. Check that .FirstSector
900
; 2d. .FirstSector is greater than or equal to start. Check that .FirstSector
901
; is greater than or equal to start+length; the subtraction
901
; is greater than or equal to start+length; the subtraction
902
; (.FirstSector-start) - length must not cause overflow. Go to 2g if life is
902
; (.FirstSector-start) - length must not cause overflow. Go to 2g if life is
903
; good or to 2f in the other case.
903
; good or to 2f in the other case.
904
	sub	eax, dword [length]
904
        sub     eax, dword [length]
905
	sbb	edx, dword [length+4]
905
        sbb     edx, dword [length+4]
906
	jb	.overlap
906
        jb      .overlap
907
	jmp	.next_existing
907
        jmp     .next_existing
908
.less:
908
.less:
909
; 2e. .FirstSector is less than start. Check that .FirstSector+.Length is less
909
; 2e. .FirstSector is less than start. Check that .FirstSector+.Length is less
910
; than or equal to start. If the addition (.FirstSector-start) + .Length does
910
; than or equal to start. If the addition (.FirstSector-start) + .Length does
911
; not cause overflow, then .FirstSector + .Length is strictly less than start;
911
; not cause overflow, then .FirstSector + .Length is strictly less than start;
912
; since the equality is also valid, use decrement preliminarily. Go to 2g or
912
; since the equality is also valid, use decrement preliminarily. Go to 2g or
913
; 2f depending on the overflow.
913
; 2f depending on the overflow.
914
	sub	eax, 1
914
        sub     eax, 1
915
	sbb	edx, 0
915
        sbb     edx, 0
916
	add	eax, dword [ecx+PARTITION.Length]
916
        add     eax, dword [ecx+PARTITION.Length]
917
	adc	edx, dword [ecx+PARTITION.Length+4]
917
        adc     edx, dword [ecx+PARTITION.Length+4]
918
	jnc	.next_existing
918
        jnc     .next_existing
919
.overlap:
919
.overlap:
920
; 2f. The partition overlaps with previously registered partition. Say warning
920
; 2f. The partition overlaps with previously registered partition. Say warning
921
; and return with nothing done.
921
; and return with nothing done.
922
	dbgstr 'two partitions overlap, ignoring the last one'
922
        dbgstr 'two partitions overlap, ignoring the last one'
923
	jmp	.nothing
923
        jmp     .nothing
924
.next_existing:
924
.next_existing:
925
; 2g. The partition does not overlap with the current partition. Continue the
925
; 2g. The partition does not overlap with the current partition. Continue the
926
; loop.
926
; loop.
927
	dec	ebx
927
        dec     ebx
928
	jnz	.scan_existing
928
        jnz     .scan_existing
929
.partitionok:
929
.partitionok:
930
; 3. The partition has passed tests. Reallocate the partitions array for a new
930
; 3. The partition has passed tests. Reallocate the partitions array for a new
931
; entry.
931
; entry.
932
; 3a. Call the allocator.
932
; 3a. Call the allocator.
933
	mov	eax, [esi+DISK.NumPartitions]
933
        mov     eax, [esi+DISK.NumPartitions]
934
	inc	eax	; one more entry
934
        inc     eax     ; one more entry
935
	shl	eax, 2	; each entry is dword
935
        shl     eax, 2  ; each entry is dword
936
	call	malloc
936
        call    malloc
937
; 3b. Test the result. If failed, return with nothing done.
937
; 3b. Test the result. If failed, return with nothing done.
938
	test	eax, eax
938
        test    eax, eax
939
	jz	.nothing
939
        jz      .nothing
940
; 3c. Copy the old array to the new array.
940
; 3c. Copy the old array to the new array.
941
	mov	edi, eax
941
        mov     edi, eax
942
	push	esi
942
        push    esi
943
	mov	ecx, [esi+DISK.NumPartitions]
943
        mov     ecx, [esi+DISK.NumPartitions]
944
	mov	esi, [esi+DISK.Partitions]
944
        mov     esi, [esi+DISK.Partitions]
945
	rep	movsd
945
        rep movsd
946
	pop	esi
946
        pop     esi
947
; 3d. Set the field in the DISK structure to the new array.
947
; 3d. Set the field in the DISK structure to the new array.
948
	xchg	[esi+DISK.Partitions], eax
948
        xchg    [esi+DISK.Partitions], eax
949
; 3e. Free the old array.
949
; 3e. Free the old array.
950
	call	free
950
        call    free
951
; 4. Recognize the file system.
951
; 4. Recognize the file system.
952
; 4a. Call the filesystem recognizer. It will allocate the PARTITION structure
952
; 4a. Call the filesystem recognizer. It will allocate the PARTITION structure
953
; with possible filesystem-specific fields.
953
; with possible filesystem-specific fields.
954
	call	disk_detect_partition
954
        call    disk_detect_partition
955
; 4b. Check return value. If zero, return with list not changed; so far only
955
; 4b. Check return value. If zero, return with list not changed; so far only
956
; the array was reallocated, this is ok for other code.
956
; the array was reallocated, this is ok for other code.
957
	test	eax, eax
957
        test    eax, eax
958
	jz	.nothing
958
        jz      .nothing
959
; 5. Insert the new partition to the list.
959
; 5. Insert the new partition to the list.
960
	stosd
960
        stosd
961
	inc	[esi+DISK.NumPartitions]
961
        inc     [esi+DISK.NumPartitions]
962
; 6. Return.
962
; 6. Return.
963
.nothing:
963
.nothing:
964
	ret
964
        ret
965
endp
965
endp
966
 
966
 
967
; This is an internal function called from disk_add_partition.
967
; This is an internal function called from disk_add_partition.
968
; It tries to recognize the file system on the partition and allocates the
968
; It tries to recognize the file system on the partition and allocates the
969
; corresponding PARTITION structure with filesystem-specific fields.
969
; corresponding PARTITION structure with filesystem-specific fields.
970
disk_detect_partition:
970
disk_detect_partition:
971
; This function inherits the stack frame from disk_add_partition. In stdcall
971
; This function inherits the stack frame from disk_add_partition. In stdcall
972
; with ebp-based frame arguments start from ebp+8, since [ebp]=saved ebp
972
; with ebp-based frame arguments start from ebp+8, since [ebp]=saved ebp
973
; and [ebp+4]=return address.
973
; and [ebp+4]=return address.
974
virtual at ebp+8
974
virtual at ebp+8
975
.start	dq	?
975
.start  dq      ?
976
.length dq	?
976
.length dq      ?
977
end virtual
977
end virtual
978
; Currently no file systems are supported, so just allocate the PARTITION
978
; Currently no file systems are supported, so just allocate the PARTITION
979
; structure without extra fields.
979
; structure without extra fields.
980
; 1. Allocate and check result.
980
; 1. Allocate and check result.
981
	push	sizeof.PARTITION
981
        push    sizeof.PARTITION
982
	pop	eax
982
        pop     eax
983
	call	malloc
983
        call    malloc
984
	test	eax, eax
984
        test    eax, eax
985
	jz	.nothing
985
        jz      .nothing
986
; 2. Fill the common fields: copy .start and .length.
986
; 2. Fill the common fields: copy .start and .length.
987
	mov	edx, dword [.start]
987
        mov     edx, dword [.start]
988
	mov	dword [eax+PARTITION.FirstSector], edx
988
        mov     dword [eax+PARTITION.FirstSector], edx
989
	mov	edx, dword [.start+4]
989
        mov     edx, dword [.start+4]
990
	mov	dword [eax+PARTITION.FirstSector+4], edx
990
        mov     dword [eax+PARTITION.FirstSector+4], edx
991
	mov	edx, dword [.length]
991
        mov     edx, dword [.length]
992
	mov	dword [eax+PARTITION.Length], edx
992
        mov     dword [eax+PARTITION.Length], edx
993
	mov	edx, dword [.length+4]
993
        mov     edx, dword [.length+4]
994
	mov	dword [eax+PARTITION.Length+4], edx
994
        mov     dword [eax+PARTITION.Length+4], edx
995
.nothing:
995
.nothing:
996
; 3. Return with eax = pointer to PARTITION or NULL.
996
; 3. Return with eax = pointer to PARTITION or NULL.
997
	ret
997
        ret
998
 
998
 
999
; This function is called from file_system_lfn.
999
; This function is called from file_system_lfn.
1000
; This handler gets the control each time when fn 70 is called
1000
; This handler gets the control each time when fn 70 is called
1001
; with unknown item of root subdirectory.
1001
; with unknown item of root subdirectory.
1002
; in: esi -> name
1002
; in: esi -> name
1003
;     ebp = 0 or rest of name relative to esi
1003
;     ebp = 0 or rest of name relative to esi
1004
; out: if the handler processes path, it must not return in file_system_lfn,
1004
; out: if the handler processes path, it must not return in file_system_lfn,
1005
;      but instead pop return address and return directly to the caller
1005
;      but instead pop return address and return directly to the caller
1006
;      otherwise simply return
1006
;      otherwise simply return
1007
dyndisk_handler:
1007
dyndisk_handler:
1008
	push	ebx edi 	; save registers used in file_system_lfn
1008
        push    ebx edi         ; save registers used in file_system_lfn
1009
; 1. Acquire the mutex.
1009
; 1. Acquire the mutex.
1010
	mov	ecx, disk_list_mutex
1010
        mov     ecx, disk_list_mutex
1011
	call	mutex_lock
1011
        call    mutex_lock
1012
; 2. Loop over the list of DISK structures.
1012
; 2. Loop over the list of DISK structures.
1013
; 2a. Initialize.
1013
; 2a. Initialize.
1014
	mov	ebx, disk_list
1014
        mov     ebx, disk_list
1015
.scan:
1015
.scan:
1016
; 2b. Get the next item.
1016
; 2b. Get the next item.
1017
	mov	ebx, [ebx+DISK.Next]
1017
        mov     ebx, [ebx+DISK.Next]
1018
; 2c. Check whether the list is done. If so, go to 3.
1018
; 2c. Check whether the list is done. If so, go to 3.
1019
	cmp	ebx, disk_list
1019
        cmp     ebx, disk_list
1020
	jz	.notfound
1020
        jz      .notfound
1021
; 2d. Compare names. If names match, go to 5.
1021
; 2d. Compare names. If names match, go to 5.
1022
	mov	edi, [ebx+DISK.Name]
1022
        mov     edi, [ebx+DISK.Name]
1023
	push	esi
1023
        push    esi
1024
@@:
1024
@@:
1025
; esi points to the name from fs operation; it is terminated by zero or slash.
1025
; esi points to the name from fs operation; it is terminated by zero or slash.
1026
	lodsb
1026
        lodsb
1027
	test	al, al
1027
        test    al, al
1028
	jz	.eoin_dec
1028
        jz      .eoin_dec
1029
	cmp	al, '/'
1029
        cmp     al, '/'
1030
	jz	.eoin
1030
        jz      .eoin
1031
; edi points to the disk name.
1031
; edi points to the disk name.
1032
	inc	edi
1032
        inc     edi
1033
; edi points to lowercase name, this is a requirement for the driver.
1033
; edi points to lowercase name, this is a requirement for the driver.
1034
; Characters at esi can have any register. Lowercase the current character.
1034
; Characters at esi can have any register. Lowercase the current character.
1035
; This lowercasing works for latin letters and digits; since the disk name
1035
; This lowercasing works for latin letters and digits; since the disk name
1036
; should not contain other symbols, this is ok.
1036
; should not contain other symbols, this is ok.
1037
	or	al, 20h
1037
        or      al, 20h
1038
	cmp	al, [edi-1]
1038
        cmp     al, [edi-1]
1039
	jz	@b
1039
        jz      @b
1040
.wrongname:
1040
.wrongname:
1041
; 2f. Names don't match. Continue the loop.
1041
; 2f. Names don't match. Continue the loop.
1042
	pop	esi
1042
        pop     esi
1043
	jmp	.scan
1043
        jmp     .scan
1044
.notfound:
1044
.notfound:
1045
; The loop is done and no name matches.
1045
; The loop is done and no name matches.
1046
; 3. Release the mutex.
1046
; 3. Release the mutex.
1047
	call mutex_unlock
1047
        call    mutex_unlock
1048
; 4. Return normally.
1048
; 4. Return normally.
1049
	pop	edi ebx 	; restore registers used in file_system_lfn
1049
        pop     edi ebx         ; restore registers used in file_system_lfn
1050
	ret
1050
        ret
1051
; part of 2d: the name matches partially, but we must check that this is full
1051
; part of 2d: the name matches partially, but we must check that this is full
1052
; equality.
1052
; equality.
1053
.eoin_dec:
1053
.eoin_dec:
1054
	dec	esi
1054
        dec     esi
1055
.eoin:
1055
.eoin:
1056
	cmp	byte [edi], 0
1056
        cmp     byte [edi], 0
1057
	jnz	.wrongname
1057
        jnz     .wrongname
1058
; We found the addressed DISK structure.
1058
; We found the addressed DISK structure.
1059
; 5. Reference the disk.
1059
; 5. Reference the disk.
1060
lock	inc	[ebx+DISK.RefCount]
1060
        lock inc [ebx+DISK.RefCount]
1061
; 6. Now we are sure that the DISK structure is not going to die at least
1061
; 6. Now we are sure that the DISK structure is not going to die at least
1062
; while we are working with it, so release the global mutex.
1062
; while we are working with it, so release the global mutex.
1063
	call	mutex_unlock
1063
        call    mutex_unlock
1064
; 7. Acquire the mutex for media object.
1064
; 7. Acquire the mutex for media object.
1065
	pop	edi		; restore edi
1065
        pop     edi             ; restore edi
1066
	lea	ecx, [ebx+DISK.MediaLock]
1066
        lea     ecx, [ebx+DISK.MediaLock]
1067
	call	mutex_lock
1067
        call    mutex_lock
1068
; 8. Get the media object. If it is not NULL, reference it.
1068
; 8. Get the media object. If it is not NULL, reference it.
1069
	xor	edx, edx
1069
        xor     edx, edx
1070
	cmp	[ebx+DISK.MediaInserted], dl
1070
        cmp     [ebx+DISK.MediaInserted], dl
1071
	jz	@f
1071
        jz      @f
1072
	mov	edx, ebx
1072
        mov     edx, ebx
1073
	inc	[ebx+DISK.MediaRefCount]
1073
        inc     [ebx+DISK.MediaRefCount]
1074
@@:
1074
@@:
1075
; 9. Now we are sure that the media object, if it exists, is not going to die
1075
; 9. Now we are sure that the media object, if it exists, is not going to die
1076
; at least while we are working with it, so release the mutex for media object.
1076
; at least while we are working with it, so release the mutex for media object.
1077
	call	mutex_unlock
1077
        call    mutex_unlock
1078
	mov	ecx, ebx
1078
        mov     ecx, ebx
1079
	pop	ebx eax 	; restore ebx, pop return address
1079
        pop     ebx eax         ; restore ebx, pop return address
1080
; 10. Check whether the fs operation wants to enumerate partitions (go to 11)
1080
; 10. Check whether the fs operation wants to enumerate partitions (go to 11)
1081
; or work with some concrete partition (go to 12).
1081
; or work with some concrete partition (go to 12).
1082
	cmp	byte [esi], 0
1082
        cmp     byte [esi], 0
1083
	jnz	.haspartition
1083
        jnz     .haspartition
1084
; 11. The fs operation wants to enumerate partitions.
1084
; 11. The fs operation wants to enumerate partitions.
1085
; 11a. Only "list directory" operation is applicable to / path. Check
1085
; 11a. Only "list directory" operation is applicable to / path. Check
1086
; the operation code. If wrong, go to 13.
1086
; the operation code. If wrong, go to 13.
1087
	cmp	dword [ebx], 1
1087
        cmp     dword [ebx], 1
1088
	jnz	.access_denied
1088
        jnz     .access_denied
1089
; 11b. If the media is inserted, use 'fs_dyndisk_next' as an enumeration
1089
; 11b. If the media is inserted, use 'fs_dyndisk_next' as an enumeration
1090
; procedure. Otherwise, use 'fs_dyndisk_next_nomedia'.
1090
; procedure. Otherwise, use 'fs_dyndisk_next_nomedia'.
1091
	mov	esi, fs_dyndisk_next_nomedia
1091
        mov     esi, fs_dyndisk_next_nomedia
1092
	test	edx, edx
1092
        test    edx, edx
1093
	jz	@f
1093
        jz      @f
1094
	mov	esi, fs_dyndisk_next
1094
        mov     esi, fs_dyndisk_next
1095
@@:
1095
@@:
1096
; 11c. Let the procedure from fs_lfn.inc do the job.
1096
; 11c. Let the procedure from fs_lfn.inc do the job.
1097
	jmp	file_system_lfn.maindir_noesi
1097
        jmp     file_system_lfn.maindir_noesi
1098
.haspartition:
1098
.haspartition:
1099
; 12. The fs operation has specified some partition.
1099
; 12. The fs operation has specified some partition.
1100
; 12a. Store parameters for callback functions.
1100
; 12a. Store parameters for callback functions.
1101
	push	edx
1101
        push    edx
1102
	push	ecx
1102
        push    ecx
1103
; 12b. Store callback functions.
1103
; 12b. Store callback functions.
1104
	push	dyndisk_cleanup
1104
        push    dyndisk_cleanup
1105
	push	fs_dyndisk
1105
        push    fs_dyndisk
1106
	mov	edi, esp
1106
        mov     edi, esp
1107
; 12c. Let the procedure from fs_lfn.inc do the job.
1107
; 12c. Let the procedure from fs_lfn.inc do the job.
1108
	jmp	file_system_lfn.found2
1108
        jmp     file_system_lfn.found2
1109
.access_denied:
1109
.access_denied:
1110
; 13. Fail the operation with the appropriate code.
1110
; 13. Fail the operation with the appropriate code.
1111
	mov	dword [esp+32], ERROR_ACCESS_DENIED
1111
        mov     dword [esp+32], ERROR_ACCESS_DENIED
1112
.cleanup:
1112
.cleanup:
1113
; 14. Cleanup.
1113
; 14. Cleanup.
1114
	mov	esi, ecx	; disk*dereference assume that esi points to DISK
1114
        mov     esi, ecx        ; disk*dereference assume that esi points to DISK
1115
.cleanup_esi:
1115
.cleanup_esi:
1116
	test	edx, edx	; if there are no media, we didn't reference it
1116
        test    edx, edx        ; if there are no media, we didn't reference it
1117
	jz	@f
1117
        jz      @f
1118
	call	disk_media_dereference
1118
        call    disk_media_dereference
1119
@@:
1119
@@:
1120
	call	disk_dereference
1120
        call    disk_dereference
1121
; 15. Return.
1121
; 15. Return.
1122
	ret
1122
        ret
1123
 
1123
 
1124
; This is a callback for cleaning up things called from file_system_lfn.found2.
1124
; This is a callback for cleaning up things called from file_system_lfn.found2.
1125
dyndisk_cleanup:
1125
dyndisk_cleanup:
1126
	mov	esi, [edi+8]
1126
        mov     esi, [edi+8]
1127
	mov	edx, [edi+12]
1127
        mov     edx, [edi+12]
1128
	jmp	dyndisk_handler.cleanup_esi
1128
        jmp     dyndisk_handler.cleanup_esi
1129
 
1129
 
1130
; This is a callback for enumerating partitions called from
1130
; This is a callback for enumerating partitions called from
1131
; file_system_lfn.maindir in the case of inserted media.
1131
; file_system_lfn.maindir in the case of inserted media.
1132
; It just increments eax until DISK.NumPartitions reached and then
1132
; It just increments eax until DISK.NumPartitions reached and then
1133
; cleans up.
1133
; cleans up.
1134
fs_dyndisk_next:
1134
fs_dyndisk_next:
1135
	cmp	eax, [ecx+DISK.NumPartitions]
1135
        cmp     eax, [ecx+DISK.NumPartitions]
1136
	jae	.nomore
1136
        jae     .nomore
1137
	inc	eax
1137
        inc     eax
1138
	clc
1138
        clc
1139
	ret
1139
        ret
1140
.nomore:
1140
.nomore:
1141
	pusha
1141
        pusha
1142
	mov	esi, ecx
1142
        mov     esi, ecx
1143
	call	disk_media_dereference
1143
        call    disk_media_dereference
1144
	call	disk_dereference
1144
        call    disk_dereference
1145
	popa
1145
        popa
1146
	stc
1146
        stc
1147
	ret
1147
        ret
1148
 
1148
 
1149
; This is a callback for enumerating partitions called from
1149
; This is a callback for enumerating partitions called from
1150
; file_system_lfn.maindir in the case of missing media.
1150
; file_system_lfn.maindir in the case of missing media.
1151
; In this case we create one pseudo-partition.
1151
; In this case we create one pseudo-partition.
1152
fs_dyndisk_next_nomedia:
1152
fs_dyndisk_next_nomedia:
1153
	cmp	eax, 1
1153
        cmp     eax, 1
1154
	jae	.nomore
1154
        jae     .nomore
1155
	inc	eax
1155
        inc     eax
1156
	clc
1156
        clc
1157
	ret
1157
        ret
1158
.nomore:
1158
.nomore:
1159
	pusha
1159
        pusha
1160
	mov	esi, ecx
1160
        mov     esi, ecx
1161
	call	disk_dereference
1161
        call    disk_dereference
1162
	popa
1162
        popa
1163
	stc
1163
        stc
1164
	ret
1164
        ret
1165
 
1165
 
1166
; This is a callback for doing real work with selected partition.
1166
; This is a callback for doing real work with selected partition.
1167
; Currently this is just placeholder, since no file systems are supported.
1167
; Currently this is just placeholder, since no file systems are supported.
1168
; edi = esp -> {dd fs_dyndisk, dd dyndisk_cleanup, dd pointer to DISK, dd media object}
1168
; edi = esp -> {dd fs_dyndisk, dd dyndisk_cleanup, dd pointer to DISK, dd media object}
1169
; ecx = partition number, esi+ebp = ASCIIZ name
1169
; ecx = partition number, esi+ebp = ASCIIZ name
1170
fs_dyndisk:
1170
fs_dyndisk:
1171
	dec	ecx	; convert to zero-based partition index
1171
        dec     ecx     ; convert to zero-based partition index
1172
	pop	edx edx edx eax ; edx = pointer to DISK, eax = NULL or edx
1172
        pop     edx edx edx eax ; edx = pointer to DISK, eax = NULL or edx
1173
	test	eax, eax
1173
        test    eax, eax
1174
	jz	.nomedia
1174
        jz      .nomedia
1175
.main:
1175
.main:
1176
	cmp	ecx, [edx+DISK.NumPartitions]
1176
        cmp     ecx, [edx+DISK.NumPartitions]
1177
	jae	.notfound
1177
        jae     .notfound
1178
	mov	dword [esp+32], ERROR_UNKNOWN_FS
1178
        mov     dword [esp+32], ERROR_UNKNOWN_FS
1179
.cleanup:
1179
.cleanup:
1180
	mov	esi, edx
1180
        mov     esi, edx
1181
	call	disk_media_dereference
1181
        call    disk_media_dereference
1182
	call	disk_dereference
1182
        call    disk_dereference
1183
	ret
1183
        ret
1184
.notfound:
1184
.notfound:
1185
	mov	dword [esp+32], ERROR_FILE_NOT_FOUND
1185
        mov     dword [esp+32], ERROR_FILE_NOT_FOUND
1186
	jmp	.cleanup
1186
        jmp     .cleanup
1187
.nomedia:
1187
.nomedia:
1188
	test	ecx, ecx
1188
        test    ecx, ecx
1189
	jnz	.notfound
1189
        jnz     .notfound
1190
	test	byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
1190
        test    byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
1191
	jz	.deverror
1191
        jz      .deverror
1192
; if the driver does not support insert notifications and we are the only fs
1192
; if the driver does not support insert notifications and we are the only fs
1193
; operation with this disk, issue the fake insert notification; if media is
1193
; operation with this disk, issue the fake insert notification; if media is
1194
; still not inserted, 'disk_media_changed' will detect this and do nothing
1194
; still not inserted, 'disk_media_changed' will detect this and do nothing
1195
;;;        push    ebx
1195
;;;        push    ebx
1196
	lea	ecx, [edx+DISK.MediaLock]
1196
        lea     ecx, [edx+DISK.MediaLock]
1197
	call	mutex_lock
1197
        call    mutex_lock
1198
	cmp	[edx+DISK.MediaRefCount], 1
1198
        cmp     [edx+DISK.MediaRefCount], 1
1199
	jnz	.noluck
1199
        jnz     .noluck
1200
	call	mutex_unlock
1200
        call    mutex_unlock
1201
	push	edx
1201
        push    edx
1202
	stdcall disk_media_changed, edx, 1
1202
        stdcall disk_media_changed, edx, 1
1203
	pop	edx
1203
        pop     edx
1204
	lea	ecx, [edx+DISK.MediaLock]
1204
        lea     ecx, [edx+DISK.MediaLock]
1205
	call	mutex_lock
1205
        call    mutex_lock
1206
	cmp	[edx+DISK.MediaInserted], 0
1206
        cmp     [edx+DISK.MediaInserted], 0
1207
	jz	.noluck
1207
        jz      .noluck
1208
lock	inc	[edx+DISK.MediaRefCount]
1208
        lock inc [edx+DISK.MediaRefCount]
1209
	call	mutex_unlock
1209
        call    mutex_unlock
1210
	xor	ecx, ecx
1210
        xor     ecx, ecx
1211
	jmp	.main
1211
        jmp     .main
1212
.noluck:
1212
.noluck:
1213
	call	mutex_unlock
1213
        call    mutex_unlock
1214
.deverror:
1214
.deverror:
1215
	mov	dword [esp+32], ERROR_DEVICE
1215
        mov     dword [esp+32], ERROR_DEVICE
1216
	mov	esi, edx
1216
        mov     esi, edx
1217
	call	disk_dereference
1217
        call    disk_dereference
1218
	ret
1218
        ret
1219
 
1219
 
1220
; This function is called from file_system_lfn.
1220
; This function is called from file_system_lfn.
1221
; This handler is called when virtual root is enumerated
1221
; This handler is called when virtual root is enumerated
1222
; and must return all items which can be handled by this.
1222
; and must return all items which can be handled by this.
1223
; It is called several times, first time with eax=0
1223
; It is called several times, first time with eax=0
1224
; in: eax = 0 for first call, previously returned value for subsequent calls
1224
; in: eax = 0 for first call, previously returned value for subsequent calls
1225
; out: eax = 0 => no more items
1225
; out: eax = 0 => no more items
1226
;      eax != 0 => buffer pointed to by edi contains name of item
1226
;      eax != 0 => buffer pointed to by edi contains name of item
1227
dyndisk_enum_root:
1227
dyndisk_enum_root:
1228
	push	edx		; save register used in file_system_lfn
1228
        push    edx             ; save register used in file_system_lfn
1229
	mov	ecx, disk_list_mutex	; it will be useful
1229
        mov     ecx, disk_list_mutex    ; it will be useful
1230
; 1. If this is the first call, acquire the mutex and initialize.
1230
; 1. If this is the first call, acquire the mutex and initialize.
1231
	test	eax, eax
1231
        test    eax, eax
1232
	jnz	.notfirst
1232
        jnz     .notfirst
1233
	call	mutex_lock
1233
        call    mutex_lock
1234
	mov	eax, disk_list
1234
        mov     eax, disk_list
1235
.notfirst:
1235
.notfirst:
1236
; 2. Get next item.
1236
; 2. Get next item.
1237
	mov	eax, [eax+DISK.Next]
1237
        mov     eax, [eax+DISK.Next]
1238
; 3. If there are no more items, go to 6.
1238
; 3. If there are no more items, go to 6.
1239
	cmp	eax, disk_list
1239
        cmp     eax, disk_list
1240
	jz	.last
1240
        jz      .last
1241
; 4. Copy name from the DISK structure to edi.
1241
; 4. Copy name from the DISK structure to edi.
1242
	push	eax esi
1242
        push    eax esi
1243
	mov	esi, [eax+DISK.Name]
1243
        mov     esi, [eax+DISK.Name]
1244
@@:
1244
@@:
1245
	lodsb
1245
        lodsb
1246
	stosb
1246
        stosb
1247
	test	al, al
1247
        test    al, al
1248
	jnz	@b
1248
        jnz     @b
1249
	pop	esi eax
1249
        pop     esi eax
1250
; 5. Return with eax = item.
1250
; 5. Return with eax = item.
1251
	pop	edx		; restore register used in file_system_lfn
1251
        pop     edx             ; restore register used in file_system_lfn
1252
	ret
1252
        ret
1253
.last:
1253
.last:
1254
; 6. Release the mutex and return with eax = 0.
1254
; 6. Release the mutex and return with eax = 0.
1255
	call	mutex_unlock
1255
        call    mutex_unlock
1256
	xor	eax, eax
1256
        xor     eax, eax
1257
	pop	edx		; restore register used in file_system_lfn
1257
        pop     edx             ; restore register used in file_system_lfn
1258
	ret
1258
        ret