feat: a better boot command line parser
[lunaix-os.git] / lunaix-os / hal / gfxa / gfxm.c
1 #include <lunaix/compiler.h>
2 #include <lunaix/mm/valloc.h>
3 #include <lunaix/spike.h>
4 #include <lunaix/status.h>
5
6 #include <hal/gfxm.h>
7
8 #include <klibc/string.h>
9
10 DEFINE_LLIST(gfxa_flat);
11 DECLARE_HASHTABLE(gfxa_idset, 8);
12
13 struct device* gfxa_devcat = NULL;
14 static int id = 0;
15
16 static struct devclass gfxa_class = DEVCLASS(DEV_BUILTIN, DEVFN_DISP, DEV_GFXA);
17
18 static int
19 __gfxa_cmd_router(struct device* dev, u32_t req, va_list args)
20 {
21     struct gfxa* gfxa = (struct gfxa*)dev->underlay;
22     struct disp_profile* disp = &gfxa->disp_info;
23
24     switch (req) {
25         case GFX_ADAPTER_INFO: {
26             struct gfxa_info* info = va_arg(args, struct gfxa_info*);
27             *info =
28               (struct gfxa_info){ .disp_mode = { .w_px = disp->mon.w_px,
29                                                  .h_px = disp->mon.h_px,
30                                                  .freq = disp->mon.freq,
31                                                  .depth = disp->mon.depth } };
32             gfxa->ops.hwioctl(gfxa, req, args);
33             break;
34         };
35         case GFX_ADAPTER_CHMODE: {
36             struct gfxa_mon* mon_info = va_arg(args, struct gfxa_mon*);
37             gfxa->disp_info.mon = *mon_info;
38
39             return gfxa->ops.update_profile(gfxa);
40         };
41         case GFX_ADAPTER_VMCPY:
42         case GFX_ADAPTER_LFBCPY: {
43             void* buf = va_arg(args, void*);
44             off_t off = va_arg(args, off_t);
45             size_t len = va_arg(args, size_t);
46             if (req == GFX_ADAPTER_VMCPY) {
47                 return gfxa->ops.vmcpy(gfxa, buf, off, len);
48             }
49             return gfxa->ops.lfbcpy(gfxa, buf, off, len);
50         };
51         case GFX_ADAPTER_REG_WR:
52         case GFX_ADAPTER_REG_RD: {
53             u32_t* reg_addrmap = va_arg(args, u32_t*);
54             void* reg_val = va_arg(args, void*);
55             size_t reg_count = va_arg(args, size_t);
56
57             if (req == GFX_ADAPTER_LUT_RD) {
58                 return gfxa->ops.rreads(gfxa, reg_addrmap, reg_val, reg_count);
59             }
60             return gfxa->ops.rwrites(gfxa, reg_addrmap, reg_val, reg_count);
61         };
62         case GFX_ADAPTER_LUT_RD: {
63             struct gfxa_clut* clut = va_arg(args, struct gfxa_clut*);
64             if (!clut->val || !clut->len) {
65                 return disp->clut.len;
66             }
67
68             size_t clut_len = MIN(clut->len, disp->clut.len);
69             memcpy(clut->val, disp->clut.val, clut_len * sizeof(color_t));
70             return clut_len;
71         };
72         case GFX_ADAPTER_LUT_WR: {
73             struct gfxa_clut* clut = va_arg(args, struct gfxa_clut*);
74             int err = gfxm_set_lut(gfxa, clut->val, clut->len);
75             if (!err) {
76                 err = gfxa->ops.update_profile(gfxa);
77             }
78             return err;
79         };
80         default:
81             return gfxa->ops.hwioctl(gfxa, req, args);
82     }
83
84     return 0;
85 }
86
87 struct gfxa*
88 gfxm_alloc_adapter(void* hw_obj)
89 {
90     if (unlikely(!gfxa_devcat)) {
91         gfxa_devcat = device_addcat(NULL, "gfx");
92     }
93
94     struct gfxa* gfxa = valloc(sizeof(struct gfxa));
95     struct device* gfxa_dev = device_allocsys(gfxa_devcat, gfxa);
96
97     *gfxa = (struct gfxa){ .dev = gfxa_dev, .hw_obj = hw_obj };
98
99     gfxa_dev->ops.exec_cmd = __gfxa_cmd_router;
100
101     return gfxa;
102 }
103
104 void
105 gfxm_register(struct gfxa* gfxa)
106 {
107     gfxa->id = gfxa_class.variant++;
108
109     llist_append(&gfxa_flat, &gfxa->gfxas);
110     hashtable_hash_in(gfxa_idset, &gfxa->gfxas_id, gfxa->id);
111
112     device_register(gfxa->dev, &gfxa_class, "gfxa%d", gfxa->id);
113 }
114
115 struct gfxa*
116 gfxm_adapter(int gfxa_id)
117 {
118     struct gfxa *pos, *n;
119     hashtable_hash_foreach(gfxa_idset, gfxa_id, pos, n, gfxas_id)
120     {
121         if (pos->id == gfxa_id) {
122             return pos;
123         }
124     }
125
126     return NULL;
127 }
128
129 int
130 gfxm_set_lut(struct gfxa* gfxa, u32_t* lut, size_t len)
131 {
132     // It is generally not feasible for graphic adapter with >256 colors still
133     // using color lut
134     if (unlikely(len > 256)) {
135         return EINVAL;
136     }
137
138     struct disp_profile* disp = &gfxa->disp_info;
139     size_t lutsz = len * sizeof(*lut);
140
141     if (disp->clut.len != len) {
142         vfree_safe(disp->clut.val);
143         disp->clut.val = valloc(lutsz);
144         disp->clut.len = len;
145     }
146
147     memcpy(disp->clut.val, lut, lutsz);
148
149     return 0;
150 }