libcdi: +debug function; +FIFOs
[meinos.git] / apps / lib / libcdi / pci.c
blob5c43e23f9d1b347a2d3b33bb4d20bc2419ce3d59
1 /*
2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <cdi/lists.h>
20 #include <cdi/pci.h>
21 #include <cdi/misc.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <stddef.h>
27 #include <dirent.h>
29 struct pci_config {
30 uint16_t vendor_id;
31 uint16_t device_id;
32 uint16_t command;
33 uint16_t status;
34 uint16_t revision_id;
35 uint8_t subclass;
36 uint8_t class;
37 uint8_t cache_line_size;
38 uint8_t latency_timer;
39 uint8_t header_type;
40 uint8_t bist;
41 uint32_t bar[6];
42 uint32_t cardbus_cis_ptr;
43 uint16_t subsystem_vendor_id;
44 uint16_t subsystem_id;
45 uint32_t exp_rom_bar;
46 uint32_t reserved[2];
47 uint8_t interrupt_line;
48 uint8_t interrupt_pin;
49 uint8_t min_grant;
50 uint8_t max_latency;
53 static cdi_list_t pci_devices = NULL;
55 static int cdi_pci_read_config(struct cdi_pci_device *pci) {
56 int ret = 0;
57 char *filename;
58 asprintf(&filename,"dev/pci%d.%d.%d",pci->bus,pci->dev,pci->function);
59 int fh = open(filename,O_RDWR);
60 free(filename);
62 if (fh!=-1) {
63 struct pci_config conf;
64 read(fh,&conf,sizeof(conf));
66 if (conf.header_type==0 || conf.header_type==1) {
67 pci->vendor_id = conf.vendor_id;
68 pci->device_id = conf.device_id;
69 pci->class_id = (conf.class<<8)|conf.subclass;
70 pci->irq = conf.interrupt_line; /// @todo Is that right?
71 pci->resources = cdi_list_create();
73 size_t i;
74 for (i=0;i<6;i++) {
75 if (conf.bar[i]&1) {
76 struct cdi_pci_resource *res = malloc(sizeof(struct cdi_pci_resource));
77 res->start = conf.bar[i]&0xFFFFFFF0;
78 res->type = (conf.bar[i]&1)?CDI_PCI_IOPORTS:CDI_PCI_MEMORY;
79 res->index = i;
80 lseek(fh,offsetof(struct pci_config,bar[i]),SEEK_SET);
81 uint32_t bar_tmp = 0xFFFFFFF0|(conf.bar[i]&1);
82 write(fh,&bar_tmp,4);
83 lseek(fh,offsetof(struct pci_config,bar[i]),SEEK_SET);
84 read(fh,&(res->length),4);
85 res->length = (~res->length|0xF)+1;
86 lseek(fh,offsetof(struct pci_config,bar[i]),SEEK_SET);
87 write(fh,conf.bar+i,4);
88 cdi_list_push(pci->resources,res);
92 else ret = -1;
94 close(fh);
96 else ret = -1;
98 return ret;
101 void cdi_pci_get_all_devices(cdi_list_t list) {
102 if (pci_devices==NULL) {
103 DIR *dir = opendir("/dev");
104 if (dir!=NULL) {
105 struct dirent *ent;
106 do {
107 ent = readdir(dir);
108 if (ent!=NULL) {
109 if (strncmp(ent->d_name,"pci",3)==0) {
110 struct cdi_pci_device *new = malloc(sizeof(struct cdi_pci_device));
111 if (sscanf(ent->d_name,"pci%d.%d.%d",&(new->bus),&(new->dev),&(new->function))==3) {
112 if (cdi_pci_read_config(new)!=-1) cdi_list_push(list,new);
114 else free(new);
117 } while (ent!=NULL);
118 closedir(dir);
123 void cdi_pci_device_destroy(struct cdi_pci_device* device) {
124 struct cdi_pci_resource *res;
126 cdi_pci_free_ioports(device);
127 cdi_pci_free_memory(device);
128 while ((res = cdi_list_pop(device->resources))) free(res);
129 cdi_list_destroy(device->resources);
130 free(device);
133 void cdi_pci_alloc_ioports(struct cdi_pci_device* device) {
134 struct cdi_pci_resource *res;
135 size_t i;
137 for (i=0;(res = cdi_list_get(device->resources,i));i++) {
138 if (res->type==CDI_PCI_IOPORTS) cdi_ioports_alloc(res->start,res->length);
142 void cdi_pci_free_ioports(struct cdi_pci_device* device) {
143 struct cdi_pci_resource *res;
144 size_t i;
146 for (i=0;(res = cdi_list_get(device->resources,i));i++) {
147 if (res->type==CDI_PCI_IOPORTS) cdi_ioports_free(res->start,res->length);
151 void cdi_pci_alloc_memory(struct cdi_pci_device *device) {
152 struct cdi_pci_resource *res;
153 size_t i;
155 for (i=0;(res = cdi_list_get(device->resources,i));i++) {
156 if (res->type==CDI_PCI_MEMORY) res->address = cdi_alloc_phys_addr(res->length,res->start);
160 void cdi_pci_free_memory(struct cdi_pci_device *device) {
161 struct cdi_pci_resource *res;
162 size_t i;
164 for (i=0;(res = cdi_list_get(device->resources,i));i++) {
165 if (res->type==CDI_PCI_MEMORY) cdi_free_phys_addr(res->length,res->start);