1 /*
2 Copyright 2007-2008 Haiku, Inc. All rights reserved.
3 Distributed under the terms of the MIT license.
4
5 Authors:
6 Gerald Zajac 2007-2008
7 */
8
9 #include <KernelExport.h>
10 #include <PCI.h>
11 #ifdef __HAIKU__
12 #include <drivers/bios.h>
13 #endif // __HAIKU__
14 #include <malloc.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <graphic_driver.h>
18
19 #include "DriverInterface.h"
20
21
22 #undef TRACE
23
24 #ifdef ENABLE_DEBUG_TRACE
25 # define TRACE(x...) dprintf("S3: " x)
26 #else
27 # define TRACE(x...) ;
28 #endif
29
30
31
32 #define SKD_HANDLER_INSTALLED 0x80000000
33 #define MAX_DEVICES 4
34 #define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X"
35
36 int32 api_version = B_CUR_DRIVER_API_VERSION; // revision of driver API we support
37
38 #define VENDOR_ID 0x5333 // S3 vendor ID
39
40
41 struct ChipInfo {
42 uint16 chipID; // PCI device id of the chip
43 uint16 chipType; // assigned chip type identifier
44 const char* chipName; // user recognizable name for chip (must be < 32
45 // chars)
46 };
47
48 // This table maps a PCI device ID to a chip type identifier and the chip name.
49 // Note that the Trio64 and Trio64V+ chips have the same ID, but have a different
50 // revision number. After the revision number is examined, the Trio64V+ will
51 // have a different chip type code and name assigned.
52
53 static const ChipInfo chipTable[] = {
54 { 0x8811, S3_TRIO64, "Trio64" }, // see comment above
55 { 0x8814, S3_TRIO64_UVP, "Trio64 UV+" },
56 { 0x8901, S3_TRIO64_V2, "Trio64 V2/DX/GX" },
57
58 { 0x5631, S3_VIRGE, "Virge" },
59 { 0x883D, S3_VIRGE_VX, "Virge VX" },
60 { 0x8A01, S3_VIRGE_DXGX, "Virge DX/GX" },
61 { 0x8A10, S3_VIRGE_GX2, "Virge GX2" },
62 { 0x8C01, S3_VIRGE_MX, "Virge MX" },
63 { 0x8C03, S3_VIRGE_MXP, "Virge MX+" },
64 { 0x8904, S3_TRIO_3D, "Trio 3D" },
65 { 0x8A13, S3_TRIO_3D_2X, "Trio 3D/2X" },
66
67 { 0x8a20, S3_SAVAGE_3D, "Savage3D" },
68 { 0x8a21, S3_SAVAGE_3D, "Savage3D-MV" },
69 { 0x8a22, S3_SAVAGE4, "Savage4" },
70 { 0x8a25, S3_PROSAVAGE, "ProSavage PM133" },
71 { 0x8a26, S3_PROSAVAGE, "ProSavage KM133" },
72 { 0x8c10, S3_SAVAGE_MX, "Savage/MX-MV" },
73 { 0x8c11, S3_SAVAGE_MX, "Savage/MX" },
74 { 0x8c12, S3_SAVAGE_MX, "Savage/IX-MV" },
75 { 0x8c13, S3_SAVAGE_MX, "Savage/IX" },
76 { 0x8c22, S3_SUPERSAVAGE, "SuperSavage/MX 128" },
77 { 0x8c24, S3_SUPERSAVAGE, "SuperSavage/MX 64" },
78 { 0x8c26, S3_SUPERSAVAGE, "SuperSavage/MX 64C" },
79 { 0x8c2a, S3_SUPERSAVAGE, "SuperSavage/IX 128SDR" },
80 { 0x8c2b, S3_SUPERSAVAGE, "SuperSavage/IX 128DDR" },
81 { 0x8c2c, S3_SUPERSAVAGE, "SuperSavage/IX 64SDR" },
82 { 0x8c2d, S3_SUPERSAVAGE, "SuperSavage/IX 64DDR" },
83 { 0x8c2e, S3_SUPERSAVAGE, "SuperSavage/IXC 64SDR" },
84 { 0x8c2f, S3_SUPERSAVAGE, "SuperSavage/IXC 64DDR" },
85 { 0x8d01, S3_TWISTER, "Twister PN133" },
86 { 0x8d02, S3_TWISTER, "Twister KN133" },
87 { 0x8d03, S3_PROSAVAGE_DDR, "ProSavage DDR" },
88 { 0x8d04, S3_PROSAVAGE_DDR, "ProSavage DDR-K" },
89 { 0x9102, S3_SAVAGE2000, "Savage2000" },
90 { 0, 0, NULL }
91 };
92
93
94 struct DeviceInfo {
95 uint32 openCount; // count of how many times device has been opened
96 int32 flags;
97 area_id sharedArea; // area shared between driver and all accelerants
98 SharedInfo* sharedInfo; // pointer to shared info area memory
99 vuint8* regs; // pointer to memory mapped registers
100 const ChipInfo* pChipInfo; // info about the selected chip
101 pci_info pciInfo; // copy of pci info for this device
102 char name[B_OS_NAME_LENGTH]; // name of device
103 };
104
105
106 static Benaphore gLock;
107 static DeviceInfo gDeviceInfo[MAX_DEVICES];
108 static char* gDeviceNames[MAX_DEVICES + 1];
109 static pci_module_info* gPCI;
110
111
112 // Prototypes for device hook functions.
113
114 static status_t device_open(const char* name, uint32 flags, void** cookie);
115 static status_t device_close(void* dev);
116 static status_t device_free(void* dev);
117 static status_t device_read(void* dev, off_t pos, void* buf, size_t* len);
118 static status_t device_write(void* dev, off_t pos, const void* buf, size_t* len);
119 static status_t device_ioctl(void* dev, uint32 msg, void* buf, size_t len);
120
121 static device_hooks gDeviceHooks =
122 {
123 device_open,
124 device_close,
125 device_free,
126 device_ioctl,
127 device_read,
128 device_write,
129 NULL,
130 NULL,
131 NULL,
132 NULL
133 };
134
135
136
137 static inline uint32
GetPCI(pci_info & info,uint8 offset,uint8 size)138 GetPCI(pci_info& info, uint8 offset, uint8 size)
139 {
140 return gPCI->read_pci_config(info.bus, info.device, info.function, offset, size);
141 }
142
143
144 static inline void
SetPCI(pci_info & info,uint8 offset,uint8 size,uint32 value)145 SetPCI(pci_info& info, uint8 offset, uint8 size, uint32 value)
146 {
147 gPCI->write_pci_config(info.bus, info.device, info.function, offset, size, value);
148 }
149
150
151 // Functions for dealing with Vertical Blanking Interrupts. Currently, I do
152 // not know the commands to handle these operations; thus, these functions
153 // currently do nothing.
154
155 static bool
InterruptIsVBI()156 InterruptIsVBI()
157 {
158 // return true only if a vertical blanking interrupt has occured
159 return false;
160 }
161
162
163 static void
ClearVBI()164 ClearVBI()
165 {
166 }
167
168 static void
EnableVBI()169 EnableVBI()
170 {
171 }
172
173 static void
DisableVBI()174 DisableVBI()
175 {
176 }
177
178
179 static status_t
MapDevice(DeviceInfo & di)180 MapDevice(DeviceInfo& di)
181 {
182 char areaName[B_OS_NAME_LENGTH];
183 SharedInfo& si = *(di.sharedInfo);
184 pci_info& pciInfo = di.pciInfo;
185
186 TRACE("enter MapDevice()\n");
187
188 // Enable memory mapped IO and bus master.
189
190 SetPCI(pciInfo, PCI_command, 2, GetPCI(pciInfo, PCI_command, 2)
191 | PCI_command_io | PCI_command_memory | PCI_command_master);
192
193 const uint32 SavageMmioRegBaseOld = 0x1000000; // 16 MB
194 const uint32 SavageMmioRegBaseNew = 0x0000000;
195 const uint32 SavageMmioRegSize = 0x0080000; // 512 KB reg area size
196
197 const uint32 VirgeMmioRegBase = 0x1000000; // 16 MB
198 const uint32 VirgeMmioRegSize = 0x10000; // 64 KB reg area size
199
200 uint32 videoRamAddr = 0;
201 uint32 videoRamSize = 0;
202 uint32 regsBase = 0;
203 uint32 regAreaSize = 0;
204
205 // Since we do not know at this point the actual size of the video
206 // memory, set it to the largest value that the respective chipset
207 // family can have.
208
209 if (S3_SAVAGE_FAMILY(di.pChipInfo->chipType)) {
210 if (S3_SAVAGE_3D_SERIES(di.pChipInfo->chipType)) {
211 // Savage 3D & Savage MX chips.
212
213 regsBase = pciInfo.u.h0.base_registers[0] + SavageMmioRegBaseOld;
214 regAreaSize = SavageMmioRegSize;
215
216 videoRamAddr = pciInfo.u.h0.base_registers[0];
217 videoRamSize = 16 * 1024 * 1024; // 16 MB is max for 3D series
218 si.videoMemPCI = (void *)(pciInfo.u.h0.base_registers_pci[0]);
219 } else {
220 // All other Savage chips.
221
222 regsBase = pciInfo.u.h0.base_registers[0] + SavageMmioRegBaseNew;
223 regAreaSize = SavageMmioRegSize;
224
225 videoRamAddr = pciInfo.u.h0.base_registers[1];
226 videoRamSize = pciInfo.u.h0.base_register_sizes[1];
227 si.videoMemPCI = (void *)(pciInfo.u.h0.base_registers_pci[1]);
228 }
229 } else {
230 // Trio/Virge chips.
231
232 regsBase = pciInfo.u.h0.base_registers[0] + VirgeMmioRegBase;
233 regAreaSize = VirgeMmioRegSize;
234
235 videoRamAddr = pciInfo.u.h0.base_registers[0];
236 videoRamSize = 8 * 1024 * 1024; // 8 MB is max for Trio/Virge chips
237 si.videoMemPCI = (void *)(pciInfo.u.h0.base_registers_pci[0]);
238 }
239
240 // Map the MMIO register area.
241
242 sprintf(areaName, DEVICE_FORMAT " regs",
243 pciInfo.vendor_id, pciInfo.device_id,
244 pciInfo.bus, pciInfo.device, pciInfo.function);
245
246 si.regsArea = map_physical_memory(areaName, regsBase, regAreaSize,
247 B_ANY_KERNEL_ADDRESS,
248 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA,
249 (void**)(&(di.regs)));
250
251 if (si.regsArea < 0)
252 return si.regsArea; // return error code
253
254 // Map the video memory.
255
256 sprintf(areaName, DEVICE_FORMAT " framebuffer",
257 pciInfo.vendor_id, pciInfo.device_id,
258 pciInfo.bus, pciInfo.device, pciInfo.function);
259
260 si.videoMemArea = map_physical_memory(
261 areaName,
262 videoRamAddr,
263 videoRamSize,
264 B_ANY_KERNEL_BLOCK_ADDRESS | B_WRITE_COMBINING_MEMORY,
265 B_READ_AREA + B_WRITE_AREA,
266 &(si.videoMemAddr));
267
268 if (si.videoMemArea < 0) {
269 // Try to map this time without write combining.
270 si.videoMemArea = map_physical_memory(
271 areaName,
272 videoRamAddr,
273 videoRamSize,
274 B_ANY_KERNEL_BLOCK_ADDRESS,
275 B_READ_AREA + B_WRITE_AREA,
276 &(si.videoMemAddr));
277 }
278
279 TRACE("Video memory, area: %ld, addr: 0x%" B_PRIXADDR "\n",
280 si.videoMemArea, (addr_t)(si.videoMemAddr));
281
282 // If there was an error, delete other areas.
283 if (si.videoMemArea < 0) {
284 delete_area(si.regsArea);
285 si.regsArea = -1;
286 }
287
288 TRACE("leave MapDevice(); result: %ld\n", si.videoMemArea);
289 return si.videoMemArea;
290 }
291
292
293 static void
UnmapDevice(DeviceInfo & di)294 UnmapDevice(DeviceInfo& di)
295 {
296 SharedInfo& si = *(di.sharedInfo);
297
298 TRACE("enter UnmapDevice()\n");
299
300 if (si.regsArea >= 0)
301 delete_area(si.regsArea);
302 if (si.videoMemArea >= 0)
303 delete_area(si.videoMemArea);
304
305 si.regsArea = si.videoMemArea = -1;
306 si.videoMemAddr = NULL;
307 di.regs = NULL;
308
309 TRACE("exit UnmapDevice()\n");
310 }
311
312
313 static int32
InterruptHandler(void * data)314 InterruptHandler(void* data)
315 {
316 int32 handled = B_UNHANDLED_INTERRUPT;
317 DeviceInfo& di = *((DeviceInfo*)data);
318 int32* flags = &(di.flags);
319
320 // Is someone already handling an interrupt for this device?
321 if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED)
322 return B_UNHANDLED_INTERRUPT;
323
324 if (InterruptIsVBI()) { // was interrupt a VBI?
325 ClearVBI(); // clear interrupt
326
327 handled = B_HANDLED_INTERRUPT;
328
329 // Release vertical blanking semaphore.
330 sem_id& sem = di.sharedInfo->vertBlankSem;
331
332 if (sem >= 0) {
333 int32 blocked;
334 if ((get_sem_count(sem, &blocked) == B_OK) && (blocked < 0)) {
335 release_sem_etc(sem, -blocked, B_DO_NOT_RESCHEDULE);
336 handled = B_INVOKE_SCHEDULER;
337 }
338 }
339 }
340
341 atomic_and(flags, ~SKD_HANDLER_INSTALLED); // note we're not in handler anymore
342
343 return handled;
344 }
345
346
347 static void
InitInterruptHandler(DeviceInfo & di)348 InitInterruptHandler(DeviceInfo& di)
349 {
350 SharedInfo& si = *(di.sharedInfo);
351
352 TRACE("enter InitInterruptHandler()\n");
353
354 DisableVBI(); // disable & clear any pending interrupts
355 si.bInterruptAssigned = false; // indicate interrupt not assigned yet
356
357 // Create a semaphore for vertical blank management.
358 si.vertBlankSem = create_sem(0, di.name);
359 if (si.vertBlankSem < 0)
360 return;
361
362 // Change the owner of the semaphores to the calling team (usually the
363 // app_server). This is required because apps can't aquire kernel
364 // semaphores.
365
366 thread_id threadID = find_thread(NULL);
367 thread_info threadInfo;
368 status_t status = get_thread_info(threadID, &threadInfo);
369 if (status == B_OK)
370 status = set_sem_owner(si.vertBlankSem, threadInfo.team);
371
372 // If there is a valid interrupt assigned, set up interrupts.
373
374 if (status == B_OK && di.pciInfo.u.h0.interrupt_pin != 0x00
375 && di.pciInfo.u.h0.interrupt_line != 0xff) {
376 // We have a interrupt line to use.
377
378 status = install_io_interrupt_handler(di.pciInfo.u.h0.interrupt_line,
379 InterruptHandler, (void*)(&di), 0);
380
381 if (status == B_OK)
382 si.bInterruptAssigned = true; // we can use interrupt related functions
383 }
384
385 if (status != B_OK) {
386 // Interrupt does not exist; thus delete semaphore as it won't be used.
387 delete_sem(si.vertBlankSem);
388 si.vertBlankSem = -1;
389 }
390 }
391
392
393 static status_t
InitDevice(DeviceInfo & di)394 InitDevice(DeviceInfo& di)
395 {
396 // Perform initialization and mapping of the device, and return B_OK if
397 // sucessful; else, return error code.
398
399 // Create the area for shared info with NO user-space read or write
400 // permissions, to prevent accidental damage.
401
402 TRACE("enter InitDevice()\n");
403
404 pci_info& pciInfo = di.pciInfo;
405 char sharedName[B_OS_NAME_LENGTH];
406
407 sprintf(sharedName, DEVICE_FORMAT " shared",
408 pciInfo.vendor_id, pciInfo.device_id,
409 pciInfo.bus, pciInfo.device, pciInfo.function);
410
411 di.sharedArea = create_area(sharedName, (void**) &(di.sharedInfo),
412 B_ANY_KERNEL_ADDRESS,
413 ((sizeof(SharedInfo) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)),
414 B_FULL_LOCK,
415 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
416 if (di.sharedArea < 0)
417 return di.sharedArea; // return error code
418
419 SharedInfo& si = *(di.sharedInfo);
420
421 si.vendorID = pciInfo.vendor_id;
422 si.deviceID = pciInfo.device_id;
423 si.revision = pciInfo.revision;
424 si.chipType = di.pChipInfo->chipType;
425 strcpy(si.chipName, di.pChipInfo->chipName);
426
427 // Trio64 and Trio64V+ chips have the same ID but different revision numbers.
428 // Since the Trio64V+ supports MMIO, better performance can be obtained
429 // from it if it is distinguished from the Trio64.
430
431 if (si.chipType == S3_TRIO64 && si.revision & 0x40) {
432 si.chipType = S3_TRIO64_VP;
433 strcpy(si.chipName, "Trio64 V+");
434 }
435
436 status_t status = MapDevice(di);
437 if (status < 0) {
438 delete_area(di.sharedArea);
439 di.sharedArea = -1;
440 di.sharedInfo = NULL;
441 return status; // return error code
442 }
443
444 InitInterruptHandler(di);
445
446 TRACE("Interrupt assigned: %s\n", si.bInterruptAssigned ? "yes" : "no");
447 return B_OK;
448 }
449
450
451 static const ChipInfo*
GetNextSupportedDevice(uint32 & pciIndex,pci_info & pciInfo)452 GetNextSupportedDevice(uint32& pciIndex, pci_info& pciInfo)
453 {
454 // Search the PCI devices for a device that is supported by this driver.
455 // The search starts at the device specified by argument pciIndex, and
456 // continues until a supported device is found or there are no more devices
457 // to examine. Argument pciIndex is incremented after each device is
458 // examined.
459
460 // If a supported device is found, return a pointer to the struct containing
461 // the chip info; else return NULL.
462
463 while (gPCI->get_nth_pci_info(pciIndex, &pciInfo) == B_OK) {
464 if (pciInfo.vendor_id == VENDOR_ID) {
465 // Search the table of supported devices to find a chip/device that
466 // matches device ID of the current PCI device.
467
468 const ChipInfo* pDevice = chipTable;
469
470 while (pDevice->chipID != 0) { // end of table?
471 if (pDevice->chipID == pciInfo.device_id) {
472 pciIndex++;
473 return pDevice; // matching device/chip found
474 }
475
476 pDevice++;
477 }
478 }
479
480 pciIndex++;
481 }
482
483 return NULL; // no supported device found found
484 }
485
486
487
488 #ifdef __HAIKU__
489
490 static status_t
GetEdidFromBIOS(edid1_raw & edidRaw)491 GetEdidFromBIOS(edid1_raw& edidRaw)
492 {
493 // Get the EDID info from the video BIOS, and return B_OK if successful.
494
495 #define ADDRESS_SEGMENT(address) ((addr_t)(address) >> 4)
496 #define ADDRESS_OFFSET(address) ((addr_t)(address) & 0xf)
497
498 bios_module_info* biosModule;
499 status_t status = get_module(B_BIOS_MODULE_NAME, (module_info**)&biosModule);
500 if (status != B_OK) {
501 TRACE("GetEdidFromBIOS(): failed to get BIOS module: 0x%" B_PRIx32 "\n",
502 status);
503 return status;
504 }
505
506 bios_state* state;
507 status = biosModule->prepare(&state);
508 if (status != B_OK) {
509 TRACE("GetEdidFromBIOS(): bios_prepare() failed: 0x%" B_PRIx32 "\n",
510 status);
511 put_module(B_BIOS_MODULE_NAME);
512 return status;
513 }
514
515 bios_regs regs = {};
516 regs.eax = 0x4f15;
517 regs.ebx = 0; // 0 = report DDC service
518 regs.ecx = 0;
519 regs.es = 0;
520 regs.edi = 0;
521
522 status = biosModule->interrupt(state, 0x10, ®s);
523 if (status == B_OK) {
524 // AH contains the error code, and AL determines whether or not the
525 // function is supported.
526 if (regs.eax != 0x4f)
527 status = B_NOT_SUPPORTED;
528
529 // Test if DDC is supported by the monitor.
530 if ((regs.ebx & 3) == 0)
531 status = B_NOT_SUPPORTED;
532 }
533
534 if (status == B_OK) {
535 edid1_raw* edid = (edid1_raw*)biosModule->allocate_mem(state,
536 sizeof(edid1_raw));
537 if (edid == NULL) {
538 status = B_NO_MEMORY;
539 goto out;
540 }
541
542 regs.eax = 0x4f15;
543 regs.ebx = 1; // 1 = read EDID
544 regs.ecx = 0;
545 regs.edx = 0;
546 regs.es = ADDRESS_SEGMENT(edid);
547 regs.edi = ADDRESS_OFFSET(edid);
548
549 status = biosModule->interrupt(state, 0x10, ®s);
550 if (status == B_OK) {
551 if (regs.eax != 0x4f) {
552 status = B_NOT_SUPPORTED;
553 } else {
554 // Copy the EDID info to the caller's location, and compute the
555 // checksum of the EDID info while copying.
556
557 uint8 sum = 0;
558 uint8 allOr = 0;
559 uint8* dest = (uint8*)&edidRaw;
560 uint8* src = (uint8*)edid;
561
562 for (uint32 j = 0; j < sizeof(edidRaw); j++) {
563 sum += *src;
564 allOr |= *src;
565 *dest++ = *src++;
566 }
567
568 if (allOr == 0) {
569 TRACE("GetEdidFromBIOS(); EDID info contains only zeros\n");
570 status = B_ERROR;
571 } else if (sum != 0) {
572 TRACE("GetEdidFromBIOS(); Checksum error in EDID info\n");
573 status = B_ERROR;
574 }
575 }
576 }
577 }
578
579 out:
580 biosModule->finish(state);
581 put_module(B_BIOS_MODULE_NAME);
582
583 TRACE("GetEdidFromBIOS() status: 0x%" B_PRIx32 "\n", status);
584 return status;
585 }
586
587 #endif // __HAIKU__
588
589
590
591 // #pragma mark - Kernel Interface
592
593
594 status_t
init_hardware(void)595 init_hardware(void)
596 {
597 // Return B_OK if a device supported by this driver is found; otherwise,
598 // return B_ERROR so the driver will be unloaded.
599
600 if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI) != B_OK)
601 return B_ERROR; // unable to access PCI bus
602
603 // Check pci devices for a device supported by this driver.
604
605 uint32 pciIndex = 0;
606 pci_info pciInfo;
607 const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, pciInfo);
608
609 TRACE("init_hardware() - %s\n", pDevice == NULL ? "no supported devices" : "device supported");
610
611 put_module(B_PCI_MODULE_NAME); // put away the module manager
612
613 return (pDevice == NULL ? B_ERROR : B_OK);
614 }
615
616
init_driver(void)617 status_t init_driver(void)
618 {
619 // Get handle for the pci bus.
620
621 if (get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI) != B_OK)
622 return B_ERROR;
623
624 status_t status = gLock.Init("S3 driver lock");
625 if (status < B_OK)
626 return status;
627
628 // Get info about all the devices supported by this driver.
629
630 uint32 pciIndex = 0;
631 uint32 count = 0;
632
633 while (count < MAX_DEVICES) {
634 DeviceInfo& di = gDeviceInfo[count];
635
636 const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, di.pciInfo);
637 if (pDevice == NULL)
638 break; // all supported devices have been obtained
639
640 // Compose device name.
641 sprintf(di.name, "graphics/" DEVICE_FORMAT,
642 di.pciInfo.vendor_id, di.pciInfo.device_id,
643 di.pciInfo.bus, di.pciInfo.device, di.pciInfo.function);
644 TRACE("init_driver() match found; name: %s\n", di.name);
645
646 gDeviceNames[count] = di.name;
647 di.openCount = 0; // mark driver as available for R/W open
648 di.sharedArea = -1; // indicate shared area not yet created
649 di.sharedInfo = NULL;
650 di.pChipInfo = pDevice;
651 count++;
652 }
653
654 gDeviceNames[count] = NULL; // terminate list with null pointer
655
656 TRACE("init_driver() %ld supported devices\n", count);
657
658 return B_OK;
659 }
660
661
662 void
uninit_driver(void)663 uninit_driver(void)
664 {
665 // Free the driver data.
666
667 gLock.Delete();
668 put_module(B_PCI_MODULE_NAME); // put the pci module away
669 }
670
671
672 const char**
publish_devices(void)673 publish_devices(void)
674 {
675 return (const char**)gDeviceNames; // return list of supported devices
676 }
677
678
679 device_hooks*
find_device(const char * name)680 find_device(const char* name)
681 {
682 int index = 0;
683 while (gDeviceNames[index] != NULL) {
684 if (strcmp(name, gDeviceNames[index]) == 0)
685 return &gDeviceHooks;
686 index++;
687 }
688
689 return NULL;
690 }
691
692
693
694 // #pragma mark - Device Hooks
695
696
697 static status_t
device_open(const char * name,uint32,void ** cookie)698 device_open(const char* name, uint32 /*flags*/, void** cookie)
699 {
700 status_t status = B_OK;
701
702 TRACE("device_open() - name: %s, cookie: 0x%" B_PRIXADDR "\n", name,
703 (addr_t)cookie);
704
705 // Find the device name in the list of devices.
706
707 int32 index = 0;
708 while (gDeviceNames[index] != NULL && (strcmp(name, gDeviceNames[index]) != 0))
709 index++;
710
711 if (gDeviceNames[index] == NULL)
712 return B_BAD_VALUE; // device name not found in list of devices
713
714 DeviceInfo& di = gDeviceInfo[index];
715
716 gLock.Acquire(); // make sure no one else has write access to common data
717
718 if (di.openCount == 0)
719 status = InitDevice(di);
720
721 gLock.Release();
722
723 if (status == B_OK) {
724 di.openCount++; // mark device open
725 *cookie = &di; // send cookie to opener
726 }
727
728 TRACE("device_open() returning 0x%lx, open count: %ld\n", status, di.openCount);
729 return status;
730 }
731
732
733 static status_t
device_read(void * dev,off_t pos,void * buf,size_t * len)734 device_read(void* dev, off_t pos, void* buf, size_t* len)
735 {
736 // Following 3 lines of code are here to eliminate "unused parameter" warnings.
737 (void)dev;
738 (void)pos;
739 (void)buf;
740
741 *len = 0;
742 return B_NOT_ALLOWED;
743 }
744
745
746 static status_t
device_write(void * dev,off_t pos,const void * buf,size_t * len)747 device_write(void* dev, off_t pos, const void* buf, size_t* len)
748 {
749 // Following 3 lines of code are here to eliminate "unused parameter" warnings.
750 (void)dev;
751 (void)pos;
752 (void)buf;
753
754 *len = 0;
755 return B_NOT_ALLOWED;
756 }
757
758
759 static status_t
device_close(void * dev)760 device_close(void* dev)
761 {
762 (void)dev; // avoid compiler warning for unused arg
763
764 TRACE("device_close()\n");
765 return B_NO_ERROR;
766 }
767
768
769 static status_t
device_free(void * dev)770 device_free(void* dev)
771 {
772 DeviceInfo& di = *((DeviceInfo*)dev);
773 SharedInfo& si = *(di.sharedInfo);
774 pci_info& pciInfo = di.pciInfo;
775
776 TRACE("enter device_free()\n");
777
778 gLock.Acquire(); // lock driver
779
780 // If opened multiple times, merely decrement the open count and exit.
781
782 if (di.openCount <= 1) {
783 DisableVBI(); // disable & clear any pending interrupts
784
785 if (si.bInterruptAssigned) {
786 remove_io_interrupt_handler(pciInfo.u.h0.interrupt_line, InterruptHandler, &di);
787 }
788
789 // Delete the semaphores, ignoring any errors because the owning team may have died.
790 if (si.vertBlankSem >= 0)
791 delete_sem(si.vertBlankSem);
792 si.vertBlankSem = -1;
793
794 UnmapDevice(di); // free regs and frame buffer areas
795
796 delete_area(di.sharedArea);
797 di.sharedArea = -1;
798 di.sharedInfo = NULL;
799 }
800
801 if (di.openCount > 0)
802 di.openCount--; // mark device available
803
804 gLock.Release(); // unlock driver
805
806 TRACE("exit device_free() openCount: %ld\n", di.openCount);
807 return B_OK;
808 }
809
810
811 static status_t
device_ioctl(void * dev,uint32 msg,void * buf,size_t len)812 device_ioctl(void* dev, uint32 msg, void* buf, size_t len)
813 {
814 DeviceInfo& di = *((DeviceInfo*)dev);
815
816 (void)len; // avoid compiler warning for unused arg
817
818 // TRACE("device_ioctl(); ioctl: %lu, buf: 0x%08lx, len: %lu\n", msg, (uint32)buf, len);
819
820 switch (msg) {
821 case B_GET_ACCELERANT_SIGNATURE:
822 strcpy((char*)buf, "s3.accelerant");
823 return B_OK;
824
825 case S3_DEVICE_NAME:
826 strncpy((char*)buf, di.name, B_OS_NAME_LENGTH);
827 ((char*)buf)[B_OS_NAME_LENGTH -1] = '\0';
828 return B_OK;
829
830 case S3_GET_PRIVATE_DATA:
831 {
832 S3GetPrivateData* gpd = (S3GetPrivateData*)buf;
833 if (gpd->magic == S3_PRIVATE_DATA_MAGIC) {
834 gpd->sharedInfoArea = di.sharedArea;
835 return B_OK;
836 }
837 break;
838 }
839
840 case S3_GET_EDID:
841 {
842 #ifdef __HAIKU__
843 S3GetEDID* ged = (S3GetEDID*)buf;
844 if (ged->magic == S3_PRIVATE_DATA_MAGIC) {
845 edid1_raw rawEdid;
846 status_t status = GetEdidFromBIOS(rawEdid);
847 if (status == B_OK)
848 user_memcpy(&ged->rawEdid, &rawEdid, sizeof(rawEdid));
849 return status;
850 }
851 #else
852 return B_UNSUPPORTED;
853 #endif
854 break;
855 }
856
857 case S3_GET_PIO:
858 {
859 S3GetSetPIO* gsp = (S3GetSetPIO*)buf;
860 if (gsp->magic == S3_PRIVATE_DATA_MAGIC) {
861 switch (gsp->size) {
862 case 1:
863 gsp->value = gPCI->read_io_8(gsp->offset);
864 break;
865 case 2:
866 gsp->value = gPCI->read_io_16(gsp->offset);
867 break;
868 case 4:
869 gsp->value = gPCI->read_io_32(gsp->offset);
870 break;
871 default:
872 TRACE("device_ioctl() S3_GET_PIO invalid size: %ld\n", gsp->size);
873 return B_ERROR;
874 }
875 return B_OK;
876 }
877 break;
878 }
879
880 case S3_SET_PIO:
881 {
882 S3GetSetPIO* gsp = (S3GetSetPIO*)buf;
883 if (gsp->magic == S3_PRIVATE_DATA_MAGIC) {
884 switch (gsp->size) {
885 case 1:
886 gPCI->write_io_8(gsp->offset, gsp->value);
887 break;
888 case 2:
889 gPCI->write_io_16(gsp->offset, gsp->value);
890 break;
891 case 4:
892 gPCI->write_io_32(gsp->offset, gsp->value);
893 break;
894 default:
895 TRACE("device_ioctl() S3_SET_PIO invalid size: %ld\n", gsp->size);
896 return B_ERROR;
897 }
898 return B_OK;
899 }
900 break;
901 }
902
903 case S3_RUN_INTERRUPTS:
904 {
905 S3SetBoolState* ri = (S3SetBoolState*)buf;
906 if (ri->magic == S3_PRIVATE_DATA_MAGIC) {
907 if (ri->bEnable)
908 EnableVBI();
909 else
910 DisableVBI();
911 }
912 return B_OK;
913 }
914 }
915
916 return B_DEV_INVALID_IOCTL;
917 }
918