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