Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 77b2555b52a894a2e39a42e43d993df875c46a6a 399 lines 14 kB view raw
1/* $Id: hysdn_boot.c,v 1.4.6.4 2001/09/23 22:24:54 kai Exp $ 2 * 3 * Linux driver for HYSDN cards 4 * specific routines for booting and pof handling 5 * 6 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH 7 * Copyright 1999 by Werner Cornelius (werner@titro.de) 8 * 9 * This software may be used and distributed according to the terms 10 * of the GNU General Public License, incorporated herein by reference. 11 * 12 */ 13 14#include <linux/vmalloc.h> 15#include <linux/slab.h> 16#include <asm/uaccess.h> 17 18#include "hysdn_defs.h" 19#include "hysdn_pof.h" 20 21/********************************/ 22/* defines for pof read handler */ 23/********************************/ 24#define POF_READ_FILE_HEAD 0 25#define POF_READ_TAG_HEAD 1 26#define POF_READ_TAG_DATA 2 27 28/************************************************************/ 29/* definition of boot specific data area. This data is only */ 30/* needed during boot and so allocated dynamically. */ 31/************************************************************/ 32struct boot_data { 33 word Cryptor; /* for use with Decrypt function */ 34 word Nrecs; /* records remaining in file */ 35 uchar pof_state; /* actual state of read handler */ 36 uchar is_crypted; /* card data is crypted */ 37 int BufSize; /* actual number of bytes bufferd */ 38 int last_error; /* last occurred error */ 39 word pof_recid; /* actual pof recid */ 40 ulong pof_reclen; /* total length of pof record data */ 41 ulong pof_recoffset; /* actual offset inside pof record */ 42 union { 43 uchar BootBuf[BOOT_BUF_SIZE]; /* buffer as byte count */ 44 tPofRecHdr PofRecHdr; /* header for actual record/chunk */ 45 tPofFileHdr PofFileHdr; /* header from POF file */ 46 tPofTimeStamp PofTime; /* time information */ 47 } buf; 48}; 49 50/*****************************************************/ 51/* start decryption of successive POF file chuncks. */ 52/* */ 53/* to be called at start of POF file reading, */ 54/* before starting any decryption on any POF record. */ 55/*****************************************************/ 56static void 57StartDecryption(struct boot_data *boot) 58{ 59 boot->Cryptor = CRYPT_STARTTERM; 60} /* StartDecryption */ 61 62 63/***************************************************************/ 64/* decrypt complete BootBuf */ 65/* NOTE: decryption must be applied to all or none boot tags - */ 66/* to HI and LO boot loader and (all) seq tags, because */ 67/* global Cryptor is started for whole POF. */ 68/***************************************************************/ 69static void 70DecryptBuf(struct boot_data *boot, int cnt) 71{ 72 uchar *bufp = boot->buf.BootBuf; 73 74 while (cnt--) { 75 boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0); 76 *bufp++ ^= (uchar) boot->Cryptor; 77 } 78} /* DecryptBuf */ 79 80/********************************************************************************/ 81/* pof_handle_data executes the required actions dependent on the active record */ 82/* id. If successful 0 is returned, a negative value shows an error. */ 83/********************************************************************************/ 84static int 85pof_handle_data(hysdn_card * card, int datlen) 86{ 87 struct boot_data *boot = card->boot; /* pointer to boot specific data */ 88 long l; 89 uchar *imgp; 90 int img_len; 91 92 /* handle the different record types */ 93 switch (boot->pof_recid) { 94 95 case TAG_TIMESTMP: 96 if (card->debug_flags & LOG_POF_RECORD) 97 hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText); 98 break; 99 100 case TAG_CBOOTDTA: 101 DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ 102 case TAG_BOOTDTA: 103 if (card->debug_flags & LOG_POF_RECORD) 104 hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", 105 (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA", 106 datlen, boot->pof_recoffset); 107 108 if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) { 109 boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */ 110 return (boot->last_error); 111 } 112 imgp = boot->buf.BootBuf; /* start of buffer */ 113 img_len = datlen; /* maximum length to transfer */ 114 115 l = POF_BOOT_LOADER_OFF_IN_PAGE - 116 (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1)); 117 if (l > 0) { 118 /* buffer needs to be truncated */ 119 imgp += l; /* advance pointer */ 120 img_len -= l; /* adjust len */ 121 } 122 /* at this point no special handling for data wrapping over buffer */ 123 /* is necessary, because the boot image always will be adjusted to */ 124 /* match a page boundary inside the buffer. */ 125 /* The buffer for the boot image on the card is filled in 2 cycles */ 126 /* first the 1024 hi-words are put in the buffer, then the low 1024 */ 127 /* word are handled in the same way with different offset. */ 128 129 if (img_len > 0) { 130 /* data available for copy */ 131 if ((boot->last_error = 132 card->writebootimg(card, imgp, 133 (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0) 134 return (boot->last_error); 135 } 136 break; /* end of case boot image hi/lo */ 137 138 case TAG_CABSDATA: 139 DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ 140 case TAG_ABSDATA: 141 if (card->debug_flags & LOG_POF_RECORD) 142 hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", 143 (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA", 144 datlen, boot->pof_recoffset); 145 146 if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0)) 147 return (boot->last_error); /* error writing data */ 148 149 if (boot->pof_recoffset + datlen >= boot->pof_reclen) 150 return (card->waitpofready(card)); /* data completely spooled, wait for ready */ 151 152 break; /* end of case boot seq data */ 153 154 default: 155 if (card->debug_flags & LOG_POF_RECORD) 156 hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid, 157 datlen, boot->pof_recoffset); 158 159 break; /* simply skip record */ 160 } /* switch boot->pof_recid */ 161 162 return (0); 163} /* pof_handle_data */ 164 165 166/******************************************************************************/ 167/* pof_write_buffer is called when the buffer has been filled with the needed */ 168/* number of data bytes. The number delivered is additionally supplied for */ 169/* verification. The functions handles the data and returns the needed number */ 170/* of bytes for the next action. If the returned value is 0 or less an error */ 171/* occurred and booting must be aborted. */ 172/******************************************************************************/ 173int 174pof_write_buffer(hysdn_card * card, int datlen) 175{ 176 struct boot_data *boot = card->boot; /* pointer to boot specific data */ 177 178 if (!boot) 179 return (-EFAULT); /* invalid call */ 180 if (boot->last_error < 0) 181 return (boot->last_error); /* repeated error */ 182 183 if (card->debug_flags & LOG_POF_WRITE) 184 hysdn_addlog(card, "POF write: got %d bytes ", datlen); 185 186 switch (boot->pof_state) { 187 case POF_READ_FILE_HEAD: 188 if (card->debug_flags & LOG_POF_WRITE) 189 hysdn_addlog(card, "POF write: checking file header"); 190 191 if (datlen != sizeof(tPofFileHdr)) { 192 boot->last_error = -EPOF_INTERNAL; 193 break; 194 } 195 if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) { 196 boot->last_error = -EPOF_BAD_MAGIC; 197 break; 198 } 199 /* Setup the new state and vars */ 200 boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */ 201 boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ 202 boot->last_error = sizeof(tPofRecHdr); /* new length */ 203 break; 204 205 case POF_READ_TAG_HEAD: 206 if (card->debug_flags & LOG_POF_WRITE) 207 hysdn_addlog(card, "POF write: checking tag header"); 208 209 if (datlen != sizeof(tPofRecHdr)) { 210 boot->last_error = -EPOF_INTERNAL; 211 break; 212 } 213 boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */ 214 boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */ 215 boot->pof_recoffset = 0; /* no starting offset */ 216 217 if (card->debug_flags & LOG_POF_RECORD) 218 hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ", 219 boot->pof_recid, boot->pof_reclen); 220 221 boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */ 222 if (boot->pof_reclen < BOOT_BUF_SIZE) 223 boot->last_error = boot->pof_reclen; /* limit size */ 224 else 225 boot->last_error = BOOT_BUF_SIZE; /* maximum */ 226 227 if (!boot->last_error) { /* no data inside record */ 228 boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ 229 boot->last_error = sizeof(tPofRecHdr); /* new length */ 230 } 231 break; 232 233 case POF_READ_TAG_DATA: 234 if (card->debug_flags & LOG_POF_WRITE) 235 hysdn_addlog(card, "POF write: getting tag data"); 236 237 if (datlen != boot->last_error) { 238 boot->last_error = -EPOF_INTERNAL; 239 break; 240 } 241 if ((boot->last_error = pof_handle_data(card, datlen)) < 0) 242 return (boot->last_error); /* an error occurred */ 243 boot->pof_recoffset += datlen; 244 if (boot->pof_recoffset >= boot->pof_reclen) { 245 boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ 246 boot->last_error = sizeof(tPofRecHdr); /* new length */ 247 } else { 248 if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE) 249 boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */ 250 else 251 boot->last_error = BOOT_BUF_SIZE; /* maximum */ 252 } 253 break; 254 255 default: 256 boot->last_error = -EPOF_INTERNAL; /* unknown state */ 257 break; 258 } /* switch (boot->pof_state) */ 259 260 return (boot->last_error); 261} /* pof_write_buffer */ 262 263 264/*******************************************************************************/ 265/* pof_write_open is called when an open for boot on the cardlog device occurs. */ 266/* The function returns the needed number of bytes for the next operation. If */ 267/* the returned number is less or equal 0 an error specified by this code */ 268/* occurred. Additionally the pointer to the buffer data area is set on success */ 269/*******************************************************************************/ 270int 271pof_write_open(hysdn_card * card, uchar ** bufp) 272{ 273 struct boot_data *boot; /* pointer to boot specific data */ 274 275 if (card->boot) { 276 if (card->debug_flags & LOG_POF_OPEN) 277 hysdn_addlog(card, "POF open: already opened for boot"); 278 return (-ERR_ALREADY_BOOT); /* boot already active */ 279 } 280 /* error no mem available */ 281 if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) { 282 if (card->debug_flags & LOG_MEM_ERR) 283 hysdn_addlog(card, "POF open: unable to allocate mem"); 284 return (-EFAULT); 285 } 286 card->boot = boot; 287 card->state = CARD_STATE_BOOTING; 288 memset(boot, 0, sizeof(struct boot_data)); 289 290 card->stopcard(card); /* first stop the card */ 291 if (card->testram(card)) { 292 if (card->debug_flags & LOG_POF_OPEN) 293 hysdn_addlog(card, "POF open: DPRAM test failure"); 294 boot->last_error = -ERR_BOARD_DPRAM; 295 card->state = CARD_STATE_BOOTERR; /* show boot error */ 296 return (boot->last_error); 297 } 298 boot->BufSize = 0; /* Buffer is empty */ 299 boot->pof_state = POF_READ_FILE_HEAD; /* read file header */ 300 StartDecryption(boot); /* if POF File should be encrypted */ 301 302 if (card->debug_flags & LOG_POF_OPEN) 303 hysdn_addlog(card, "POF open: success"); 304 305 *bufp = boot->buf.BootBuf; /* point to buffer */ 306 return (sizeof(tPofFileHdr)); 307} /* pof_write_open */ 308 309/********************************************************************************/ 310/* pof_write_close is called when an close of boot on the cardlog device occurs. */ 311/* The return value must be 0 if everything has happened as desired. */ 312/********************************************************************************/ 313int 314pof_write_close(hysdn_card * card) 315{ 316 struct boot_data *boot = card->boot; /* pointer to boot specific data */ 317 318 if (!boot) 319 return (-EFAULT); /* invalid call */ 320 321 card->boot = NULL; /* no boot active */ 322 kfree(boot); 323 324 if (card->state == CARD_STATE_RUN) 325 card->set_errlog_state(card, 1); /* activate error log */ 326 327 if (card->debug_flags & LOG_POF_OPEN) 328 hysdn_addlog(card, "POF close: success"); 329 330 return (0); 331} /* pof_write_close */ 332 333/*********************************************************************************/ 334/* EvalSysrTokData checks additional records delivered with the Sysready Message */ 335/* when POF has been booted. A return value of 0 is used if no error occurred. */ 336/*********************************************************************************/ 337int 338EvalSysrTokData(hysdn_card * card, uchar * cp, int len) 339{ 340 u_char *p; 341 u_char crc; 342 343 if (card->debug_flags & LOG_POF_RECORD) 344 hysdn_addlog(card, "SysReady Token data length %d", len); 345 346 if (len < 2) { 347 hysdn_addlog(card, "SysReady Token Data to short"); 348 return (1); 349 } 350 for (p = cp, crc = 0; p < (cp + len - 2); p++) 351 if ((crc & 0x80)) 352 crc = (((u_char) (crc << 1)) + 1) + *p; 353 else 354 crc = ((u_char) (crc << 1)) + *p; 355 crc = ~crc; 356 if (crc != *(cp + len - 1)) { 357 hysdn_addlog(card, "SysReady Token Data invalid CRC"); 358 return (1); 359 } 360 len--; /* don't check CRC byte */ 361 while (len > 0) { 362 363 if (*cp == SYSR_TOK_END) 364 return (0); /* End of Token stream */ 365 366 if (len < (*(cp + 1) + 2)) { 367 hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1)); 368 return (1); 369 } 370 switch (*cp) { 371 case SYSR_TOK_B_CHAN: /* 1 */ 372 if (*(cp + 1) != 1) 373 return (1); /* length invalid */ 374 card->bchans = *(cp + 2); 375 break; 376 377 case SYSR_TOK_FAX_CHAN: /* 2 */ 378 if (*(cp + 1) != 1) 379 return (1); /* length invalid */ 380 card->faxchans = *(cp + 2); 381 break; 382 383 case SYSR_TOK_MAC_ADDR: /* 3 */ 384 if (*(cp + 1) != 6) 385 return (1); /* length invalid */ 386 memcpy(card->mac_addr, cp + 2, 6); 387 break; 388 389 default: 390 hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1)); 391 break; 392 } 393 len -= (*(cp + 1) + 2); /* adjust len */ 394 cp += (*(cp + 1) + 2); /* and pointer */ 395 } 396 397 hysdn_addlog(card, "no end token found"); 398 return (1); 399} /* EvalSysrTokData */