1 /*
2  * Copyright 2007 Nouveau Project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 
27 #include "nouveau_private.h"
28 
29 #if NOUVEAU_DRM_HEADER_PATCHLEVEL != 12
30 #error nouveau_drm.h does not match expected patchlevel, update libdrm.
31 #endif
32 
33 int
nouveau_device_open_existing(struct nouveau_device ** dev,int close,int fd,drm_context_t ctx)34 nouveau_device_open_existing(struct nouveau_device **dev, int close,
35 			     int fd, drm_context_t ctx)
36 {
37 	struct nouveau_device_priv *nvdev;
38 	drmVersionPtr ver;
39 	uint64_t value;
40 	int ret;
41 
42 	if (!dev || *dev)
43 	    return -EINVAL;
44 
45 	ver = drmGetVersion(fd);
46 	if (!ver || ver->version_patchlevel != NOUVEAU_DRM_HEADER_PATCHLEVEL)
47 		return -EINVAL;
48 	drmFreeVersion(ver);
49 
50 	nvdev = calloc(1, sizeof(*nvdev));
51 	if (!nvdev)
52 	    return -ENOMEM;
53 	nvdev->fd = fd;
54 	nvdev->ctx = ctx;
55 	nvdev->needs_close = close;
56 
57 	ret = drmCommandNone(nvdev->fd, DRM_NOUVEAU_CARD_INIT);
58 	if (ret) {
59 		nouveau_device_close((void *)&nvdev);
60 		return ret;
61 	}
62 
63 	ret = nouveau_device_get_param(&nvdev->base,
64 				       NOUVEAU_GETPARAM_MM_ENABLED, &value);
65 	if (ret) {
66 		nouveau_device_close((void *)&nvdev);
67 		return ret;
68 	}
69 	nvdev->mm_enabled = value;
70 
71 	ret = nouveau_device_get_param(&nvdev->base,
72 				       NOUVEAU_GETPARAM_VM_VRAM_BASE, &value);
73 	if (ret) {
74 		nouveau_device_close((void *)&nvdev);
75 		return ret;
76 	}
77 	nvdev->base.vm_vram_base = value;
78 
79 	ret = nouveau_device_get_param(&nvdev->base,
80 				       NOUVEAU_GETPARAM_FB_SIZE, &value);
81 	if (ret) {
82 		nouveau_device_close((void *)&nvdev);
83 		return ret;
84 	}
85 	nvdev->vram_aper_size = value;
86 
87 	ret = nouveau_device_get_param(&nvdev->base,
88 				       NOUVEAU_GETPARAM_AGP_SIZE, &value);
89 	if (ret) {
90 		nouveau_device_close((void *)&nvdev);
91 		return ret;
92 	}
93 	nvdev->gart_aper_size = value;
94 
95 	ret = nouveau_bo_init(&nvdev->base);
96 	if (ret) {
97 		nouveau_device_close((void *)&nvdev);
98 		return ret;
99 	}
100 
101 	ret = nouveau_device_get_param(&nvdev->base,
102 				       NOUVEAU_GETPARAM_CHIPSET_ID, &value);
103 	if (ret) {
104 		nouveau_device_close((void *)&nvdev);
105 		return ret;
106 	}
107 	nvdev->base.chipset = value;
108 
109 	*dev = &nvdev->base;
110 	return 0;
111 }
112 
113 int
nouveau_device_open(struct nouveau_device ** dev,const char * busid)114 nouveau_device_open(struct nouveau_device **dev, const char *busid)
115 {
116 	drm_context_t ctx;
117 	int fd, ret;
118 
119 	if (!dev || *dev)
120 		return -EINVAL;
121 
122 	fd = drmOpen("nouveau", busid);
123 	if (fd < 0)
124 		return -EINVAL;
125 
126 	ret = drmCreateContext(fd, &ctx);
127 	if (ret) {
128 		drmClose(fd);
129 		return ret;
130 	}
131 
132 	ret = nouveau_device_open_existing(dev, 1, fd, ctx);
133 	if (ret) {
134 	    drmDestroyContext(fd, ctx);
135 	    drmClose(fd);
136 	    return ret;
137 	}
138 
139 	return 0;
140 }
141 
142 void
nouveau_device_close(struct nouveau_device ** dev)143 nouveau_device_close(struct nouveau_device **dev)
144 {
145 	struct nouveau_device_priv *nvdev;
146 
147 	if (!dev || !*dev)
148 		return;
149 	nvdev = nouveau_device(*dev);
150 	*dev = NULL;
151 
152 	nouveau_bo_takedown(&nvdev->base);
153 
154 	if (nvdev->needs_close) {
155 		drmDestroyContext(nvdev->fd, nvdev->ctx);
156 		drmClose(nvdev->fd);
157 	}
158 	free(nvdev);
159 }
160 
161 int
nouveau_device_get_param(struct nouveau_device * dev,uint64_t param,uint64_t * value)162 nouveau_device_get_param(struct nouveau_device *dev,
163 			 uint64_t param, uint64_t *value)
164 {
165 	struct nouveau_device_priv *nvdev = nouveau_device(dev);
166 	struct drm_nouveau_getparam g;
167 	int ret;
168 
169 	if (!nvdev || !value)
170 		return -EINVAL;
171 
172 	g.param = param;
173 	ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GETPARAM,
174 				  &g, sizeof(g));
175 	if (ret)
176 		return ret;
177 
178 	*value = g.value;
179 	return 0;
180 }
181 
182 int
nouveau_device_set_param(struct nouveau_device * dev,uint64_t param,uint64_t value)183 nouveau_device_set_param(struct nouveau_device *dev,
184 			 uint64_t param, uint64_t value)
185 {
186 	struct nouveau_device_priv *nvdev = nouveau_device(dev);
187 	struct drm_nouveau_setparam s;
188 	int ret;
189 
190 	if (!nvdev)
191 		return -EINVAL;
192 
193 	s.param = param;
194 	s.value = value;
195 	ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_SETPARAM,
196 				  &s, sizeof(s));
197 	if (ret)
198 		return ret;
199 
200 	return 0;
201 }
202 
203