linux/drivers/media/i2c/ccs/ccs-data.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
   2/*
   3 * CCS static data binary parser library
   4 *
   5 * Copyright 2019--2020 Intel Corporation
   6 */
   7
   8#include <linux/device.h>
   9#include <linux/errno.h>
  10#include <linux/limits.h>
  11#include <linux/mm.h>
  12#include <linux/slab.h>
  13
  14#include "ccs-data-defs.h"
  15
  16struct bin_container {
  17        void *base;
  18        void *now;
  19        void *end;
  20        size_t size;
  21};
  22
  23static void *bin_alloc(struct bin_container *bin, size_t len)
  24{
  25        void *ptr;
  26
  27        len = ALIGN(len, 8);
  28
  29        if (bin->end - bin->now < len)
  30                return NULL;
  31
  32        ptr = bin->now;
  33        bin->now += len;
  34
  35        return ptr;
  36}
  37
  38static void bin_reserve(struct bin_container *bin, size_t len)
  39{
  40        bin->size += ALIGN(len, 8);
  41}
  42
  43static int bin_backing_alloc(struct bin_container *bin)
  44{
  45        bin->base = bin->now = kvzalloc(bin->size, GFP_KERNEL);
  46        if (!bin->base)
  47                return -ENOMEM;
  48
  49        bin->end = bin->base + bin->size;
  50
  51        return 0;
  52}
  53
  54#define is_contained(var, endp)                         \
  55        (sizeof(*var) <= (endp) - (void *)(var))
  56#define has_headroom(ptr, headroom, endp)       \
  57        ((headroom) <= (endp) - (void *)(ptr))
  58#define is_contained_with_headroom(var, headroom, endp)         \
  59        (sizeof(*var) + (headroom) <= (endp) - (void *)(var))
  60
  61static int
  62ccs_data_parse_length_specifier(const struct __ccs_data_length_specifier *__len,
  63                                size_t *__hlen, size_t *__plen,
  64                                const void *endp)
  65{
  66        size_t hlen, plen;
  67
  68        if (!is_contained(__len, endp))
  69                return -ENODATA;
  70
  71        switch (__len->length >> CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) {
  72        case CCS_DATA_LENGTH_SPECIFIER_1:
  73                hlen = sizeof(*__len);
  74                plen = __len->length &
  75                        ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1);
  76                break;
  77        case CCS_DATA_LENGTH_SPECIFIER_2: {
  78                struct __ccs_data_length_specifier2 *__len2 = (void *)__len;
  79
  80                if (!is_contained(__len2, endp))
  81                        return -ENODATA;
  82
  83                hlen = sizeof(*__len2);
  84                plen = ((size_t)
  85                        (__len2->length[0] &
  86                         ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
  87                        << 8) + __len2->length[1];
  88                break;
  89        }
  90        case CCS_DATA_LENGTH_SPECIFIER_3: {
  91                struct __ccs_data_length_specifier3 *__len3 = (void *)__len;
  92
  93                if (!is_contained(__len3, endp))
  94                        return -ENODATA;
  95
  96                hlen = sizeof(*__len3);
  97                plen = ((size_t)
  98                        (__len3->length[0] &
  99                         ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
 100                        << 16) + (__len3->length[0] << 8) + __len3->length[1];
 101                break;
 102        }
 103        default:
 104                return -EINVAL;
 105        }
 106
 107        if (!has_headroom(__len, hlen + plen, endp))
 108                return -ENODATA;
 109
 110        *__hlen = hlen;
 111        *__plen = plen;
 112
 113        return 0;
 114}
 115
 116static u8
 117ccs_data_parse_format_version(const struct __ccs_data_block *block)
 118{
 119        return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT;
 120}
 121
 122static u8 ccs_data_parse_block_id(const struct __ccs_data_block *block,
 123                                       bool is_first)
 124{
 125        if (!is_first)
 126                return block->id;
 127
 128        return block->id & ((1 << CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT) - 1);
 129}
 130
 131static int ccs_data_parse_version(struct bin_container *bin,
 132                                  struct ccs_data_container *ccsdata,
 133                                  const void *payload, const void *endp)
 134{
 135        const struct __ccs_data_block_version *v = payload;
 136        struct ccs_data_block_version *vv;
 137
 138        if (v + 1 != endp)
 139                return -ENODATA;
 140
 141        if (!bin->base) {
 142                bin_reserve(bin, sizeof(*ccsdata->version));
 143                return 0;
 144        }
 145
 146        ccsdata->version = bin_alloc(bin, sizeof(*ccsdata->version));
 147        if (!ccsdata->version)
 148                return -ENOMEM;
 149
 150        vv = ccsdata->version;
 151        vv->version_major = ((u16)v->static_data_version_major[0] << 8) +
 152                v->static_data_version_major[1];
 153        vv->version_minor = ((u16)v->static_data_version_minor[0] << 8) +
 154                v->static_data_version_minor[1];
 155        vv->date_year =  ((u16)v->year[0] << 8) + v->year[1];
 156        vv->date_month = v->month;
 157        vv->date_day = v->day;
 158
 159        return 0;
 160}
 161
 162static void print_ccs_data_version(struct device *dev,
 163                                   struct ccs_data_block_version *v)
 164{
 165        dev_dbg(dev,
 166                "static data version %4.4x.%4.4x, date %4.4u-%2.2u-%2.2u\n",
 167                v->version_major, v->version_minor,
 168                v->date_year, v->date_month, v->date_day);
 169}
 170
 171static int ccs_data_block_parse_header(const struct __ccs_data_block *block,
 172                                       bool is_first, unsigned int *__block_id,
 173                                       const void **payload,
 174                                       const struct __ccs_data_block **next_block,
 175                                       const void *endp, struct device *dev,
 176                                       bool verbose)
 177{
 178        size_t plen, hlen;
 179        u8 block_id;
 180        int rval;
 181
 182        if (!is_contained(block, endp))
 183                return -ENODATA;
 184
 185        rval = ccs_data_parse_length_specifier(&block->length, &hlen, &plen,
 186                                               endp);
 187        if (rval < 0)
 188                return rval;
 189
 190        block_id = ccs_data_parse_block_id(block, is_first);
 191
 192        if (verbose)
 193                dev_dbg(dev,
 194                        "Block ID 0x%2.2x, header length %zu, payload length %zu\n",
 195                        block_id, hlen, plen);
 196
 197        if (!has_headroom(&block->length, hlen + plen, endp))
 198                return -ENODATA;
 199
 200        if (__block_id)
 201                *__block_id = block_id;
 202
 203        if (payload)
 204                *payload = (void *)&block->length + hlen;
 205
 206        if (next_block)
 207                *next_block = (void *)&block->length + hlen + plen;
 208
 209        return 0;
 210}
 211
 212static int ccs_data_parse_regs(struct bin_container *bin,
 213                               struct ccs_reg **__regs,
 214                               size_t *__num_regs, const void *payload,
 215                               const void *endp, struct device *dev)
 216{
 217        struct ccs_reg *regs_base = NULL, *regs = NULL;
 218        size_t num_regs = 0;
 219        u16 addr = 0;
 220
 221        if (bin->base && __regs) {
 222                regs = regs_base = bin_alloc(bin, sizeof(*regs) * *__num_regs);
 223                if (!regs)
 224                        return -ENOMEM;
 225        }
 226
 227        while (payload < endp && num_regs < INT_MAX) {
 228                const struct __ccs_data_block_regs *r = payload;
 229                size_t len;
 230                const void *data;
 231
 232                if (!is_contained(r, endp))
 233                        return -ENODATA;
 234
 235                switch (r->reg_len >> CCS_DATA_BLOCK_REGS_SEL_SHIFT) {
 236                case CCS_DATA_BLOCK_REGS_SEL_REGS:
 237                        addr += r->reg_len & CCS_DATA_BLOCK_REGS_ADDR_MASK;
 238                        len = ((r->reg_len & CCS_DATA_BLOCK_REGS_LEN_MASK)
 239                               >> CCS_DATA_BLOCK_REGS_LEN_SHIFT) + 1;
 240
 241                        if (!is_contained_with_headroom(r, len, endp))
 242                                return -ENODATA;
 243
 244                        data = r + 1;
 245                        break;
 246                case CCS_DATA_BLOCK_REGS_SEL_REGS2: {
 247                        const struct __ccs_data_block_regs2 *r2 = payload;
 248
 249                        if (!is_contained(r2, endp))
 250                                return -ENODATA;
 251
 252                        addr += ((u16)(r2->reg_len &
 253                                       CCS_DATA_BLOCK_REGS_2_ADDR_MASK) << 8)
 254                                + r2->addr;
 255                        len = ((r2->reg_len & CCS_DATA_BLOCK_REGS_2_LEN_MASK)
 256                               >> CCS_DATA_BLOCK_REGS_2_LEN_SHIFT) + 1;
 257
 258                        if (!is_contained_with_headroom(r2, len, endp))
 259                                return -ENODATA;
 260
 261                        data = r2 + 1;
 262                        break;
 263                }
 264                case CCS_DATA_BLOCK_REGS_SEL_REGS3: {
 265                        const struct __ccs_data_block_regs3 *r3 = payload;
 266
 267                        if (!is_contained(r3, endp))
 268                                return -ENODATA;
 269
 270                        addr = ((u16)r3->addr[0] << 8) + r3->addr[1];
 271                        len = (r3->reg_len & CCS_DATA_BLOCK_REGS_3_LEN_MASK) + 1;
 272
 273                        if (!is_contained_with_headroom(r3, len, endp))
 274                                return -ENODATA;
 275
 276                        data = r3 + 1;
 277                        break;
 278                }
 279                default:
 280                        return -EINVAL;
 281                }
 282
 283                num_regs++;
 284
 285                if (!bin->base) {
 286                        bin_reserve(bin, len);
 287                } else if (__regs) {
 288                        if (!regs)
 289                                return -EIO;
 290
 291                        regs->addr = addr;
 292                        regs->len = len;
 293                        regs->value = bin_alloc(bin, len);
 294                        if (!regs->value)
 295                                return -ENOMEM;
 296
 297                        memcpy(regs->value, data, len);
 298                        regs++;
 299                }
 300
 301                addr += len;
 302                payload = data + len;
 303        }
 304
 305        if (!bin->base)
 306                bin_reserve(bin, sizeof(*regs) * num_regs);
 307
 308        if (__num_regs)
 309                *__num_regs = num_regs;
 310
 311        if (bin->base && __regs) {
 312                if (!regs_base)
 313                        return -EIO;
 314
 315                *__regs = regs_base;
 316        }
 317
 318        return 0;
 319}
 320
 321static int ccs_data_parse_reg_rules(struct bin_container *bin,
 322                                    struct ccs_reg **__regs,
 323                                    size_t *__num_regs,
 324                                    const void *payload,
 325                                    const void *endp, struct device *dev)
 326{
 327        int rval;
 328
 329        if (!bin->base)
 330                return ccs_data_parse_regs(bin, NULL, NULL, payload, endp, dev);
 331
 332        rval = ccs_data_parse_regs(bin, NULL, __num_regs, payload, endp, dev);
 333        if (rval)
 334                return rval;
 335
 336        return ccs_data_parse_regs(bin, __regs, __num_regs, payload, endp,
 337                                   dev);
 338}
 339
 340static void assign_ffd_entry(struct ccs_frame_format_desc *desc,
 341                             const struct __ccs_data_block_ffd_entry *ent)
 342{
 343        desc->pixelcode = ent->pixelcode;
 344        desc->value = ((u16)ent->value[0] << 8) + ent->value[1];
 345}
 346
 347static int ccs_data_parse_ffd(struct bin_container *bin,
 348                              struct ccs_frame_format_descs **ffd,
 349                              const void *payload,
 350                              const void *endp, struct device *dev)
 351{
 352        const struct __ccs_data_block_ffd *__ffd = payload;
 353        const struct __ccs_data_block_ffd_entry *__entry;
 354        unsigned int i;
 355
 356        if (!is_contained(__ffd, endp))
 357                return -ENODATA;
 358
 359        if ((void *)__ffd + sizeof(*__ffd) +
 360            ((u32)__ffd->num_column_descs +
 361             (u32)__ffd->num_row_descs) *
 362            sizeof(struct __ccs_data_block_ffd_entry) != endp)
 363                return -ENODATA;
 364
 365        if (!bin->base) {
 366                bin_reserve(bin, sizeof(**ffd));
 367                bin_reserve(bin, __ffd->num_column_descs *
 368                            sizeof(struct ccs_frame_format_desc));
 369                bin_reserve(bin, __ffd->num_row_descs *
 370                            sizeof(struct ccs_frame_format_desc));
 371
 372                return 0;
 373        }
 374
 375        *ffd = bin_alloc(bin, sizeof(**ffd));
 376        if (!*ffd)
 377                return -ENOMEM;
 378
 379        (*ffd)->num_column_descs = __ffd->num_column_descs;
 380        (*ffd)->num_row_descs = __ffd->num_row_descs;
 381        __entry = (void *)(__ffd + 1);
 382
 383        (*ffd)->column_descs = bin_alloc(bin, __ffd->num_column_descs *
 384                                         sizeof(*(*ffd)->column_descs));
 385        if (!(*ffd)->column_descs)
 386                return -ENOMEM;
 387
 388        for (i = 0; i < __ffd->num_column_descs; i++, __entry++)
 389                assign_ffd_entry(&(*ffd)->column_descs[i], __entry);
 390
 391        (*ffd)->row_descs = bin_alloc(bin, __ffd->num_row_descs *
 392                                      sizeof(*(*ffd)->row_descs));
 393        if (!(*ffd)->row_descs)
 394                return -ENOMEM;
 395
 396        for (i = 0; i < __ffd->num_row_descs; i++, __entry++)
 397                assign_ffd_entry(&(*ffd)->row_descs[i], __entry);
 398
 399        if (__entry != endp)
 400                return -EPROTO;
 401
 402        return 0;
 403}
 404
 405static int ccs_data_parse_pdaf_readout(struct bin_container *bin,
 406                                       struct ccs_pdaf_readout **pdaf_readout,
 407                                       const void *payload,
 408                                       const void *endp, struct device *dev)
 409{
 410        const struct __ccs_data_block_pdaf_readout *__pdaf = payload;
 411
 412        if (!is_contained(__pdaf, endp))
 413                return -ENODATA;
 414
 415        if (!bin->base) {
 416                bin_reserve(bin, sizeof(**pdaf_readout));
 417        } else {
 418                *pdaf_readout = bin_alloc(bin, sizeof(**pdaf_readout));
 419                if (!*pdaf_readout)
 420                        return -ENOMEM;
 421
 422                (*pdaf_readout)->pdaf_readout_info_order =
 423                        __pdaf->pdaf_readout_info_order;
 424        }
 425
 426        return ccs_data_parse_ffd(bin, !bin->base ? NULL : &(*pdaf_readout)->ffd,
 427                                  __pdaf + 1, endp, dev);
 428}
 429
 430static int ccs_data_parse_rules(struct bin_container *bin,
 431                                struct ccs_rule **__rules,
 432                                size_t *__num_rules, const void *payload,
 433                                const void *endp, struct device *dev)
 434{
 435        struct ccs_rule *rules_base = NULL, *rules = NULL, *next_rule = NULL;
 436        size_t num_rules = 0;
 437        const void *__next_rule = payload;
 438        int rval;
 439
 440        if (bin->base) {
 441                rules_base = next_rule =
 442                        bin_alloc(bin, sizeof(*rules) * *__num_rules);
 443                if (!rules_base)
 444                        return -ENOMEM;
 445        }
 446
 447        while (__next_rule < endp) {
 448                size_t rule_hlen, rule_plen, rule_plen2;
 449                const u8 *__rule_type;
 450                const void *rule_payload;
 451
 452                /* Size of a single rule */
 453                rval = ccs_data_parse_length_specifier(__next_rule, &rule_hlen,
 454                                                       &rule_plen, endp);
 455
 456                if (rval < 0)
 457                        return rval;
 458
 459                __rule_type = __next_rule + rule_hlen;
 460
 461                if (!is_contained(__rule_type, endp))
 462                        return -ENODATA;
 463
 464                rule_payload = __rule_type + 1;
 465                rule_plen2 = rule_plen - sizeof(*__rule_type);
 466
 467                switch (*__rule_type) {
 468                case CCS_DATA_BLOCK_RULE_ID_IF: {
 469                        const struct __ccs_data_block_rule_if *__if_rules =
 470                                rule_payload;
 471                        const size_t __num_if_rules =
 472                                rule_plen2 / sizeof(*__if_rules);
 473                        struct ccs_if_rule *if_rule;
 474
 475                        if (!has_headroom(__if_rules,
 476                                          sizeof(*__if_rules) * __num_if_rules,
 477                                          rule_payload + rule_plen2))
 478                                return -ENODATA;
 479
 480                        /* Also check there is no extra data */
 481                        if (__if_rules + __num_if_rules !=
 482                            rule_payload + rule_plen2)
 483                                return -EINVAL;
 484
 485                        if (!bin->base) {
 486                                bin_reserve(bin,
 487                                            sizeof(*if_rule) *
 488                                            __num_if_rules);
 489                                num_rules++;
 490                        } else {
 491                                unsigned int i;
 492
 493                                if (!next_rule)
 494                                        return -EIO;
 495
 496                                rules = next_rule;
 497                                next_rule++;
 498
 499                                if_rule = bin_alloc(bin,
 500                                                    sizeof(*if_rule) *
 501                                                    __num_if_rules);
 502                                if (!if_rule)
 503                                        return -ENOMEM;
 504
 505                                for (i = 0; i < __num_if_rules; i++) {
 506                                        if_rule[i].addr =
 507                                                ((u16)__if_rules[i].addr[0]
 508                                                 << 8) +
 509                                                __if_rules[i].addr[1];
 510                                        if_rule[i].value = __if_rules[i].value;
 511                                        if_rule[i].mask = __if_rules[i].mask;
 512                                }
 513
 514                                rules->if_rules = if_rule;
 515                                rules->num_if_rules = __num_if_rules;
 516                        }
 517                        break;
 518                }
 519                case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS:
 520                        rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs,
 521                                                        &rules->num_read_only_regs,
 522                                                        rule_payload,
 523                                                        rule_payload + rule_plen2,
 524                                                        dev);
 525                        if (rval)
 526                                return rval;
 527                        break;
 528                case CCS_DATA_BLOCK_RULE_ID_FFD:
 529                        rval = ccs_data_parse_ffd(bin, &rules->frame_format,
 530                                                  rule_payload,
 531                                                  rule_payload + rule_plen2,
 532                                                  dev);
 533                        if (rval)
 534                                return rval;
 535                        break;
 536                case CCS_DATA_BLOCK_RULE_ID_MSR:
 537                        rval = ccs_data_parse_reg_rules(bin,
 538                                                        &rules->manufacturer_regs,
 539                                                        &rules->num_manufacturer_regs,
 540                                                        rule_payload,
 541                                                        rule_payload + rule_plen2,
 542                                                        dev);
 543                        if (rval)
 544                                return rval;
 545                        break;
 546                case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT:
 547                        rval = ccs_data_parse_pdaf_readout(bin,
 548                                                           &rules->pdaf_readout,
 549                                                           rule_payload,
 550                                                           rule_payload + rule_plen2,
 551                                                           dev);
 552                        if (rval)
 553                                return rval;
 554                        break;
 555                default:
 556                        dev_dbg(dev,
 557                                "Don't know how to handle rule type %u!\n",
 558                                *__rule_type);
 559                        return -EINVAL;
 560                }
 561                __next_rule = __next_rule + rule_hlen + rule_plen;
 562        }
 563
 564        if (!bin->base) {
 565                bin_reserve(bin, sizeof(*rules) * num_rules);
 566                *__num_rules = num_rules;
 567        } else {
 568                if (!rules_base)
 569                        return -EIO;
 570
 571                *__rules = rules_base;
 572        }
 573
 574        return 0;
 575}
 576
 577static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_loc **pdaf,
 578                               const void *payload, const void *endp,
 579                               struct device *dev)
 580{
 581        const struct __ccs_data_block_pdaf_pix_loc *__pdaf = payload;
 582        const struct __ccs_data_block_pdaf_pix_loc_block_desc_group *__bdesc_group;
 583        const struct __ccs_data_block_pdaf_pix_loc_pixel_desc *__pixel_desc;
 584        unsigned int i;
 585        u16 num_block_desc_groups;
 586        u8 max_block_type_id = 0;
 587        const u8 *__num_pixel_descs;
 588
 589        if (!is_contained(__pdaf, endp))
 590                return -ENODATA;
 591
 592        if (bin->base) {
 593                *pdaf = bin_alloc(bin, sizeof(**pdaf));
 594                if (!*pdaf)
 595                        return -ENOMEM;
 596        } else {
 597                bin_reserve(bin, sizeof(**pdaf));
 598        }
 599
 600        num_block_desc_groups =
 601                ((u16)__pdaf->num_block_desc_groups[0] << 8) +
 602                __pdaf->num_block_desc_groups[1];
 603
 604        if (bin->base) {
 605                (*pdaf)->main_offset_x =
 606                        ((u16)__pdaf->main_offset_x[0] << 8) +
 607                        __pdaf->main_offset_x[1];
 608                (*pdaf)->main_offset_y =
 609                        ((u16)__pdaf->main_offset_y[0] << 8) +
 610                        __pdaf->main_offset_y[1];
 611                (*pdaf)->global_pdaf_type = __pdaf->global_pdaf_type;
 612                (*pdaf)->block_width = __pdaf->block_width;
 613                (*pdaf)->block_height = __pdaf->block_height;
 614                (*pdaf)->num_block_desc_groups = num_block_desc_groups;
 615        }
 616
 617        __bdesc_group = (const void *)(__pdaf + 1);
 618
 619        if (bin->base) {
 620                (*pdaf)->block_desc_groups =
 621                        bin_alloc(bin,
 622                                  sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
 623                                  num_block_desc_groups);
 624                if (!(*pdaf)->block_desc_groups)
 625                        return -ENOMEM;
 626        } else {
 627                bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
 628                            num_block_desc_groups);
 629        }
 630
 631        for (i = 0; i < num_block_desc_groups; i++) {
 632                const struct __ccs_data_block_pdaf_pix_loc_block_desc *__bdesc;
 633                u16 num_block_descs;
 634                unsigned int j;
 635
 636                if (!is_contained(__bdesc_group, endp))
 637                        return -ENODATA;
 638
 639                num_block_descs =
 640                        ((u16)__bdesc_group->num_block_descs[0] << 8) +
 641                        __bdesc_group->num_block_descs[1];
 642
 643                if (bin->base) {
 644                        (*pdaf)->block_desc_groups[i].repeat_y =
 645                                __bdesc_group->repeat_y;
 646                        (*pdaf)->block_desc_groups[i].num_block_descs =
 647                                num_block_descs;
 648                }
 649
 650                __bdesc = (const void *)(__bdesc_group + 1);
 651
 652                if (bin->base) {
 653                        (*pdaf)->block_desc_groups[i].block_descs =
 654                                bin_alloc(bin,
 655                                          sizeof(struct ccs_pdaf_pix_loc_block_desc) *
 656                                          num_block_descs);
 657                        if (!(*pdaf)->block_desc_groups[i].block_descs)
 658                                return -ENOMEM;
 659                } else {
 660                        bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc) *
 661                                    num_block_descs);
 662                }
 663
 664                for (j = 0; j < num_block_descs; j++, __bdesc++) {
 665                        struct ccs_pdaf_pix_loc_block_desc *bdesc;
 666
 667                        if (!is_contained(__bdesc, endp))
 668                                return -ENODATA;
 669
 670                        if (max_block_type_id <= __bdesc->block_type_id)
 671                                max_block_type_id = __bdesc->block_type_id + 1;
 672
 673                        if (!bin->base)
 674                                continue;
 675
 676                        bdesc = &(*pdaf)->block_desc_groups[i].block_descs[j];
 677
 678                        bdesc->repeat_x = ((u16)__bdesc->repeat_x[0] << 8)
 679                                + __bdesc->repeat_x[1];
 680
 681                        if (__bdesc->block_type_id >= num_block_descs)
 682                                return -EINVAL;
 683
 684                        bdesc->block_type_id = __bdesc->block_type_id;
 685                }
 686
 687                __bdesc_group = (const void *)__bdesc;
 688        }
 689
 690        __num_pixel_descs = (const void *)__bdesc_group;
 691
 692        if (bin->base) {
 693                (*pdaf)->pixel_desc_groups =
 694                        bin_alloc(bin,
 695                                  sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
 696                                  max_block_type_id);
 697                if (!(*pdaf)->pixel_desc_groups)
 698                        return -ENOMEM;
 699                (*pdaf)->num_pixel_desc_grups = max_block_type_id;
 700        } else {
 701                bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
 702                            max_block_type_id);
 703        }
 704
 705        for (i = 0; i < max_block_type_id; i++) {
 706                struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup = NULL;
 707                unsigned int j;
 708
 709                if (!is_contained(__num_pixel_descs, endp))
 710                        return -ENODATA;
 711
 712                if (bin->base) {
 713                        pdgroup = &(*pdaf)->pixel_desc_groups[i];
 714                        pdgroup->descs =
 715                                bin_alloc(bin,
 716                                          sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
 717                                          *__num_pixel_descs);
 718                        if (!pdgroup->descs)
 719                                return -ENOMEM;
 720                        pdgroup->num_descs = *__num_pixel_descs;
 721                } else {
 722                        bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
 723                                    *__num_pixel_descs);
 724                }
 725
 726                __pixel_desc = (const void *)(__num_pixel_descs + 1);
 727
 728                for (j = 0; j < *__num_pixel_descs; j++, __pixel_desc++) {
 729                        struct ccs_pdaf_pix_loc_pixel_desc *pdesc;
 730
 731                        if (!is_contained(__pixel_desc, endp))
 732                                return -ENODATA;
 733
 734                        if (!bin->base)
 735                                continue;
 736
 737                        if (!pdgroup)
 738                                return -EIO;
 739
 740                        pdesc = &pdgroup->descs[j];
 741                        pdesc->pixel_type = __pixel_desc->pixel_type;
 742                        pdesc->small_offset_x = __pixel_desc->small_offset_x;
 743                        pdesc->small_offset_y = __pixel_desc->small_offset_y;
 744                }
 745
 746                __num_pixel_descs = (const void *)(__pixel_desc + 1);
 747        }
 748
 749        return 0;
 750}
 751
 752static int ccs_data_parse_license(struct bin_container *bin,
 753                                  char **__license,
 754                                  size_t *__license_length,
 755                                  const void *payload, const void *endp)
 756{
 757        size_t size = endp - payload;
 758        char *license;
 759
 760        if (!bin->base) {
 761                bin_reserve(bin, size);
 762                return 0;
 763        }
 764
 765        license = bin_alloc(bin, size);
 766        if (!license)
 767                return -ENOMEM;
 768
 769        memcpy(license, payload, size);
 770
 771        *__license = license;
 772        *__license_length = size;
 773
 774        return 0;
 775}
 776
 777static int ccs_data_parse_end(bool *end, const void *payload, const void *endp,
 778                              struct device *dev)
 779{
 780        const struct __ccs_data_block_end *__end = payload;
 781
 782        if (__end + 1 != endp) {
 783                dev_dbg(dev, "Invalid end block length %u\n",
 784                        (unsigned int)(endp - payload));
 785                return -ENODATA;
 786        }
 787
 788        *end = true;
 789
 790        return 0;
 791}
 792
 793static int __ccs_data_parse(struct bin_container *bin,
 794                            struct ccs_data_container *ccsdata,
 795                            const void *data, size_t len, struct device *dev,
 796                            bool verbose)
 797{
 798        const struct __ccs_data_block *block = data;
 799        const struct __ccs_data_block *endp = data + len;
 800        unsigned int version;
 801        bool is_first = true;
 802        int rval;
 803
 804        version = ccs_data_parse_format_version(block);
 805        if (version != CCS_STATIC_DATA_VERSION) {
 806                dev_dbg(dev, "Don't know how to handle version %u\n", version);
 807                return -EINVAL;
 808        }
 809
 810        if (verbose)
 811                dev_dbg(dev, "Parsing CCS static data version %u\n", version);
 812
 813        if (!bin->base)
 814                *ccsdata = (struct ccs_data_container){ 0 };
 815
 816        while (block < endp) {
 817                const struct __ccs_data_block *next_block;
 818                unsigned int block_id;
 819                const void *payload;
 820
 821                rval = ccs_data_block_parse_header(block, is_first, &block_id,
 822                                                   &payload, &next_block, endp,
 823                                                   dev,
 824                                                   bin->base ? false : verbose);
 825
 826                if (rval < 0)
 827                        return rval;
 828
 829                switch (block_id) {
 830                case CCS_DATA_BLOCK_ID_DUMMY:
 831                        break;
 832                case CCS_DATA_BLOCK_ID_DATA_VERSION:
 833                        rval = ccs_data_parse_version(bin, ccsdata, payload,
 834                                                      next_block);
 835                        if (rval < 0)
 836                                return rval;
 837                        break;
 838                case CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS:
 839                        rval = ccs_data_parse_regs(
 840                                bin, &ccsdata->sensor_read_only_regs,
 841                                &ccsdata->num_sensor_read_only_regs, payload,
 842                                next_block, dev);
 843                        if (rval < 0)
 844                                return rval;
 845                        break;
 846                case CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS:
 847                        rval = ccs_data_parse_regs(
 848                                bin, &ccsdata->sensor_manufacturer_regs,
 849                                &ccsdata->num_sensor_manufacturer_regs, payload,
 850                                next_block, dev);
 851                        if (rval < 0)
 852                                return rval;
 853                        break;
 854                case CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS:
 855                        rval = ccs_data_parse_regs(
 856                                bin, &ccsdata->module_read_only_regs,
 857                                &ccsdata->num_module_read_only_regs, payload,
 858                                next_block, dev);
 859                        if (rval < 0)
 860                                return rval;
 861                        break;
 862                case CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS:
 863                        rval = ccs_data_parse_regs(
 864                                bin, &ccsdata->module_manufacturer_regs,
 865                                &ccsdata->num_module_manufacturer_regs, payload,
 866                                next_block, dev);
 867                        if (rval < 0)
 868                                return rval;
 869                        break;
 870                case CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION:
 871                        rval = ccs_data_parse_pdaf(bin, &ccsdata->sensor_pdaf,
 872                                                   payload, next_block, dev);
 873                        if (rval < 0)
 874                                return rval;
 875                        break;
 876                case CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION:
 877                        rval = ccs_data_parse_pdaf(bin, &ccsdata->module_pdaf,
 878                                                   payload, next_block, dev);
 879                        if (rval < 0)
 880                                return rval;
 881                        break;
 882                case CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK:
 883                        rval = ccs_data_parse_rules(
 884                                bin, &ccsdata->sensor_rules,
 885                                &ccsdata->num_sensor_rules, payload, next_block,
 886                                dev);
 887                        if (rval < 0)
 888                                return rval;
 889                        break;
 890                case CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK:
 891                        rval = ccs_data_parse_rules(
 892                                bin, &ccsdata->module_rules,
 893                                &ccsdata->num_module_rules, payload, next_block,
 894                                dev);
 895                        if (rval < 0)
 896                                return rval;
 897                        break;
 898                case CCS_DATA_BLOCK_ID_LICENSE:
 899                        rval = ccs_data_parse_license(bin, &ccsdata->license,
 900                                                      &ccsdata->license_length,
 901                                                      payload, next_block);
 902                        if (rval < 0)
 903                                return rval;
 904                        break;
 905                case CCS_DATA_BLOCK_ID_END:
 906                        rval = ccs_data_parse_end(&ccsdata->end, payload,
 907                                                  next_block, dev);
 908                        if (rval < 0)
 909                                return rval;
 910                        break;
 911                default:
 912                        dev_dbg(dev, "WARNING: not handling block ID 0x%2.2x\n",
 913                                block_id);
 914                }
 915
 916                block = next_block;
 917                is_first = false;
 918        }
 919
 920        return 0;
 921}
 922
 923/**
 924 * ccs_data_parse - Parse a CCS static data file into a usable in-memory
 925 *                  data structure
 926 * @ccsdata:    CCS static data in-memory data structure
 927 * @data:       CCS static data binary
 928 * @len:        Length of @data
 929 * @dev:        Device the data is related to (used for printing debug messages)
 930 * @verbose:    Whether to be verbose or not
 931 */
 932int ccs_data_parse(struct ccs_data_container *ccsdata, const void *data,
 933                   size_t len, struct device *dev, bool verbose)
 934{
 935        struct bin_container bin = { 0 };
 936        int rval;
 937
 938        rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, verbose);
 939        if (rval)
 940                return rval;
 941
 942        rval = bin_backing_alloc(&bin);
 943        if (rval)
 944                return rval;
 945
 946        rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, false);
 947        if (rval)
 948                goto out_free;
 949
 950        if (verbose && ccsdata->version)
 951                print_ccs_data_version(dev, ccsdata->version);
 952
 953        if (bin.now != bin.end) {
 954                rval = -EPROTO;
 955                dev_dbg(dev, "parsing mismatch; base %p; now %p; end %p\n",
 956                        bin.base, bin.now, bin.end);
 957                goto out_free;
 958        }
 959
 960        ccsdata->backing = bin.base;
 961
 962        return 0;
 963
 964out_free:
 965        kvfree(bin.base);
 966
 967        return rval;
 968}
 969
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.