1/*****************************************************************************\
2 * Tseng Labs ET6000, ET6100 and ET6300 graphics driver for BeOS 5.
3 * Copyright (c) 2003-2004, Evgeniy Vladimirovich Bobkov.
4\*****************************************************************************/
5
6/* standard kernel driver stuff */
7#include <KernelExport.h>
8#include <PCI.h>
9#include <OS.h>
10#include <malloc.h>
11
12/* this is for the standardized portion of the driver API */
13/* currently only one operation is defined: B_GET_ACCELERANT_SIGNATURE */
14#include <graphic_driver.h>
15
16/* this is for sprintf() */
17#include <stdio.h>
18
19/* this is for string compares */
20#include <string.h>
21
22/* The private interface between the accelerant and the kernel driver. */
23#include "DriverInterface.h"
24
25#include "setmode.h"
26#include "acl.h"
27#include "bits.h"
28
29/*****************************************************************************/
30#if DEBUG > 0
31#define ddprintf(a)     dprintf a
32#else
33#define ddprintf(a)
34#endif
35
36#define MAX_DEVICES     8
37
38/* Tell the kernel what revision of the driver API we support */
39int32   api_version = 2;
40
41/*****************************************************************************/
42/* This structure is private to the kernel driver */
43typedef struct {
44    uint32 isOpen; /* a count of how many times the devices has been opened */
45    area_id sharedArea; /* the area shared between the driver and all of the accelerants */
46    ET6000SharedInfo *si; /* a pointer to the shared area, for convenience */
47#if DEBUG > 0
48    uint32 interrupt_count; /* if we're debugging, a count of how many times
49                       the interrupt handler has been called for this device */
50#endif
51    pci_info pcii; /* a convenience copy of the pci info for this device */
52    char name[B_OS_NAME_LENGTH]; /* where we keep the name of the device for publishing and comparing */
53} ET6000DeviceInfo;
54/*****************************************************************************/
55typedef struct {
56#if DEBUG > 0
57    uint32 total_interrupts; /* total number of interrupts seen by our handler */
58#endif
59    uint32 count; /* number of devices actually found */
60    benaphore kernel; /* for serializing opens/closes */
61    char *deviceNames[MAX_DEVICES+1]; /* device name pointer storage */
62    ET6000DeviceInfo di[MAX_DEVICES]; /* device specific stuff */
63} DeviceData;
64/*****************************************************************************/
65static DeviceData *pd;
66/*****************************************************************************/
67/* prototypes for our private functions */
68static status_t et6000OpenHook(const char* name, uint32 flags, void** cookie);
69static status_t et6000CloseHook(void* dev);
70static status_t et6000FreeHook(void* dev);
71static status_t et6000ReadHook(void* dev, off_t pos, void* buf, size_t* len);
72static status_t et6000WriteHook(void* dev, off_t pos, const void* buf, size_t* len);
73static status_t et6000ControlHook(void* dev, uint32 msg, void *buf, size_t len);
74static status_t et6000MapDevice(ET6000DeviceInfo *di);
75static void et6000UnmapDevice(ET6000DeviceInfo *di);
76static void et6000ProbeDevices(void);
77static int32 et6000Interrupt(void *data);
78
79#if DEBUG > 0
80static int et6000dump(int argc, char **argv);
81#endif
82/*****************************************************************************/
83static pci_module_info *pci_bus;
84
85#define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
86
87#define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
88/*****************************************************************************/
89static device_hooks et6000DeviceHooks = {
90    et6000OpenHook,
91    et6000CloseHook,
92    et6000FreeHook,
93    et6000ControlHook,
94    et6000ReadHook,
95    et6000WriteHook,
96    NULL,
97    NULL,
98    NULL,
99    NULL
100};
101/*****************************************************************************/
102#define TSENG_VENDOR_ID 0x100C /* Tseng Labs Inc */
103
104static uint16 et6000DeviceList[] = {
105    0x3208, /* ET6000/ET6100 */
106    0x4702, /* ET6300 */
107    0
108};
109
110static struct {
111    uint16  vendor;
112    uint16  *devices;
113} supportedDevices[] = {
114    {TSENG_VENDOR_ID, et6000DeviceList},
115    {0x0000, NULL}
116};
117/*****************************************************************************/
118/*
119 * Returns B_OK if one is found, otherwise returns
120 * B_ERROR so the driver will be unloaded.
121 */
122status_t init_hardware(void) {
123long pciIndex = 0;
124pci_info pcii;
125bool foundOne = FALSE;
126
127    /* choke if we can't find the PCI bus */
128    if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
129        return B_ERROR;
130
131    /* while there are more pci devices */
132    while ((*pci_bus->get_nth_pci_info)(pciIndex, &pcii) == B_NO_ERROR) {
133        int vendor = 0;
134
135        ddprintf(("ET6000 init_hardware(): checking pci index %ld, device 0x%04x/0x%04x\n", pciIndex, pcii.vendor_id, pcii.device_id));
136        /* if we match a supported vendor */
137        while (supportedDevices[vendor].vendor) {
138            if (supportedDevices[vendor].vendor == pcii.vendor_id) {
139                uint16 *devices = supportedDevices[vendor].devices;
140                /* while there are more supported devices */
141                while (*devices) {
142                    /* if we match a supported device */
143                    if (*devices == pcii.device_id) {
144                        ddprintf(("ET6000: we support this device\n"));
145                        foundOne = TRUE;
146                        goto done;
147                    }
148                    /* next supported device */
149                    devices++;
150                }
151            }
152            vendor++;
153        }
154        /* next pci_info struct, please */
155        pciIndex++;
156    }
157    ddprintf(("ET6000: init_hardware - no supported devices\n"));
158
159done:
160    /* put away the module manager */
161    put_module(B_PCI_MODULE_NAME);
162    return (foundOne ? B_OK : B_ERROR);
163}
164/*****************************************************************************/
165static void et6000ProbeDevices(void) {
166uint32 pciIndex = 0;
167uint32 count = 0;
168ET6000DeviceInfo *di = pd->di;
169
170    /* while there are more pci devices */
171    while ((count < MAX_DEVICES) &&
172        ((*pci_bus->get_nth_pci_info)(pciIndex, &(di->pcii)) == B_NO_ERROR))
173    {
174        int vendor = 0;
175
176        ddprintf(("ET6000: checking pci index %ld, device 0x%04x/0x%04x\n", pciIndex, di->pcii.vendor_id, di->pcii.device_id));
177        /* if we match a supported vendor */
178        while (supportedDevices[vendor].vendor) {
179            if (supportedDevices[vendor].vendor == di->pcii.vendor_id) {
180                uint16 *devices = supportedDevices[vendor].devices;
181                /* while there are more supported devices */
182                while (*devices) {
183                    /* if we match a supported device */
184                    if (*devices == di->pcii.device_id) {
185                        /* publish the device name */
186                        sprintf(di->name, "graphics/%04X_%04X_%02X%02X%02X",
187                                di->pcii.vendor_id, di->pcii.device_id,
188                                di->pcii.bus, di->pcii.device, di->pcii.function);
189                        ddprintf(("ET6000: making /dev/%s\n", di->name));
190                        /* remember the name */
191                        pd->deviceNames[count] = di->name;
192                        /* mark the driver as available for R/W open */
193                        di->isOpen = 0;
194                        /* mark areas as not yet created */
195                        di->sharedArea = -1;
196                        /* mark pointer to shared data as invalid */
197                        di->si = NULL;
198                        /* inc pointer to device info */
199                        di++;
200                        /* inc count */
201                        count++;
202                        /* break out of these while loops */
203                        goto next_device;
204                    }
205                    /* next supported device */
206                    devices++;
207                }
208            }
209            vendor++;
210        }
211next_device:
212        /* next pci_info struct, please */
213        pciIndex++;
214    }
215    /* propagate count */
216    pd->count = count;
217    /* terminate list of device names with a null pointer */
218    pd->deviceNames[pd->count] = NULL;
219    ddprintf(("SKD et6000ProbeDevices: %ld supported devices\n", pd->count));
220}
221/*****************************************************************************/
222status_t init_driver(void) {
223    /* get a handle for the pci bus */
224    if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
225        return B_ERROR;
226
227    /* driver private data */
228    pd = (DeviceData *)calloc(1, sizeof(DeviceData));
229    if (!pd) {
230        put_module(B_PCI_MODULE_NAME);
231        return B_ERROR;
232    }
233    /* initialize the benaphore */
234    INIT_BEN(pd->kernel);
235
236    /* find all of our supported devices */
237    et6000ProbeDevices();
238
239#if DEBUG > 0
240    add_debugger_command("et6000dump", et6000dump, "dump ET6000 kernel driver persistant data");
241#endif
242
243    return B_OK;
244}
245/*****************************************************************************/
246const char **publish_devices(void) {
247    /* return the list of supported devices */
248    return (const char **)pd->deviceNames;
249}
250/*****************************************************************************/
251device_hooks *find_device(const char *name) {
252int index = 0;
253    while (pd->deviceNames[index]) {
254        if (strcmp(name, pd->deviceNames[index]) == 0)
255            return &et6000DeviceHooks;
256        index++;
257    }
258    return NULL;
259}
260/*****************************************************************************/
261void uninit_driver(void) {
262
263#if DEBUG > 0
264    remove_debugger_command("et6000dump", et6000dump);
265#endif
266
267    /* free the driver data */
268    DELETE_BEN(pd->kernel);
269    free(pd);
270    pd = NULL;
271
272    /* put the pci module away */
273    put_module(B_PCI_MODULE_NAME);
274}
275/*****************************************************************************/
276static int32 et6000Interrupt(void *data) {
277int32 handled = B_UNHANDLED_INTERRUPT;
278ET6000DeviceInfo *di = (ET6000DeviceInfo *)data;
279ET6000SharedInfo *si = di->si;
280int32 *flags = &(si->flags);
281
282#if DEBUG > 0
283    pd->total_interrupts++;
284#endif
285
286    /* is someone already handling an interrupt for this device? */
287    if (atomic_or(flags, ET6000_HANDLER_INSTALLED) & ET6000_HANDLER_INSTALLED) {
288#if DEBUG > 0
289        kprintf("ET6000: Already in handler!\n");
290#endif
291        goto exit0;
292    }
293
294    switch (et6000aclInterruptCause(si->mmRegs)) {
295    case ET6000_ACL_INT_CAUSE_NONE:
296        handled = B_UNHANDLED_INTERRUPT;
297        break;
298    case ET6000_ACL_INT_CAUSE_READ:
299        et6000aclReadInterruptClear(si->mmRegs);
300        handled = B_HANDLED_INTERRUPT;
301        break;
302    case ET6000_ACL_INT_CAUSE_WRITE:
303        et6000aclWriteInterruptClear(si->mmRegs);
304        handled = B_HANDLED_INTERRUPT;
305        break;
306    case ET6000_ACL_INT_CAUSE_BOTH: /* Can it be at all? */
307        et6000aclReadInterruptClear(si->mmRegs);
308        et6000aclWriteInterruptClear(si->mmRegs);
309        handled = B_HANDLED_INTERRUPT;
310        break;
311    }
312
313#if DEBUG > 0
314    /* increment the counter for this device */
315    if (handled == B_HANDLED_INTERRUPT)
316        di->interrupt_count++;
317#endif
318
319    /* note that we're not in the handler any more */
320    atomic_and(flags, ~ET6000_HANDLER_INSTALLED);
321
322exit0:
323    return handled;
324}
325/*****************************************************************************/
326static uint32 et6000GetOnboardMemorySize(uint16 pciConfigSpace,
327                                  volatile void *memory)
328{
329uint32 memSize = 0;
330
331    ioSet8(0x3d8, 0x00, 0xa0); /* Set the KEY for color modes */
332    ioSet8(0x3b8, 0x00, 0xa0); /* Set the KEY for monochrome modes */
333
334    switch (ioGet8(0x3C2) & 0x03) {
335    case 0x00: /* onboard memory is of DRAM type */
336        memSize = 1024*1024 * ((ioGet8(pciConfigSpace + 0x45) & 0x03) + 1);
337        break;
338    case 0x03: /* onboard memory is of MDRAM type */
339        memSize = /* number*8 of 32kb banks per channel */
340            ((ioGet8(pciConfigSpace + 0x47) & 0x07) + 1) * 8 * 32*1024;
341        if (ioGet8(pciConfigSpace + 0x45) & 0x04) /* If 2 channels */
342            memSize *= 2;
343        break;
344    default:  /* onboard memory is of unknown type */
345        memSize = 4196*1024; /* Let it be of maximum possible size */
346    }
347
348    /*
349     * This algorithm would fail to recongize 2.25Mb of onboard
350     * memory - it would detect 2.5Mb instead. It needs to be fixed.
351     */
352    if (memSize == 2621440) { /* If 2.5Mb detected */
353        uint8 pci40 = ioGet8(pciConfigSpace+0x40);
354        et6000EnableLinearMemoryMapping(pciConfigSpace);
355
356        /* Check whether the memory beyond 2.25Mb really exists */
357        *(volatile uint32 *)((uint32)memory + 2359296) = 0xaa55aa55;
358        if (*(volatile uint32 *)((uint32)memory + 2359296) != 0xaa55aa55)
359            memSize = 2359296; /* It's 2.25Mb */
360
361        ioSet8(pciConfigSpace+0x40, 0x00, pci40); /* Restore */
362    }
363
364    return memSize;
365}
366/*****************************************************************************/
367static status_t et6000MapDevice(ET6000DeviceInfo *di) {
368char buffer[B_OS_NAME_LENGTH];
369ET6000SharedInfo *si = di->si;
370uint32  tmpUlong;
371pci_info *pcii = &(di->pcii);
372
373    /* Enable memory space access and I/O space access */
374    tmpUlong = get_pci(PCI_command, 4);
375    tmpUlong |= 0x00000003;
376    set_pci(PCI_command, 4, tmpUlong);
377
378    /* Enable ROM decoding */
379    tmpUlong = get_pci(PCI_rom_base, 4);
380    tmpUlong |= 0x00000001;
381    set_pci(PCI_rom_base, 4, tmpUlong);
382
383    /* PCI header base address in I/O space */
384    si->pciConfigSpace = (uint16)di->pcii.u.h0.base_registers[1];
385
386    sprintf(buffer, "%04X_%04X_%02X%02X%02X videomemory",
387        di->pcii.vendor_id, di->pcii.device_id,
388        di->pcii.bus, di->pcii.device, di->pcii.function);
389
390   /*
391    * We map the whole graphics card memory area (which consist of RAM memory
392    * and memory mapped registers) at once. Memory mapped registers must not
393    * be cacheble, so the whole area is mapped with B_MTR_UC (unable caching).
394    * We certainly could map separately the RAM memory with write combining
395    * (B_MTR_WC) and the memory mapped registers with B_MTR_UC.
396    */
397    si->memoryArea = map_physical_memory(buffer,
398        di->pcii.u.h0.base_registers[0],
399        di->pcii.u.h0.base_register_sizes[0],
400        B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_UC,
401        B_READ_AREA + B_WRITE_AREA,
402        &(si->memory));
403
404    si->framebuffer = si->memory;
405    si->mmRegs = (void *)((uint32)si->memory + 0x003fff00);
406    si->emRegs = (void *)((uint32)si->memory + 0x003fe000);
407
408    /* remember the physical addresses */
409    si->physMemory = si->physFramebuffer =
410        (void *) di->pcii.u.h0.base_registers_pci[0];
411
412    si->memSize = et6000GetOnboardMemorySize(si->pciConfigSpace, si->memory);
413
414    /* in any case, return the result */
415    return si->memoryArea;
416}
417/*****************************************************************************/
418static void et6000UnmapDevice(ET6000DeviceInfo *di) {
419ET6000SharedInfo *si = di->si;
420
421    ddprintf(("et6000UnmapDevice(%08lx) begins...\n", (uint32)di));
422    ddprintf((" memoryArea: %ld\n", si->memoryArea));
423
424    if (si->memoryArea >= 0)
425        delete_area(si->memoryArea);
426    si->memoryArea = -1;
427    si->framebuffer = NULL;
428    si->physFramebuffer = NULL;
429    si->memory = NULL;
430    si->physMemory = NULL;
431
432    ddprintf(("et6000UnmapDevice() ends.\n"));
433}
434/*****************************************************************************/
435static status_t et6000OpenHook(const char* name, uint32 flags, void** cookie) {
436int32 index = 0;
437ET6000DeviceInfo *di;
438ET6000SharedInfo *si;
439status_t        result = B_OK;
440char shared_name[B_OS_NAME_LENGTH];
441
442    ddprintf(("SKD et6000OpenHook(%s, %ld, 0x%08lx)\n", name, flags, (uint32)cookie));
443
444    /* find the device name in the list of devices */
445    /* we're never passed a name we didn't publish */
446    while(pd->deviceNames[index] &&
447         (strcmp(name, pd->deviceNames[index]) != 0))
448    {
449        index++;
450    }
451
452    /* for convienience */
453    di = &(pd->di[index]);
454
455    /* make sure no one else has write access to the common data */
456    AQUIRE_BEN(pd->kernel);
457
458    /* if it's already open for writing */
459    if (di->isOpen) {
460        /* mark it open another time */
461        goto mark_as_open;
462    }
463    /* create the shared area */
464    sprintf(shared_name, "%04X_%04X_%02X%02X%02X shared",
465        di->pcii.vendor_id, di->pcii.device_id,
466        di->pcii.bus, di->pcii.device, di->pcii.function);
467    /* create this area with NO user-space read or write permissions, to prevent accidental dammage */
468    di->sharedArea = create_area(shared_name, (void **)&(di->si), B_ANY_KERNEL_ADDRESS, ((sizeof(ET6000SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), B_FULL_LOCK,
469		B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
470    if (di->sharedArea < 0) {
471        /* return the error */
472        result = di->sharedArea;
473        goto done;
474    }
475
476    /* save a few dereferences */
477    si = di->si;
478
479    /* save the vendor and device IDs */
480    si->vendor_id = di->pcii.vendor_id;
481    si->device_id = di->pcii.device_id;
482    si->revision = di->pcii.revision;
483
484    si->pixelClockMax16 = 135000;
485    si->pixelClockMax24 = 135000;
486    if (si->vendor_id == 0x100C) { /* Tseng Labs, Inc. */
487        switch (si->device_id) {
488        case 0x3208:/* ET6000/ET6100 */
489            if (si->revision < 0x70) { /* ET6000 */
490                si->pixelClockMax16 = 135000;
491                si->pixelClockMax24 = 135000;
492            }
493            else { /* ET6100 */
494                si->pixelClockMax16 = 175000;
495                si->pixelClockMax24 = 175000;
496            }
497            break;
498        case 0x4702: /* ET6300 */
499            si->pixelClockMax16 = 220000;
500            si->pixelClockMax24 = 220000;
501            break;
502        }
503    }
504
505    /* map the device */
506    result = et6000MapDevice(di);
507    if (result < 0)
508        goto free_shared;
509    result = B_OK;
510
511    /*
512     * Clear any pending interrupts and disable interrupts. Driver
513     * currently does not use interrupts and unlikely will in future.
514     */
515    et6000aclReadInterruptClear(si->mmRegs);
516    et6000aclWriteInterruptClear(si->mmRegs);
517    et6000aclMasterInterruptDisable(si->mmRegs);
518
519    /* Install the interrupt handler */
520    result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line,
521                                       et6000Interrupt, (void *)di, 0);
522    /* bail if we couldn't install the handler */
523    if (result != B_OK)
524        goto unmap;
525
526mark_as_open:
527    /* mark the device open */
528    di->isOpen++;
529
530    /* send the cookie to the opener */
531    *cookie = di;
532
533    goto done;
534
535unmap:
536    et6000UnmapDevice(di);
537
538free_shared:
539    /* clean up our shared area */
540    delete_area(di->sharedArea);
541    di->sharedArea = -1;
542    di->si = NULL;
543
544done:
545    /* end of critical section */
546    RELEASE_BEN(pd->kernel);
547
548    /* all done, return the status */
549    ddprintf(("et6000OpenHook returning 0x%08lx\n", result));
550
551    return result;
552}
553/*****************************************************************************/
554/*
555 * et6000ReadHook - does nothing, gracefully
556 */
557static status_t et6000ReadHook(void* dev, off_t pos, void* buf, size_t* len)
558{
559    *len = 0;
560    return B_NOT_ALLOWED;
561}
562
563/*****************************************************************************/
564/*
565 * et6000WriteHook - does nothing, gracefully
566 */
567static status_t et6000WriteHook(void* dev, off_t pos, const void* buf, size_t* len)
568{
569    *len = 0;
570    return B_NOT_ALLOWED;
571}
572/*****************************************************************************/
573/*
574 * et6000CloseHook - does nothing, gracefully
575 */
576static status_t et6000CloseHook(void* dev)
577{
578    ddprintf(("SKD et6000CloseHook(%08lx)\n", (uint32)dev));
579    /* we don't do anything on close: there might be dup'd fd */
580    return B_NO_ERROR;
581}
582/*****************************************************************************/
583/*
584 * et6000FreeHook - close down the device
585 */
586static status_t et6000FreeHook(void* dev) {
587ET6000DeviceInfo *di = (ET6000DeviceInfo *)dev;
588ET6000SharedInfo *si = di->si;
589
590    ddprintf(("SKD et6000FreeHook() begins...\n"));
591    /* lock the driver */
592    AQUIRE_BEN(pd->kernel);
593
594    /* if opened multiple times, decrement the open count and exit */
595    if (di->isOpen > 1)
596        goto unlock_and_exit;
597
598    /* Clear any pending interrupts and disable interrupts. */
599    et6000aclReadInterruptClear(si->mmRegs);
600    et6000aclWriteInterruptClear(si->mmRegs);
601    et6000aclMasterInterruptDisable(si->mmRegs);
602
603    /* Remove the interrupt handler */
604    remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, et6000Interrupt, di);
605
606    /* free framebuffer area */
607    et6000UnmapDevice(di);
608
609    /* clean up our shared area */
610    delete_area(di->sharedArea);
611    di->sharedArea = -1;
612    di->si = NULL;
613
614unlock_and_exit:
615    /* mark the device available */
616    di->isOpen--;
617    /* unlock the driver */
618    RELEASE_BEN(pd->kernel);
619    ddprintf(("SKD et6000FreeHook() ends.\n"));
620    /* all done */
621    return B_OK;
622}
623/*****************************************************************************/
624/*
625 * et6000ControlHook - where the real work is done
626 */
627static status_t et6000ControlHook(void* dev, uint32 msg, void *buf, size_t len) {
628ET6000DeviceInfo *di = (ET6000DeviceInfo *)dev;
629status_t result = B_DEV_INVALID_IOCTL;
630
631    /* ddprintf(("ioctl: %d, buf: 0x%08x, len: %d\n", msg, buf, len)); */
632    switch (msg) {
633        /* the only PUBLIC ioctl */
634        case B_GET_ACCELERANT_SIGNATURE: {
635            char *sig = (char *)buf;
636            strcpy(sig, "et6000.accelerant");
637            result = B_OK;
638        } break;
639
640        /* PRIVATE ioctl from here on */
641        case ET6000_GET_PRIVATE_DATA: {
642            ET6000GetPrivateData *gpd = (ET6000GetPrivateData *)buf;
643            if (gpd->magic == ET6000_PRIVATE_DATA_MAGIC) {
644                gpd->sharedInfoArea = di->sharedArea;
645                result = B_OK;
646            }
647        } break;
648
649        case ET6000_GET_PCI: {
650            ET6000GetSetPCI *gsp = (ET6000GetSetPCI *)buf;
651            if (gsp->magic == ET6000_PRIVATE_DATA_MAGIC) {
652                pci_info *pcii = &(di->pcii);
653                gsp->value = get_pci(gsp->offset, gsp->size);
654                result = B_OK;
655            }
656        } break;
657
658        case ET6000_SET_PCI: {
659            ET6000GetSetPCI *gsp = (ET6000GetSetPCI *)buf;
660            if (gsp->magic == ET6000_PRIVATE_DATA_MAGIC) {
661                pci_info *pcii = &(di->pcii);
662                set_pci(gsp->offset, gsp->size, gsp->value);
663                result = B_OK;
664            }
665        } break;
666
667        case ET6000_DEVICE_NAME: {   /* Needed for cloning */
668            ET6000DeviceName *dn = (ET6000DeviceName *)buf;
669            if(dn->magic == ET6000_PRIVATE_DATA_MAGIC) {
670                strncpy(dn->name, di->name, B_OS_NAME_LENGTH);
671                result = B_OK;
672            }
673        } break;
674
675        case ET6000_PROPOSE_DISPLAY_MODE: {
676            ET6000DisplayMode *dm = (ET6000DisplayMode *)buf;
677            if(dm->magic == ET6000_PRIVATE_DATA_MAGIC) {
678                result = et6000ProposeMode(&dm->mode, dm->memSize);
679            }
680        } break;
681
682        case ET6000_SET_DISPLAY_MODE: {
683            ET6000DisplayMode *dm = (ET6000DisplayMode *)buf;
684            if(dm->magic == ET6000_PRIVATE_DATA_MAGIC) {
685                result = et6000SetMode(&dm->mode, dm->pciConfigSpace);
686            }
687        } break;
688    }
689    return result;
690}
691/*****************************************************************************/
692#if DEBUG > 0
693static int et6000dump(int argc, char **argv) {
694int i;
695
696    kprintf("ET6000 Kernel Driver Persistant Data\n\nThere are %ld card(s)\n", pd->count);
697    kprintf("Driver wide benahpore: %ld/%ld\n", pd->kernel.ben, pd->kernel.sem);
698
699    kprintf("Total seen interrupts: %ld\n", pd->total_interrupts);
700    for (i = 0; i < pd->count; i++) {
701        ET6000DeviceInfo *di = &(pd->di[i]);
702        uint16 device_id = di->pcii.device_id;
703        ET6000SharedInfo *si = di->si;
704        kprintf("  device_id: 0x%04x\n", device_id);
705        kprintf("  interrupt count: %ld\n", di->interrupt_count);
706        if (si) {
707            kprintf("  flags:");
708        }
709        kprintf("\n");
710    }
711    return 1; /* the magic number for success */
712}
713#endif
714/*****************************************************************************/
715