41df6046358283abb847f2551c8dae2b3d72478c
[tpg/acess2.git] / Kernel / drvutil.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge
4  *
5  * drvutil.c
6  * - Common Driver/Filesystem Helper Functions
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <api_drv_disk.h>
11 #include <api_drv_video.h>
12
13 // === TYPES ===
14
15 // === PROTOTYPES ===
16 //int   DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
17 //size_t        DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
18 //void  DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
19 //void  DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
20 void    DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
21 //void  DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
22 void    DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
23 void    DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
24
25 // === GLOBALS ===
26 tDrvUtil_Video_2DHandlers       gDrvUtil_Stub_2DFunctions = {
27         NULL,
28         DrvUtil_Video_2D_Fill,
29         DrvUtil_Video_2D_Blit
30 };
31 tVideo_IOCtl_Bitmap     gDrvUtil_TextModeCursor = {
32         8, 16,
33         0, 0,
34         {
35                 0, 0, 0         , 0, 0, 0, 0, 0,
36                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
37                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
38                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
39                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
40                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
41                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
42                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
43                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
44                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
45                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
46                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
47                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
48                 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
49                 0, 0, 0         , 0, 0, 0, 0, 0,
50                 0, 0, 0         , 0, 0, 0, 0, 0
51         }
52 };
53
54 // === CODE ===
55 // --- Video Driver Helpers ---
56 int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length,
57         tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
58 {
59         void    *stream = Buffer;
60          int    rem = Length;
61          int    op;
62         while( rem )
63         {
64                 rem --;
65                 op = *(Uint8*)stream;
66                 stream = (void*)((tVAddr)stream + 1);
67                 
68                 if(op > NUM_VIDEO_2DOPS) {
69                         Log_Warning("DrvUtil",
70                                 "DrvUtil_Video_2DStream: Unknown operation %i",
71                                 op);
72                         return Length-rem;
73                 }
74                 
75                 if(op*sizeof(void*) > SizeofHandlers) {
76                         Log_Warning("DrvUtil",
77                                 "DrvUtil_Video_2DStream: Driver does not support op %i",
78                                 op);
79                         return Length-rem;
80                 }
81                 
82                 switch(op)
83                 {
84                 case VIDEO_2DOP_NOP:    break;
85                 
86                 case VIDEO_2DOP_FILL:
87                         if(rem < 12)    return Length-rem;
88                         
89                         if(!Handlers->Fill) {
90                                 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
91                                         " does not support VIDEO_2DOP_FILL");
92                                 return Length-rem;
93                         }
94                         
95                         Handlers->Fill(
96                                 Ent,
97                                 ((Uint16*)stream)[0], ((Uint16*)stream)[1],
98                                 ((Uint16*)stream)[2], ((Uint16*)stream)[3],
99                                 ((Uint32*)stream)[2]
100                                 );
101                         
102                         rem -= 12;
103                         stream = (void*)((tVAddr)stream + 12);
104                         break;
105                 
106                 case VIDEO_2DOP_BLIT:
107                         if(rem < 12)    return Length-rem;
108                         
109                         if(!Handlers->Blit) {
110                                 Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
111                                         " does not support VIDEO_2DOP_BLIT");
112                                 return Length-rem;
113                         }
114                         
115                         Handlers->Blit(
116                                 Ent,
117                                 ((Uint16*)stream)[0], ((Uint16*)stream)[1],
118                                 ((Uint16*)stream)[2], ((Uint16*)stream)[3],
119                                 ((Uint16*)stream)[4], ((Uint16*)stream)[5]
120                                 );
121                         
122                         rem -= 12;
123                         stream = (void*)((tVAddr)stream + 12);
124                         break;
125                 
126                 }
127         }
128         return 0;
129 }
130
131 int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Buffer)
132 {
133         Uint8   *dest;
134         Uint32  *src = Buffer;
135          int    csr_x, csr_y;
136          int    x, y;
137          int    bytes_per_px = (FBInfo->Depth + 7) / 8;
138         ENTER("pFBInfo xOffset xLength pBuffer",
139                 Mode, FBInfo, Offset, Length, Buffer);
140
141         csr_x = FBInfo->CursorX;
142         csr_y = FBInfo->CursorY;
143
144         DrvUtil_Video_RemoveCursor(FBInfo);
145
146         switch( FBInfo->BufferFormat )
147         {
148         case VIDEO_BUFFMT_TEXT:
149                 {
150                 tVT_Char        *chars = Buffer;
151                  int    widthInChars = FBInfo->Width/giVT_CharWidth;
152                  int    heightInChars = FBInfo->Height/giVT_CharHeight;
153                  int    i;
154         
155                 LOG("bytes_per_px = %i", bytes_per_px);
156                 LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
157         
158                 Length /= sizeof(tVT_Char);     Offset /= sizeof(tVT_Char);
159                 
160                 x = Offset % widthInChars;      y = Offset / widthInChars;
161                 LOG("x = %i, y = %i", x, y);    
162         
163                 // Sanity Check
164                 if(Offset > heightInChars * widthInChars)       LEAVE_RET('i', 0);
165                 if(y >= heightInChars)  LEAVE_RET('i', 0);
166                 
167                 if( Offset + Length > heightInChars*widthInChars )
168                 {
169                         Length = heightInChars*widthInChars - Offset;
170                 }
171                 
172                 dest = FBInfo->Framebuffer;
173                 LOG("dest = %p", dest);
174                 dest += y * giVT_CharHeight * FBInfo->Pitch;
175                 LOG("dest = %p", dest);
176                 
177                 for( i = 0; i < Length; i++ )
178                 {
179                         if( y >= heightInChars )
180                         {
181                                 Log_Notice("DrvUtil", "Stopped at %i", i);
182                                 break;
183                         }
184
185                         VT_Font_Render(
186                                 chars->Ch,
187                                 dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
188                                 VT_Colour12toN(chars->BGCol, FBInfo->Depth),
189                                 VT_Colour12toN(chars->FGCol, FBInfo->Depth)
190                                 );
191                         
192                         chars ++;
193                         x ++;
194                         if( x >= widthInChars )
195                         {
196                                 x = 0;
197                                 y ++;
198                                 dest += FBInfo->Pitch*giVT_CharHeight;
199                                 LOG("dest = %p", dest);
200                         }
201                 }
202                 Length = i * sizeof(tVT_Char);
203                 }
204                 break;
205         
206         case VIDEO_BUFFMT_FRAMEBUFFER:
207                 if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
208                 {
209                         Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
210                         return 0;
211                 }
212                 
213                 switch(FBInfo->Depth)
214                 {
215                 case 15:
216                 case 16:
217                         Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
218                         break;
219                 case 24:
220                         x = Offset % FBInfo->Width;
221                         y = Offset / FBInfo->Width;
222                         dest = (Uint8*)FBInfo->Framebuffer + y*FBInfo->Pitch;
223                         for( ; Length >= 4; Length -= 4 )
224                         {
225                                 dest[x*3+0] = *src & 0xFF;
226                                 dest[x*3+1] = (*src >> 8) & 0xFF;
227                                 dest[x*3+2] = (*src >> 16) & 0xFF;
228                                 x ++;
229                                 if(x == FBInfo->Width) {
230                                         dest += FBInfo->Pitch;
231                                         x = 0;
232                                 }
233                         }
234                         break;
235                 case 32:
236                         // Copy to Frambuffer
237                         if( FBInfo->Pitch != FBInfo->Width*4 )
238                         {
239                                 // Pitch isn't 4*Width
240                                 x = Offset % FBInfo->Width;
241                                 y = Offset / FBInfo->Height;
242                                 
243                                 dest = (Uint8*)FBInfo->Framebuffer + y*FBInfo->Pitch;
244
245                                 for( ; Length >= 4; Length -= 4, x )
246                                 {
247                                         ((Uint32*)dest)[x++] = *src ++;
248                                         if( x == FBInfo->Width ) {
249                                                 x = 0;
250                                                 dest += FBInfo->Pitch;
251                                         }
252                                 }
253                         }
254                         else
255                         {
256                                 dest = (Uint8 *)FBInfo->Framebuffer + Offset;
257                                 memcpy(dest, Buffer, Length);
258                         }
259                         break;
260                 default:
261                         Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depthn %i", FBInfo->Depth);
262                         break;
263                 }
264                 break;
265         
266         case VIDEO_BUFFMT_2DSTREAM:
267                 Length = DrvUtil_Video_2DStream(
268                         FBInfo, Buffer, Length,
269                         &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
270                         );
271                 break;
272         
273         default:
274                 LEAVE('i', -1);
275                 return -1;
276         }
277
278         DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
279
280         LEAVE('x', Length);
281         return Length;
282 }
283
284 int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
285 {
286          int    csrX = Buf->CursorX, csrY = Buf->CursorY;
287         size_t  size;
288
289         // Clear old bitmap
290         if( Buf->CursorBitmap )
291         {
292                 DrvUtil_Video_RemoveCursor(Buf);
293                 if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
294                 {
295                         free( Buf->CursorSaveBuf );
296                         Buf->CursorSaveBuf = NULL;
297                 }
298                 if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
299                         free(Buf->CursorBitmap);
300                 Buf->CursorBitmap = NULL;
301         }
302         
303         // If the new bitmap is null, disable drawing
304         if( !Bitmap )
305         {
306                 Buf->CursorX = -1;
307                 Buf->CursorY = -1;
308                 return 0;
309         }
310
311         // Sanity check the bitmap
312         if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
313         {
314                 Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
315                 errno = -EINVAL;
316                 return -1;
317         }
318
319         // Don't take a copy of the DrvUtil provided cursor
320         if( Bitmap == &gDrvUtil_TextModeCursor )
321         {
322                 Buf->CursorBitmap = Bitmap;
323         }
324         else
325         {
326                 size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
327                 
328                 // Take a copy
329                 Buf->CursorBitmap = malloc( size );
330                 memcpy(Buf->CursorBitmap, Bitmap, size);
331         }
332         
333         // Restore cursor position
334         DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
335         return 0;
336 }
337
338 void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
339 {
340          int    render_ox=0, render_oy=0, render_w, render_h;
341
342         DrvUtil_Video_RemoveCursor(Buf);
343
344         // X < 0 disables the cursor
345         if( X < 0 ) {
346                 Buf->CursorX = -1;
347                 return ;
348         }
349
350         // Sanity checking
351         if( X < 0 || Y < 0 )    return;
352         if( X >= Buf->Width || Y >= Buf->Height )       return;
353
354         // Ensure the cursor is enabled
355         if( !Buf->CursorBitmap )        return ;
356         
357         // Save cursor position (for changing the bitmap)
358         Buf->CursorX = X;       Buf->CursorY = Y;
359
360         // Apply cursor's center offset
361         X -= Buf->CursorBitmap->XOfs;
362         Y -= Buf->CursorBitmap->YOfs;
363         
364         // Get the width of the cursor on screen (clipping to right/bottom edges)
365         render_w = X > Buf->Width  - Buf->CursorBitmap->W ? Buf->Width  - X : Buf->CursorBitmap->W;
366         render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
367
368         // Clipp to left/top edges
369         if(X < 0) {     render_ox = -X; X = 0;  }
370         if(Y < 0) {     render_oy = -Y; Y = 0;  }
371
372         // Save values
373         Buf->CursorRenderW = render_w;  Buf->CursorRenderH = render_h;
374         Buf->CursorDestX   = X;         Buf->CursorDestY = Y;
375         Buf->CursorReadX   = render_ox; Buf->CursorReadY = render_oy;
376
377         // Call render routine
378         DrvUtil_Video_RenderCursor(Buf);
379 }
380
381 void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
382 {
383          int    src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
384          int    render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
385          int    dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
386          int    bytes_per_px = (Buf->Depth + 7) / 8;
387          int    save_pitch = Buf->CursorBitmap->W * bytes_per_px;
388         void    *dest;
389         Uint32  *src;
390          int    x, y;
391
392         dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
393         src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
394         
395         // Allocate save buffer if not already
396         if( !Buf->CursorSaveBuf )
397                 Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
398
399         // Save behind the cursor
400         for( y = 0; y < render_h; y ++ )
401                 memcpy(
402                         (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
403                         (Uint8*)dest + y*Buf->Pitch,
404                         render_w*bytes_per_px
405                         );
406
407         // Draw the cursor
408         switch(Buf->Depth)
409         {
410         case 15:
411         case 16:
412                 Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
413                 break;
414         case 24:
415                 for( y = 0; y < render_h; y ++ )
416                 {
417                         Uint8   *px;
418                         px = dest;
419                         for(x = 0; x < render_w; x ++, px += 3)
420                         {
421                                 Uint32  value = src[x];
422                                 // TODO: Should I implement alpha blending?
423                                 if(value & 0xFF000000)
424                                 {
425                                         px[0] = value & 0xFF;
426                                         px[1] = (value >> 8) & 0xFF;
427                                         px[2] = (value >> 16) & 0xFF;
428                                 }
429                                 else
430                                         ;
431                         }
432                         src += Buf->CursorBitmap->W;
433                         dest = (Uint8*)dest + Buf->Pitch;
434                 }
435                 break;
436         case 32:
437                 for( y = 0; y < render_h; y ++ )
438                 {
439                         Uint32  *px;
440                         px = dest;
441                         for(x = 0; x < render_w; x ++, px ++)
442                         {
443                                 Uint32  value = src[x];
444                                 // TODO: Should I implement alpha blending?
445                                 if(value & 0xFF000000)
446                                         *px = value;
447                                 else
448                                         ;       // NOP, completely transparent
449                         }
450                         src += Buf->CursorBitmap->W;
451                         dest = (Uint8*)dest + Buf->Pitch;
452                 }
453                 break;
454         default:
455                 Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
456                 Buf->CursorX = -1;
457                 break;
458         }
459 }
460
461 void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
462 {
463          int    bytes_per_px = (Buf->Depth + 7) / 8;
464          int    y, save_pitch;
465         Uint8   *dest, *src;
466
467         // Just a little sanity
468         if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
469         if( !Buf->CursorSaveBuf )       return ;
470
471 //      Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
472
473         // Set up
474         save_pitch = Buf->CursorBitmap->W * bytes_per_px;
475         dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
476         src = Buf->CursorSaveBuf;
477         
478         // Copy each line back
479         for( y = 0; y < Buf->CursorRenderH; y ++ )
480         {
481                 memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
482                 src += save_pitch;
483                 dest += Buf->Pitch;
484         }
485         
486         // Set the cursor as removed
487         Buf->CursorX = -1;
488 }
489
490 void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
491 {
492         tDrvUtil_Video_BufInfo  *FBInfo = Ent;
493
494         // TODO: Handle non-32bit modes
495         if( FBInfo->Depth != 32 )       return;
496
497         // TODO: Be less hacky
498          int    pitch = FBInfo->Pitch/4;
499         Uint32  *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
500         while( H -- ) {
501                 Uint32 *tmp;
502                  int    i;
503                 tmp = buf;
504                 for(i=W;i--;tmp++)      *tmp = Colour;
505                 buf += pitch;
506         }
507 }
508
509 void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
510 {
511         tDrvUtil_Video_BufInfo  *FBInfo = Ent;
512          int    scrnpitch = FBInfo->Pitch;
513          int    bytes_per_px = (FBInfo->Depth + 7) / 8;
514          int    dst = DstY*scrnpitch + DstX;
515          int    src = SrcY*scrnpitch + SrcX;
516          int    tmp;
517         
518         //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
519         //      Ent, DstX, DstY, SrcX, SrcY, W, H);
520         
521         if(SrcX + W > FBInfo->Width)    W = FBInfo->Width - SrcX;
522         if(DstX + W > FBInfo->Width)    W = FBInfo->Width - DstX;
523         if(SrcY + H > FBInfo->Height)   H = FBInfo->Height - SrcY;
524         if(DstY + H > FBInfo->Height)   H = FBInfo->Height - DstY;
525         
526         //Debug("W = %i, H = %i", W, H);
527         
528         if( dst > src ) {
529                 // Reverse copy
530                 dst += H*scrnpitch;
531                 src += H*scrnpitch;
532                 while( H -- ) {
533                         dst -= scrnpitch;
534                         src -= scrnpitch;
535                         tmp = W*bytes_per_px;
536                         for( tmp = W; tmp --; ) {
537                                 *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
538                         }
539                 }
540         }
541         else {
542                 // Normal copy is OK
543                 while( H -- ) {
544                         memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
545                         dst += scrnpitch;
546                         src += scrnpitch;
547                 }
548         }
549         //Log("Vesa_2D_Blit: RETURN");
550 }
551         
552
553 // --- Disk Driver Helpers ---
554 Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
555         tDrvUtil_Callback ReadBlocks, Uint64 BlockSize, Uint Argument)
556 {
557         Uint8   tmp[BlockSize]; // C99
558         Uint64  block = Start / BlockSize;
559          int    offset = Start - block * BlockSize;
560          int    leading = BlockSize - offset;
561         Uint64  num;
562          int    tailings;
563         Uint64  ret;
564         
565         ENTER("XStart XLength pBuffer pReadBlocks XBlockSize xArgument",
566                 Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
567         
568         // Non aligned start, let's fix that!
569         if(offset != 0)
570         {
571                 if(leading > Length)    leading = Length;
572                 LOG("Reading %i bytes from Block1+%i", leading, offset);
573                 ret = ReadBlocks(block, 1, tmp, Argument);
574                 if(ret != 1) {
575                         LEAVE('i', 0);
576                         return 0;
577                 }
578                 memcpy( Buffer, &tmp[offset], leading );
579                 
580                 if(leading == Length) {
581                         LEAVE('i', leading);
582                         return leading;
583                 }
584                 
585                 Buffer = (Uint8*)Buffer + leading;
586                 block ++;
587                 num = ( Length - leading ) / BlockSize;
588                 tailings = Length - num * BlockSize - leading;
589         }
590         else {
591                 num = Length / BlockSize;
592                 tailings = Length % BlockSize;
593         }
594         
595         // Read central blocks
596         if(num)
597         {
598                 LOG("Reading %i blocks", num);
599                 ret = ReadBlocks(block, num, Buffer, Argument);
600                 if(ret != num ) {
601                         LEAVE('X', leading + ret * BlockSize);
602                         return leading + ret * BlockSize;
603                 }
604         }
605         
606         // Read last tailing block
607         if(tailings != 0)
608         {
609                 LOG("Reading %i bytes from last block", tailings);
610                 block += num;
611                 Buffer = (Uint8*)Buffer + num * BlockSize;
612                 ret = ReadBlocks(block, 1, tmp, Argument);
613                 if(ret != 1) {
614                         LEAVE('X', leading + num * BlockSize);
615                         return leading + num * BlockSize;
616                 }
617                 memcpy( Buffer, tmp, tailings );
618         }
619         
620         LEAVE('X', Length);
621         return Length;
622 }
623
624 Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, void *Buffer,
625         tDrvUtil_Callback ReadBlocks, tDrvUtil_Callback WriteBlocks,
626         Uint64 BlockSize, Uint Argument)
627 {
628         Uint8   tmp[BlockSize]; // C99
629         Uint64  block = Start / BlockSize;
630          int    offset = Start - block * BlockSize;
631          int    leading = BlockSize - offset;
632         Uint64  num;
633          int    tailings;
634         Uint64  ret;
635         
636         ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize xArgument",
637                 Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
638         
639         // Non aligned start, let's fix that!
640         if(offset != 0)
641         {
642                 if(leading > Length)    leading = Length;
643                 LOG("Writing %i bytes to Block1+%i", leading, offset);
644                 // Read a copy of the block
645                 ret = ReadBlocks(block, 1, tmp, Argument);
646                 if(ret != 1) {
647                         LEAVE('i', 0);
648                         return 0;
649                 }
650                 // Modify
651                 memcpy( &tmp[offset], Buffer, leading );
652                 // Write Back
653                 ret = WriteBlocks(block, 1, tmp, Argument);
654                 if(ret != 1) {
655                         LEAVE('i', 0);
656                         return 0;
657                 }
658                 
659                 if(leading == Length) {
660                         LEAVE('i', leading);
661                         return leading;
662                 }
663                 
664                 Buffer = (Uint8*)Buffer + leading;
665                 block ++;
666                 num = ( Length - leading ) / BlockSize;
667                 tailings = Length - num * BlockSize - leading;
668         }
669         else {
670                 num = Length / BlockSize;
671                 tailings = Length % BlockSize;
672         }
673         
674         // Read central blocks
675         if(num)
676         {
677                 LOG("Writing %i blocks", num);
678                 ret = WriteBlocks(block, num, Buffer, Argument);
679                 if(ret != num ) {
680                         LEAVE('X', leading + ret * BlockSize);
681                         return leading + ret * BlockSize;
682                 }
683         }
684         
685         // Read last tailing block
686         if(tailings != 0)
687         {
688                 LOG("Writing %i bytes to last block", tailings);
689                 block += num;
690                 Buffer = (Uint8*)Buffer + num * BlockSize;
691                 // Read
692                 ret = ReadBlocks(block, 1, tmp, Argument);
693                 if(ret != 1) {
694                         LEAVE('X', leading + num * BlockSize);
695                         return leading + num * BlockSize;
696                 }
697                 // Modify
698                 memcpy( tmp, Buffer, tailings );
699                 // Write
700                 ret = WriteBlocks(block, 1, tmp, Argument);
701                 if(ret != 1) {
702                         LEAVE('X', leading + num * BlockSize);
703                         return leading + num * BlockSize;
704                 }
705                 
706         }
707         
708         LEAVE('X', Length);
709         return Length;
710 }

UCC git Repository :: git.ucc.asn.au