xref: /dragonfly/sys/dev/drm/drm_dragonfly.c (revision 279dd846)
1 /*
2  * Copyright (c) 2015 Imre Vadász <imre@vdsz.com>
3  * Copyright (c) 2015 Rimvydas Jasinskas
4  *
5  * DRM Dragonfly-specific helper functions
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that copyright
10  * notice and this permission notice appear in supporting documentation, and
11  * that the name of the copyright holders not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  The copyright holders make no representations
14  * about the suitability of this software for any purpose.  It is provided "as
15  * is" without express or implied warranty.
16  *
17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23  * OF THIS SOFTWARE.
24  */
25 
26 #include <sys/libkern.h>
27 #include <sys/ctype.h>
28 #include <drm/drmP.h>
29 
30 #if 0
31 commit 26a028bf8c7694e64d44f9e2bb8bd0fba47d7519
32 Author: Imre Vadász <imre@vdsz.com>
33 Date:   Tue Jun 2 23:14:52 2015 +0200
34 
35     drm: hack together an implementation of fb_get_options
36 
37     This can be used to set the video mode used for the syscons fb console,
38     a la "video=..." in linux.
39 #endif
40 
41 /*
42  * An implementation of fb_get_options()
43  * This can be used to set the video mode used for the syscons fb console,
44  * a la "video=..." in linux.
45  */
46 int
47 fb_get_options(const char *connector_name, char **option)
48 {
49 	char buf[128], str[1024];
50 	int i;
51 
52 	/*
53 	 * This hack allows us to use drm.video.lvds1="<video-mode>"
54 	 * in loader.conf, where linux would use video=LVDS-1:<video-mode>.
55 	 * e.g. drm.video.lvds1=1024x768 sets the LVDS-1 connector to
56 	 * a 1024x768 video mode in the syscons framebuffer console.
57 	 * See https://wiki.archlinux.org/index.php/Kernel_mode_setting
58 	 * for an explanation of the video mode command line option.
59 	 * (This corresponds to the video= Linux kernel command-line
60 	 * option)
61 	 */
62 	memset(str, 0, sizeof(str));
63 	ksnprintf(buf, sizeof(buf), "drm.video.%s", connector_name);
64 	i = 0;
65 	while (i < strlen(buf)) {
66 		buf[i] = tolower(buf[i]);
67 		if (buf[i] == '-') {
68 			memmove(&buf[i], &buf[i+1], strlen(buf)-i);
69 		} else {
70 			i++;
71 		}
72 	}
73 	kprintf("looking up kenv for \"%s\"\n", buf);
74 	if (kgetenv_string(buf, str, sizeof(str)-1)) {
75 		kprintf("found kenv %s=%s\n", buf, str);
76 		*option = kstrdup(str, M_DRM);
77 		return (0);
78 	} else {
79 		kprintf("didn't find value for kenv %s\n", buf);
80 		return (1);
81 	}
82 }
83 
84 /*
85  * Implement simplified version of kvasnrprintf() for drm needs using
86  * M_DRM and kvsnprintf(). Since it is unclear what string size is
87  * optimal thus use of an actual length.
88  */
89 char *drm_vasprintf(int flags, const char *format, __va_list ap)
90 {
91 	char *str;
92 	size_t size;
93 	__va_list aq;
94 
95 	__va_copy(aq, ap);
96 	size = kvsnprintf(NULL, 0, format, aq);
97 	__va_end(aq);
98 
99 	str = kmalloc(size+1, M_DRM, flags);
100 	if (str == NULL)
101 		return NULL;
102 
103 	kvsnprintf(str, size+1, format, ap);
104 
105 	return str;
106 }
107 
108 /* mimic ksnrprintf(), return pointer to char* and match drm api */
109 char *drm_asprintf(int flags, const char *format, ...)
110 {
111 	char *str;
112 	__va_list ap;
113 
114 	__va_start(ap, format);
115 	str = drm_vasprintf(flags, format, ap);
116 	__va_end(ap);
117 
118 	return str;
119 }
120 
121 /*
122  * XXX pci glue logic helpers
123  * Should be done in drm_pci_init(), pending drm update.
124  * Assumes static runtime data.
125  * Only for usage in *_driver_[un]load()
126  */
127 
128 static void drm_fill_pdev(struct device *dev, struct pci_dev *pdev)
129 {
130 	pdev->dev = dev;
131 	pdev->vendor = pci_get_vendor(dev);
132 	pdev->device = pci_get_device(dev);
133 	pdev->subsystem_vendor = pci_get_subvendor(dev);
134 	pdev->subsystem_device = pci_get_subdevice(dev);
135 }
136 
137 void drm_init_pdev(struct device *dev, struct pci_dev **pdev)
138 {
139 	BUG_ON(*pdev != NULL);
140 
141 	*pdev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
142 	drm_fill_pdev(dev, *pdev);
143 
144 	(*pdev)->bus = kzalloc(sizeof(struct pci_bus), GFP_KERNEL);
145 	(*pdev)->bus->self = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
146 
147 	drm_fill_pdev(device_get_parent(dev), (*pdev)->bus->self);
148 	(*pdev)->bus->number = pci_get_bus(dev);
149 }
150 
151 void drm_fini_pdev(struct pci_dev **pdev)
152 {
153 	kfree((*pdev)->bus->self);
154 	kfree((*pdev)->bus);
155 
156 	kfree(*pdev);
157 }
158