1 /*
2    Copyright (c) 2003 Andreas Robinson, All rights reserved.
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2 of the License, or (at your option) any later version.
8 */
9 
10 // DirectFB headers
11 
12 #include <config.h>
13 
14 #include <fbdev/fbdev.h>
15 
16 #include <directfb.h>
17 
18 #include <direct/messages.h>
19 
20 #include <fusion/shmalloc.h>
21 
22 #include <core/coretypes.h>
23 #include <core/core.h>
24 #include <core/gfxcard.h>
25 #include <core/graphics_driver.h>
26 #include <core/system.h>
27 #include <core/screens.h>
28 
29 #include <misc/conf.h>
30 
31 #include <fbdev/fb.h>
32 
33 // System headers
34 
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <sys/mman.h>
39 #include <unistd.h>
40 #include <stdio.h>
41 
42 #include <string.h>
43 
44 // Driver headers
45 
46 #include "unichrome.h"
47 #include "uc_state.h"
48 #include "uc_accel.h"
49 #include "uc_fifo.h"
50 #include "uc_ioctl.h"
51 #include "mmio.h"
52 #include "uc_probe.h"
53 
54 extern DisplayLayerFuncs ucOverlayFuncs;
55 extern DisplayLayerFuncs ucPrimaryFuncs;
56 extern DisplayLayerFuncs ucSubpictureFuncs;
57 
58 extern DisplayLayerFuncs  ucOldPrimaryFuncs;
59 extern void              *ucOldPrimaryDriverData;
60 
61 
DFB_GRAPHICS_DRIVER(unichrome)62 DFB_GRAPHICS_DRIVER(unichrome)
63 
64 //----------
65 
66 /* PCI probing code is derived from gfxdrivers/matrox/matrox.c */
67 
68 /** Read PCI configuration register 'reg' for device at {bus,slot,func}. */
69 static int pci_config_in8( unsigned int bus,
70                            unsigned int slot,
71                            unsigned int func,
72                            u8 reg )
73 {
74     char  filename[512];
75     int   fd;
76     int   val;
77 
78     val = 0;
79 
80     snprintf( filename, 512, "/proc/bus/pci/%02x/%02x.%x", bus, slot, func );
81 
82     fd = open( filename, O_RDONLY );
83     if (fd < 0) {
84         D_PERROR( "DirectFB/Unichrome: Error opening `%s'!\n", filename );
85         return -1;
86     }
87 
88     if (lseek( fd, reg, SEEK_SET ) == reg) {
89         if (read( fd, &val, 1 ) == 1) {
90             close( fd );
91             return val;
92         }
93     }
94 
95     close( fd );
96     return -1;
97 }
98 
99 /* Probe for a Unichrome device.
100 * @returns DFB_OK if successful, with ucdrv->hwid, ucdrv->hwrev,
101 * and ucdrv->name filled in.
102 */
uc_probe_pci(UcDriverData * ucdrv)103 static DFBResult uc_probe_pci( UcDriverData *ucdrv )
104 {
105     unsigned int    bus, devfn, vendor, device;
106     char            line[512];
107     FILE            *file;
108     int             i;
109 
110     const char* filename = "/proc/bus/pci/devices";
111 
112     file = fopen( filename, "r" );
113     if (!file) {
114         D_PERROR( "DirectFB/Unichrome: Error opening `%s'!\n", filename );
115         return errno2result( errno );
116     }
117 
118     while (fgets( line, 512, file )) {
119         if (sscanf( line, "%02x%02x\t%04x%04x",
120             &bus, &devfn, &vendor, &device ) != 4)
121             continue;
122 
123         if (vendor != PCI_VENDOR_ID_VIA)
124             continue;
125 
126         for (i = 0; uc_via_devices[i].id != 0; i++) {
127             if (device == uc_via_devices[i].id) {
128                 // Found a Unichrome device.
129                 ucdrv->hwid = device;
130                 ucdrv->name = uc_via_devices[i].name;
131                 // Read its revision number from the host bridge.
132                 ucdrv->hwrev = pci_config_in8(0, 0, 0, 0xf6);
133                 if (ucdrv->hwrev == -1 && dfb_config->unichrome_revision == -1) {
134                     ucdrv->hwrev = 0x11;    // a fairly arbitrary default
135                     D_ERROR( "DirectFB/Unichrome: Failed to determine hardware revision, assuming %d.\n",
136                         ucdrv->hwrev );
137                 }
138                 // Because we can only auto-detect if we're superuser,
139                 // allow an override
140                 if (dfb_config->unichrome_revision != -1)
141                     ucdrv->hwrev = dfb_config->unichrome_revision;
142                 fclose( file );
143                 return DFB_OK;
144             }
145         }
146     }
147 
148     D_ERROR( "DirectFB/Unichrome: Can't find a Unichrome device in `%s'!\n",
149         filename );
150 
151     fclose( file );
152     return DFB_INIT;
153 }
154 
155 /**
156  * Dump beginning of virtual queue.
157  * Use it to check that the VQ actually is in use. */
158 #if 0
159 static void uc_dump_vq(UcDeviceData *ucdev)
160 {
161      int i;
162      u8* vq;
163 
164      if (!ucdev->vq_start) return;
165      vq = dfb_system_video_memory_virtual(ucdev->vq_start);
166 
167      for (i = 0; i < 128; i++) {
168           printf("%02x ", *(vq+i));
169           if ((i+1) % 16 == 0) printf("\n");
170      }
171 }
172 #endif
173 
174 /** Allocate memory for the virtual queue. */
175 
uc_alloc_vq(CoreGraphicsDevice * device,UcDeviceData * ucdev)176 static DFBResult uc_alloc_vq(CoreGraphicsDevice *device, UcDeviceData *ucdev)
177 {
178      if (ucdev->vq_start) return DFB_OK;
179 
180      ucdev->vq_size = 256*1024; // 256kb
181      ucdev->vq_start = dfb_gfxcard_reserve_memory( device, ucdev->vq_size );
182 
183      if (!ucdev->vq_start)
184           return DFB_INIT;
185 
186      ucdev->vq_end = ucdev->vq_start + ucdev->vq_size - 1;
187 
188      // Debug: clear buffer
189      memset((void *) dfb_system_video_memory_virtual(ucdev->vq_start),
190             0xcc, ucdev->vq_size);
191 
192      // uc_dump_vq(ucdev);
193 
194      return DFB_OK;
195 }
196 
197 /**
198  * Initialize the hardware.
199  * @param enable    enable VQ if true (else disable it.)
200  */
201 
uc_init_2d_engine(CoreGraphicsDevice * device,UcDeviceData * ucdev,UcDriverData * ucdrv,bool enable)202 static DFBResult uc_init_2d_engine(CoreGraphicsDevice *device, UcDeviceData *ucdev, UcDriverData *ucdrv, bool enable)
203 {
204      DFBResult result = DFB_OK;
205      volatile u8* hwregs = ucdrv->hwregs;
206      int i;
207 
208      // Init 2D engine registers to reset 2D engine
209 
210      for ( i = 0x04; i <= 0x40; i += 4 )
211           VIA_OUT(hwregs, i, 0x0);
212 
213      // Init AGP and VQ registers
214 
215      VIA_OUT(hwregs, 0x43c, 0x00100000);
216      VIA_OUT(hwregs, 0x440, 0x00000000);
217      VIA_OUT(hwregs, 0x440, 0x00333004);
218      VIA_OUT(hwregs, 0x440, 0x60000000);
219      VIA_OUT(hwregs, 0x440, 0x61000000);
220      VIA_OUT(hwregs, 0x440, 0x62000000);
221      VIA_OUT(hwregs, 0x440, 0x63000000);
222      VIA_OUT(hwregs, 0x440, 0x64000000);
223      VIA_OUT(hwregs, 0x440, 0x7D000000);
224 
225      VIA_OUT(hwregs, 0x43c, 0xfe020000);
226      VIA_OUT(hwregs, 0x440, 0x00000000);
227 
228      if (enable) {
229           result = uc_alloc_vq(device,ucdev);
230           enable = (result == DFB_OK);
231      }
232 
233      if (enable) { // Enable VQ
234 
235           VIA_OUT(hwregs, 0x43c, 0x00fe0000);
236           VIA_OUT(hwregs, 0x440, 0x080003fe);
237           VIA_OUT(hwregs, 0x440, 0x0a00027c);
238           VIA_OUT(hwregs, 0x440, 0x0b000260);
239           VIA_OUT(hwregs, 0x440, 0x0c000274);
240           VIA_OUT(hwregs, 0x440, 0x0d000264);
241           VIA_OUT(hwregs, 0x440, 0x0e000000);
242           VIA_OUT(hwregs, 0x440, 0x0f000020);
243           VIA_OUT(hwregs, 0x440, 0x1000027e);
244           VIA_OUT(hwregs, 0x440, 0x110002fe);
245           VIA_OUT(hwregs, 0x440, 0x200f0060);
246 
247           VIA_OUT(hwregs, 0x440, 0x00000006);
248           VIA_OUT(hwregs, 0x440, 0x40008c0f);
249           VIA_OUT(hwregs, 0x440, 0x44000000);
250           VIA_OUT(hwregs, 0x440, 0x45080c04);
251           VIA_OUT(hwregs, 0x440, 0x46800408);
252 
253           VIA_OUT(hwregs, 0x440, 0x52000000 |
254                   ((ucdev->vq_start & 0xFF000000) >> 24) |
255                   ((ucdev->vq_end & 0xFF000000) >> 16));
256           VIA_OUT(hwregs, 0x440, 0x50000000 | (ucdev->vq_start & 0xFFFFFF));
257           VIA_OUT(hwregs, 0x440, 0x51000000 | (ucdev->vq_end & 0xFFFFFF));
258           VIA_OUT(hwregs, 0x440, 0x53000000 | (ucdev->vq_size >> 3));
259      }
260      else { // Disable VQ
261 
262           VIA_OUT(hwregs, 0x43c, 0x00fe0000);
263           VIA_OUT(hwregs, 0x440, 0x00000004);
264           VIA_OUT(hwregs, 0x440, 0x40008c0f);
265           VIA_OUT(hwregs, 0x440, 0x44000000);
266           VIA_OUT(hwregs, 0x440, 0x45080c04);
267           VIA_OUT(hwregs, 0x440, 0x46800408);
268      }
269 
270      return result;
271 }
272 
uc_init_3d_engine(volatile u8 * hwregs,int hwrev,bool init_all)273 static void uc_init_3d_engine(volatile u8* hwregs, int hwrev, bool init_all)
274 {
275      u32 i;
276 
277      if (init_all) {
278 
279           // Clear NotTex registers
280 
281           VIA_OUT(hwregs, 0x43C, 0x00010000);
282           for (i = 0; i <= 0x7d; i++)
283                VIA_OUT(hwregs, 0x440, i << 24);
284 
285           // Clear texture unit 0
286 
287           VIA_OUT(hwregs, 0x43C, 0x00020000);
288           for (i = 0; i <= 0x94; i++)
289                VIA_OUT(hwregs, 0x440, i << 24);
290           VIA_OUT(hwregs, 0x440, 0x82400000);
291 
292           // Clear texture unit 1
293 
294           VIA_OUT(hwregs, 0x43C, 0x01020000);
295           for (i = 0; i <= 0x94; i++)
296                VIA_OUT(hwregs, 0x440, i << 24);
297           VIA_OUT(hwregs, 0x440, 0x82400000);
298 
299           // Clear general texture settings
300 
301           VIA_OUT(hwregs, 0x43C, 0xfe020000);
302           for (i = 0; i <= 0x03; i++)
303                VIA_OUT(hwregs, 0x440, i << 24);
304 
305           // Clear palette settings
306 
307           VIA_OUT(hwregs, 0x43C, 0x00030000);
308           for (i = 0; i <= 0xff; i++)
309                VIA_OUT(hwregs, 0x440, 0);
310 
311           VIA_OUT(hwregs, 0x43C, 0x00100000);
312           VIA_OUT(hwregs, 0x440, 0x00333004);
313           VIA_OUT(hwregs, 0x440, 0x10000002);
314           VIA_OUT(hwregs, 0x440, 0x60000000);
315           VIA_OUT(hwregs, 0x440, 0x61000000);
316           VIA_OUT(hwregs, 0x440, 0x62000000);
317           VIA_OUT(hwregs, 0x440, 0x63000000);
318           VIA_OUT(hwregs, 0x440, 0x64000000);
319 
320           VIA_OUT(hwregs, 0x43C, 0x00fe0000);
321 
322           if (hwrev >= 3)
323                VIA_OUT(hwregs, 0x440,0x40008c0f);
324           else
325                VIA_OUT(hwregs, 0x440,0x4000800f);
326 
327           VIA_OUT(hwregs, 0x440,0x44000000);
328           VIA_OUT(hwregs, 0x440,0x45080C04);
329           VIA_OUT(hwregs, 0x440,0x46800408);
330           VIA_OUT(hwregs, 0x440,0x50000000);
331           VIA_OUT(hwregs, 0x440,0x51000000);
332           VIA_OUT(hwregs, 0x440,0x52000000);
333           VIA_OUT(hwregs, 0x440,0x53000000);
334 
335      }
336 
337      VIA_OUT(hwregs, 0x43C,0x00fe0000);
338      VIA_OUT(hwregs, 0x440,0x08000001);
339      VIA_OUT(hwregs, 0x440,0x0A000183);
340      VIA_OUT(hwregs, 0x440,0x0B00019F);
341      VIA_OUT(hwregs, 0x440,0x0C00018B);
342      VIA_OUT(hwregs, 0x440,0x0D00019B);
343      VIA_OUT(hwregs, 0x440,0x0E000000);
344      VIA_OUT(hwregs, 0x440,0x0F000000);
345      VIA_OUT(hwregs, 0x440,0x10000000);
346      VIA_OUT(hwregs, 0x440,0x11000000);
347      VIA_OUT(hwregs, 0x440,0x20000000);
348 }
349 
350 /** */
351 
uc_after_set_var(void * drv,void * dev)352 static void uc_after_set_var(void* drv, void* dev)
353 {
354      UcDriverData* ucdrv = (UcDriverData*) drv;
355 
356      VGA_OUT8(ucdrv->hwregs, 0x3c4, 0x1a);
357      // Clear bit 6 in extended VGA register 0x1a to prevent system lockup.
358      VGA_OUT8(ucdrv->hwregs, 0x3c5, VGA_IN8(ucdrv->hwregs, 0x3c5) & 0xbf);
359      // Set bit 2, it might make a difference.
360      VGA_OUT8(ucdrv->hwregs, 0x3c5, VGA_IN8(ucdrv->hwregs, 0x3c5) | 0x4);
361 
362      VIA_OUT(ucdrv->hwregs, VIA_REG_CURSOR_MODE, VIA_IN(ucdrv->hwregs, VIA_REG_CURSOR_MODE) & 0xFFFFFFFE);
363 }
364 
365 /** Wait until the engine is idle. */
366 
uc_engine_sync(void * drv,void * dev)367 static DFBResult uc_engine_sync(void* drv, void* dev)
368 {
369      UcDriverData* ucdrv = (UcDriverData*) drv;
370      UcDeviceData* ucdev = (UcDeviceData*) dev;
371 
372      int loop = 0;
373 
374 /*    printf("Entering uc_engine_sync(), status is 0x%08x\n",
375         VIA_IN(ucdrv->hwregs, VIA_REG_STATUS));
376 */
377 
378      while ((VIA_IN(ucdrv->hwregs, VIA_REG_STATUS) & 0xfffeffff) != 0x00020000) {
379           if (++loop > MAXLOOP) {
380                D_ERROR("DirectFB/Unichrome: Timeout waiting for idle engine!\n");
381                break;
382 
383                /* FIXME: return DFB_TIMEOUT and implement EngineReset! */
384           }
385      }
386 
387      /* printf("Leaving uc_engine_sync(), status is 0x%08x, "
388          "waiting for %d (0x%x) cycles.\n",
389          VIA_IN(ucdrv->hwregs, VIA_REG_STATUS), loop, loop);
390       */
391 
392      ucdev->idle_waitcycles += loop;
393      ucdev->must_wait = 0;
394 
395      return DFB_OK;
396 }
397 
398 
399 // DirectFB interfacing functions --------------------------------------------
400 
driver_probe(CoreGraphicsDevice * device)401 static int driver_probe(CoreGraphicsDevice *device)
402 {
403      struct stat s;
404 
405      switch (dfb_gfxcard_get_accelerator( device )) {
406           case FB_ACCEL_VIA_UNICHROME:
407                return 1;
408      }
409 
410      return stat(UNICHROME_DEVICE, &s) + 1;
411 }
412 
driver_get_info(CoreGraphicsDevice * device,GraphicsDriverInfo * info)413 static void driver_get_info(CoreGraphicsDevice* device,
414                             GraphicsDriverInfo* info)
415 {
416      // Fill in driver info structure.
417 
418      snprintf(info->name,
419               DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH,
420               "VIA UniChrome Driver");
421 
422      snprintf(info->vendor,
423               DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH,
424               "-");
425 
426      snprintf(info->url,
427               DFB_GRAPHICS_DRIVER_INFO_URL_LENGTH,
428               "http://www.directfb.org");
429 
430      snprintf(info->license,
431               DFB_GRAPHICS_DRIVER_INFO_LICENSE_LENGTH,
432               "LGPL");
433 
434      info->version.major = 0;
435      info->version.minor = 4;
436 
437      info->driver_data_size = sizeof (UcDriverData);
438      info->device_data_size = sizeof (UcDeviceData);
439 }
440 
uc_probe_fbdev(UcDriverData * ucdrv)441 static void uc_probe_fbdev(UcDriverData *ucdrv)
442 {
443      struct fb_flip flip;
444      FBDev *dfb_fbdev = dfb_system_data();
445      flip.device = VIAFB_FLIP_NOP;
446      if (ioctl(dfb_fbdev->fd, FBIO_FLIPONVSYNC, &flip) == 0)
447           ucdrv->canfliponvsync = true;
448      else
449           ucdrv->canfliponvsync = false;
450 }
451 
driver_init_driver(CoreGraphicsDevice * device,GraphicsDeviceFuncs * funcs,void * driver_data,void * device_data,CoreDFB * core)452 static DFBResult driver_init_driver(CoreGraphicsDevice* device,
453                                     GraphicsDeviceFuncs* funcs,
454                                     void* driver_data,
455                                     void* device_data,
456                                     CoreDFB *core)
457 {
458      UcDriverData *ucdrv = (UcDriverData*) driver_data;
459 
460      //printf("Entering %s\n", __PRETTY_FUNCTION__);
461 
462      ucdrv->file = -1;
463      ucdrv->pool = dfb_core_shmpool( core );
464 
465      ucdrv->hwregs = dfb_gfxcard_map_mmio( device, 0, 0 );
466      if (!ucdrv->hwregs) {
467           int fd;
468 
469           fd = open(UNICHROME_DEVICE, O_RDWR | O_SYNC, 0);
470           if (fd < 0) {
471               D_ERROR("DirectFB/Unichrome: Could not access %s. "
472                         "Is the ucio module installed?\n", UNICHROME_DEVICE);
473                return DFB_IO;
474           }
475 
476           ucdrv->file = fd;
477 
478           ucdrv->hwregs = mmap(NULL, 0x1000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
479           if (ucdrv->hwregs == MAP_FAILED)
480                return DFB_IO;
481      }
482 
483      // Get hardware id and revision.
484      uc_probe_pci(ucdrv);
485 
486      // Check framebuffer device capabilities
487      uc_probe_fbdev(ucdrv);
488 
489      /* FIXME: this belongs to device_data! */
490      ucdrv->fifo = uc_fifo_create(ucdrv->pool, UC_FIFO_SIZE);
491      if (!ucdrv->fifo)
492           return D_OOSHM();
493 
494      uc_after_set_var(driver_data, device_data);
495 
496      // Driver specific initialization
497 
498      funcs->CheckState        = uc_check_state;
499      funcs->SetState          = uc_set_state;
500      funcs->EngineSync        = uc_engine_sync;
501      funcs->EmitCommands      = uc_emit_commands;
502      funcs->FlushTextureCache = uc_flush_texture_cache;
503      funcs->AfterSetVar       = uc_after_set_var;
504 
505      funcs->FillRectangle     = uc_fill_rectangle;
506      funcs->DrawRectangle     = uc_draw_rectangle;
507      funcs->DrawLine          = uc_draw_line;
508      funcs->FillTriangle      = uc_fill_triangle;
509      funcs->Blit              = uc_blit;
510      funcs->StretchBlit       = uc_stretch_blit;
511      funcs->TextureTriangles  = uc_texture_triangles;
512 
513      ucdrv->ovl = NULL;
514 
515      /* install primary layer hooks */
516      dfb_layers_hook_primary( device, driver_data, &ucPrimaryFuncs,
517                               &ucOldPrimaryFuncs, &ucOldPrimaryDriverData );
518 
519      dfb_layers_register( dfb_screens_at(DSCID_PRIMARY),
520                           driver_data, &ucOverlayFuncs );
521      dfb_layers_register( dfb_screens_at(DSCID_PRIMARY),
522                           driver_data, &ucSubpictureFuncs );
523 
524      return DFB_OK;
525 }
526 
driver_init_device(CoreGraphicsDevice * device,GraphicsDeviceInfo * device_info,void * driver_data,void * device_data)527 static DFBResult driver_init_device(CoreGraphicsDevice* device,
528                                     GraphicsDeviceInfo* device_info,
529                                     void* driver_data,
530                                     void* device_data)
531 {
532      UcDriverData *ucdrv = (UcDriverData*) driver_data;
533      UcDeviceData *ucdev = (UcDeviceData*) device_data;
534 
535      //printf("Entering %s\n", __PRETTY_FUNCTION__);
536 
537      if (ucdrv->name != NULL) {
538           snprintf(device_info->name,
539                    DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "%s", ucdrv->name);
540      }
541      else {
542           snprintf(device_info->name,
543                    DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH, "UniChrome");
544      }
545      snprintf(device_info->vendor,
546               DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH, "VIA/S3G");
547 
548      device_info->caps.flags = CCF_CLIPPING;
549      device_info->caps.accel =
550      UC_DRAWING_FUNCTIONS_2D | UC_DRAWING_FUNCTIONS_3D |
551      UC_BLITTING_FUNCTIONS_2D | UC_BLITTING_FUNCTIONS_3D;
552 
553      device_info->caps.drawing  = UC_DRAWING_FLAGS_2D | UC_DRAWING_FLAGS_3D;
554      device_info->caps.blitting = UC_BLITTING_FLAGS_2D | UC_BLITTING_FLAGS_3D;
555 
556      device_info->limits.surface_byteoffset_alignment = 32;
557      device_info->limits.surface_pixelpitch_alignment = 32;
558 
559      ucdev->pitch = 0;
560      ucdev->draw_rop2d = VIA_ROP_P;
561      ucdev->draw_rop3d = HC_HROP_P;
562      ucdev->color = 0;
563      ucdev->bflags = 0;
564 
565      ucdev->must_wait = 0;
566      ucdev->cmd_waitcycles = 0;
567      ucdev->idle_waitcycles = 0;
568 
569      uc_init_2d_engine(device, ucdev, ucdrv, false); // VQ disabled - can't make it work.
570      uc_init_3d_engine(ucdrv->hwregs, ucdrv->hwrev, 1);
571 
572      return DFB_OK;
573 }
574 
driver_close_device(CoreGraphicsDevice * device,void * driver_data,void * device_data)575 static void driver_close_device(CoreGraphicsDevice *device,
576                                 void *driver_data, void *device_data)
577 {
578      UcDriverData* ucdrv = (UcDriverData*) driver_data;
579      UcDeviceData* ucdev = (UcDeviceData*) device_data;
580 
581      // uc_dump_vq(ucdev);
582 
583      uc_engine_sync(driver_data, device_data);
584      uc_init_2d_engine(device, ucdev, ucdrv, false);
585 }
586 
driver_close_driver(CoreGraphicsDevice * device,void * driver_data)587 static void driver_close_driver(CoreGraphicsDevice* device, void* driver_data)
588 {
589      UcDriverData* ucdrv = (UcDriverData*) driver_data;
590 
591      if (ucdrv->fifo)
592           uc_fifo_destroy( ucdrv->pool, ucdrv->fifo );
593 
594      if (ucdrv->file != -1)
595           close( ucdrv->file );
596 }
597