/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0: * * Copyright (C) 2005 Dell Inc. * by Michael Brown * Licensed under the Open Software License version 2.1 * * Alternatively, you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. */ #define LIBSMBIOS_C_SOURCE // Include compat.h first, then system headers, then public, then private #include "smbios_c/compat.h" // system //#include //#include // public #include "smbios_c/obj/cmos.h" #include "smbios_c/cmos.h" #include "smbios_c/types.h" // private #include "token_impl.h" __hidden int update_checksum(const struct cmos_access_obj *c, bool do_update, void *userdata) { int retval = -1; struct checksum_details *data = (struct checksum_details *)userdata; fnprintf(" BEGIN: start 0x%x end 0x%x location 0x%x indexPort 0x%x\n", data->start, data->end, data->csumloc, data->indexPort); u16 wordRetval = data->csum_fn(c, data->start, data->end, data->indexPort, data->dataPort); const u8 *csum = (const u8 *)(&wordRetval); fnprintf(" calculated 0x%x\n", wordRetval); u32 actualcsum = 0; for( unsigned int i=0; icsumlen; ++i ) { u8 byte; int ret = cmos_obj_read_byte(c, &byte, data->indexPort, data->dataPort, data->csumloc+i); if (ret) goto out; actualcsum = (actualcsum << 8) | byte; } fnprintf(" actual 0x%x (len %d)\n", actualcsum, data->csumlen); #if 0 u8 byteC = byteChecksum(c, data->start, data->end, data->indexPort, data->dataPort); u16 C = wordChecksum(c, data->start, data->end, data->indexPort, data->dataPort); u16 Cn = wordChecksum_n(c, data->start, data->end, data->indexPort, data->dataPort); u16 Crc = wordCrc(c, data->start, data->end, data->indexPort, data->dataPort); fnprintf(" byte(%x) wordcsum(%x) wordcsum_n(%x) wordCrc(%x)\n", byteC, C, Cn, Crc); #endif if(do_update && actualcsum != wordRetval) { // write new checksum fnprintf("REWRITE CSUM\n"); for( unsigned int i=0; icsumlen; ++i ) { int ret = cmos_obj_write_byte(c, data->indexPort, data->dataPort, data->csumloc+i, csum[data->csumlen -i -1]); if (ret) goto out; } // re-run callbacks since we may have written checksum in middle of another checksumed area cmos_obj_run_callbacks(c, do_update); } retval = 1; if (actualcsum != wordRetval) goto out; retval = 0; out: fnprintf("END\n"); return retval; } __hidden u16 byteChecksum(const struct cmos_access_obj *c, u32 start, u32 end, u32 indexPort, u32 dataPort ) { u8 running_checksum=0; u8 byte; for( u32 i = start; i <= end; i++) { if(cmos_obj_read_byte(c, &byte, indexPort, dataPort, i )) goto out; running_checksum += byte; } out: return running_checksum; } __hidden u16 wordChecksum(const struct cmos_access_obj *c, u32 start, u32 end, u32 indexPort, u32 dataPort) { u16 running_checksum=0; u8 byte; for( u32 i = start; i <= end; i++) { if(cmos_obj_read_byte(c, &byte, indexPort, dataPort, i )) goto out; running_checksum += byte; } out: return running_checksum; } __hidden u16 wordChecksum_n(const struct cmos_access_obj *c, u32 start, u32 end, u32 indexPort, u32 dataPort) { return (~wordChecksum(c, start, end, indexPort, dataPort)) + 1; } __hidden u16 wordCrc(const struct cmos_access_obj *c, u32 start, u32 end, u32 indexPort, u32 dataPort ) { u16 running_crc=0; u8 byte; for( u32 i = start; i <= end; i++) { if(cmos_obj_read_byte(c, &byte, indexPort, dataPort, i )) goto out; running_crc ^= byte; for( int j=0; j<7; j++ ) { u16 temp = running_crc & 0x0001; running_crc >>= 1; if( temp != 0 ) { running_crc |= 0x8000; running_crc ^= 0xA001; } } } out: return running_crc; }