1/*
2 * Copyright 2022, J��r��me Duval, jerome.duval@gmail.com.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <new>
8#include <stdio.h>
9#include <string.h>
10
11#include <ByteOrder.h>
12#include <bus/PCI.h>
13
14#define DRIVER_NAME "ccp_rng_pci"
15#include "ccp.h"
16
17
18typedef struct {
19	ccp_device_info info;
20	pci_device_module_info* pci;
21	pci_device* device;
22
23	pci_info pciinfo;
24} ccp_pci_sim_info;
25
26
27//	#pragma mark -
28
29
30static status_t
31init_device(device_node* node, void** device_cookie)
32{
33	CALLED();
34	ccp_pci_sim_info* bus = (ccp_pci_sim_info*)calloc(1,
35		sizeof(ccp_pci_sim_info));
36	if (bus == NULL)
37		return B_NO_MEMORY;
38
39	pci_device_module_info* pci;
40	pci_device* device;
41	{
42		device_node* pciParent = gDeviceManager->get_parent_node(node);
43		gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
44			(void**)&device);
45		gDeviceManager->put_node(pciParent);
46	}
47
48	bus->pci = pci;
49	bus->device = device;
50
51	pci_info *pciInfo = &bus->pciinfo;
52	pci->get_pci_info(device, pciInfo);
53
54#define BAR_INDEX 2
55	bus->info.base_addr = pciInfo->u.h0.base_registers[BAR_INDEX];
56	bus->info.map_size = pciInfo->u.h0.base_register_sizes[BAR_INDEX];
57	if ((pciInfo->u.h0.base_register_flags[BAR_INDEX] & PCI_address_type)
58			== PCI_address_type_64) {
59		bus->info.base_addr |= (uint64)pciInfo->u.h0.base_registers[BAR_INDEX + 1] << 32;
60		bus->info.map_size |= (uint64)pciInfo->u.h0.base_register_sizes[BAR_INDEX + 1] << 32;
61	}
62
63	if (bus->info.base_addr == 0) {
64		ERROR("PCI BAR not assigned\n");
65		free(bus);
66		return B_ERROR;
67	}
68
69	// enable bus master and memory
70	uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
71	pcicmd |= PCI_command_master | PCI_command_memory;
72	pci->write_pci_config(device, PCI_command, 2, pcicmd);
73
74	*device_cookie = bus;
75	return B_OK;
76}
77
78
79static void
80uninit_device(void* device_cookie)
81{
82	ccp_pci_sim_info* bus = (ccp_pci_sim_info*)device_cookie;
83	free(bus);
84}
85
86
87static status_t
88register_device(device_node* parent)
89{
90	device_attr attrs[] = {
91		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "CCP PCI"}},
92		{B_DEVICE_BUS, B_STRING_TYPE, {.string = "CCP"}},
93		{B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {.string = CCP_DEVICE_MODULE_NAME}},
94		{}
95	};
96
97	return gDeviceManager->register_node(parent,
98		CCP_PCI_DEVICE_MODULE_NAME, attrs, NULL, NULL);
99}
100
101
102static float
103supports_device(device_node* parent)
104{
105	const char* bus;
106	uint16 vendorID, deviceID;
107
108	// make sure parent is a CCP PCI device node
109	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
110		< B_OK || gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID,
111				&vendorID, false) < B_OK
112		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID,
113				false) < B_OK) {
114		return -1;
115	}
116
117	if (strcmp(bus, "pci") != 0)
118		return 0.0f;
119
120	if (vendorID != 0x1022)
121		return 0.0f;
122
123	switch (deviceID) {
124		case 0x1456:
125		case 0x1468:
126		case 0x1486:
127		case 0x14ca:
128		case 0x1537:
129		case 0x15df:
130		case 0x1649:
131			break;
132		default:
133			return 0.0f;
134	}
135#ifdef TRACE_CCP_RNG
136	TRACE("CCP RNG device found! vendor 0x%04x, device 0x%04x\n", vendorID, deviceID);
137#endif
138	return 0.8f;
139}
140
141
142//	#pragma mark -
143
144
145driver_module_info gCcpPciDevice = {
146	{
147		CCP_PCI_DEVICE_MODULE_NAME,
148		0,
149		NULL
150	},
151
152	supports_device,
153	register_device,
154	init_device,
155	uninit_device,
156	NULL,	// register_child_devices,
157	NULL,	// rescan
158	NULL,	// device removed
159};
160
161