1 //---------------------------------------------------------------------------
2 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
18 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22 // Except as contained in this notice, the name of Dallas Semiconductor
23 // shall not be used except as stated in the Dallas Semiconductor
24 // Branding Policy.
25 //---------------------------------------------------------------------------
26 //
27 // mbEPROM.c - Include memory bank EPROM functions.
28 //
29 // Version: 2.10
30 //
31 
32 // Include Files
33 #include "ownet.h"
34 #include "mbeprom.h"
35 
36 // External functions
37 extern SMALLINT owBlock(int,int,uchar *,int);
38 extern SMALLINT owReadByte(int);
39 extern SMALLINT owWriteByte(int,int);
40 extern void     output_status(int, char *);
41 extern void     msDelay(int);
42 extern void     owSerialNum(int,uchar *,int);
43 extern SMALLINT owAccess(int);
44 extern SMALLINT owWriteByte(int,int);
45 extern void     setcrc16(int,ushort);
46 extern ushort   docrc16(int,ushort);
47 extern void     setcrc8(int,uchar);
48 extern uchar    docrc8(int,uchar);
49 extern SMALLINT owWriteBytePower(int,int);
50 extern SMALLINT owLevel(int,int);
51 extern SMALLINT owProgramByte(int,SMALLINT,int,SMALLINT,SMALLINT,SMALLINT);
52 extern SMALLINT owHasProgramPulse(int);
53 
54 // general command defines
55 #define READ_MEMORY_COMMAND_EPROM      0xF0
56 #define MAIN_READ_PAGE_COMMAND_EPROM   0xA5
57 #define STATUS_READ_PAGE_COMMAND_EPROM 0xAA
58 #define MAIN_WRITE_COMMAND_EPROM       0x0F
59 #define STATUS_WRITE_COMMAND_EPROM     0x55
60 
61 // Local defines
62 #define SIZE_EPROM        2048
63 #define PAGE_LENGTH_EPROM 32
64 
65 // Local functions
66 uchar    writeMemCmd(SMALLINT bank, uchar *SNum);
67 SMALLINT numCRCbytes(SMALLINT bank, uchar *SNum);
68 SMALLINT writeVerify(SMALLINT bank, int portnum, uchar *SNum, int page);
69 SMALLINT crcAfterAdd(SMALLINT bank, uchar *SNum);
70 uchar    readPageWithCRC(SMALLINT bank, uchar *SNum);
71 SMALLINT isRedirectPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page);
72 SMALLINT lockRedirectPage(SMALLINT bank, int portnum, uchar *SNum, int page);
73 SMALLINT getRedirectedPage(SMALLINT bank, int portnum, uchar *SNum, int page);
74 SMALLINT redirectPage(SMALLINT bank, int portnum, uchar *SNum, int page, int newPage);
75 SMALLINT isPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page);
76 SMALLINT lockPage(SMALLINT bank, int portnum, uchar *SNum, int page);
77 SMALLINT redirectOffset(SMALLINT bank, uchar *SNum);
78 
79 // Global variables
80 char *bankDescription_eprom     = "Main Memory";
81 SMALLINT  writeVerification_eprom    = TRUE;
82 SMALLINT  generalPurposeMemory_eprom = TRUE;
83 SMALLINT  readWrite_eprom            = FALSE;
84 SMALLINT  writeOnce_eprom            = TRUE;
85 SMALLINT  readOnly_eprom             = FALSE;
86 SMALLINT  nonVolatile_eprom          = TRUE;
87 SMALLINT  needsProgramPulse_eprom    = TRUE;
88 SMALLINT  needsPowerDelivery_eprom   = FALSE;
89 SMALLINT  hasExtraInfo_eprom         = TRUE;
90 SMALLINT  extraInfoLength_eprom      = 1;
91 char *extraInfoDesc_eprom       = "Inverted redirection page";
92 SMALLINT  pageAutoCRC_eprom          = TRUE;
93 SMALLINT  lockOffset                 = 0;
94 SMALLINT  lockRedirectOffset         = 0;
95 SMALLINT  canredirectPage            = FALSE;
96 SMALLINT  canlockPage                = FALSE;
97 SMALLINT  canlockRedirectPage        = FALSE;
98 SMALLINT  numPages                   = 64;
99 SMALLINT  CRCbytes                   = 2;
100 
101 
102 /**
103  * Read  memory in the current bank with no CRC checking (device or
104  * data). The resulting data from this API may or may not be what is on
105  * the 1-Wire device.  It is recommends that the data contain some kind
106  * of checking (CRC) like in the readPagePacketEPROM() method or have
107  * the 1-Wire device provide the CRC as in readPageCRCEPROM().  readPageCRCEPROM()
108  * however is not supported on all memory types, see 'hasPageAutoCRCEPROM()'.
109  * If neither is an option then this method could be called more
110  * then once to at least verify that the same thing is read consistantly.
111  *
112  * bank     to tell what memory bank of the ibutton to use.
113  * portnum  the port number of the port being used for the
114  *          1-Wire Network.
115  * SNum     the serial number for the part that the read is
116  *          to be done on.
117  * str_add  starting physical address
118  * rd_cont  if 'true' then device read is continued without
119  *          re-selecting.  This can only be used if the new
120  *          read() continious where the last one led off
121  *          and it is inside a 'beginExclusive/endExclusive'
122  *          block.
123  * buff     byte array to place read data into
124  * len      length in bytes to read
125  *
126  * @return 'true' if the read was complete
127  */
readEPROM(SMALLINT bank,int portnum,uchar * SNum,int str_add,SMALLINT rd_cont,uchar * buff,int len)128 SMALLINT readEPROM(SMALLINT bank, int portnum, uchar *SNum, int str_add,
129                    SMALLINT rd_cont, uchar *buff, int len)
130 {
131    int i;
132    int start_pg, end_pg, num_bytes, pg;
133    uchar raw_buf[256];
134 
135    // check if read exceeds memory
136    if ((str_add + len) > getSizeEPROM(bank,SNum))
137    {
138       OWERROR(OWERROR_READ_OUT_OF_RANGE);
139       return FALSE;
140    }
141 
142    // check if status memory
143    if(readPageWithCRC(bank,SNum) == STATUS_READ_PAGE_COMMAND_EPROM)
144    {
145       // no regular read memory so must use readPageCRC
146       start_pg = str_add / getPageLengthEPROM(bank,SNum);
147       end_pg   = ((str_add + len) / getPageLengthEPROM(bank,SNum)) - 1;
148 
149       if (((str_add + len) % getPageLengthEPROM(bank,SNum)) > 0)
150          end_pg++;
151 
152       // loop to read the pages
153       for (pg = start_pg; pg <= end_pg; pg++)
154          readPageCRCEPROM(bank,portnum,SNum,pg,
155                           &raw_buf[(pg-start_pg)*getPageLengthEPROM(bank,SNum)]);
156 
157       // extract out the data
158       for(i=0;i<len;i++)
159          buff[i] = raw_buf[i];
160    }
161    // regular memory so use standard read memory command
162    else
163    {
164 
165       // see if need to access the device
166       if (!rd_cont)
167       {
168 
169          // select the device
170          if (!owAccess(portnum))
171          {
172             OWERROR(OWERROR_DEVICE_SELECT_FAIL);
173             return FALSE;
174          }
175 
176          // build start reading memory block
177          raw_buf[0] = READ_MEMORY_COMMAND_EPROM;
178          raw_buf[1] = (str_add + getStartingAddressEPROM(bank,SNum)) & 0xFF;
179          raw_buf[2] = (((str_add + getStartingAddressEPROM(bank,SNum)) & 0xFFFF) >> 8)
180                       & 0xFF;
181          raw_buf[3] = 0xFF;
182 
183          // check if get a 1 byte crc in a normal read.
184          if(SNum[0] == 0x09)
185             num_bytes = 4;
186          else
187             num_bytes = 3;
188 
189          // do the first block for command, address
190          if(!owBlock(portnum,FALSE,raw_buf,num_bytes))
191          {
192             OWERROR(OWERROR_BLOCK_FAILED);
193             return FALSE;
194          }
195       }
196 
197       // pre-fill readBuf with 0xFF
198       for (i=0;i<len;i++)
199          buff[i] = 0xFF;
200 
201       // send second block to read data, return result
202       if(!owBlock(portnum,FALSE,buff,len))
203       {
204          OWERROR(OWERROR_DEVICE_SELECT_FAIL);
205          return FALSE;
206       }
207    }
208 
209    return TRUE;
210 }
211 
212 /**
213  * Write  memory in the current bank.  It is recommended that
214  * when writing  data that some structure in the data is created
215  * to provide error free reading back with readEPROM().  Or the
216  * method 'writePagePacketEPROM()' could be used which automatically
217  * wraps the data in a length and CRC.
218  *
219  * When using on Write-Once devices care must be taken to write into
220  * into empty space.  If write() is used to write over an unlocked
221  * page on a Write-Once device it will fail.
222  *
223  * bank     to tell what memory bank of the ibutton to use.
224  * portnum  the port number of the port being used for the
225  *          1-Wire Network.
226  * SNum     the serial number for the part that the write is
227  *          to be done on.
228  * str_add  starting address
229  * buff     byte array containing data to write
230  * len      length in bytes to write
231  *
232  * @return 'true' if the write was complete.
233  */
writeEPROM(SMALLINT bank,int portnum,uchar * SNum,int str_add,uchar * buff,int len)234 SMALLINT writeEPROM(SMALLINT bank, int portnum, uchar *SNum, int str_add,
235                     uchar *buff, int len)
236 {
237    int      i;
238    int      result;
239    SMALLINT write_continue;
240    int      crc_type;
241    int      verify[256];
242 
243    // return if nothing to do
244    if (len == 0)
245       return TRUE;
246 
247    // check if power delivery is available
248    if(!owHasProgramPulse(portnum))
249    {
250       OWERROR(OWERROR_NO_PROGRAM_PULSE);
251       return FALSE;
252    }
253 
254    // check if trying to write read only bank
255    if(isReadOnlyEPROM(bank,portnum,SNum))
256    {
257       OWERROR(OWERROR_READ_ONLY);
258       return FALSE;
259    }
260 
261    for(i=0;i<len;i++)
262    {
263       verify[0] = writeVerify(bank,portnum,SNum,
264           ((str_add+i+getStartingAddressEPROM(bank,SNum))/getPageLengthEPROM(bank,SNum)));
265 
266       if(isPageLocked(bank,portnum,SNum,(str_add+i+getStartingAddressEPROM(bank,SNum))/
267                                          getPageLengthEPROM(bank,SNum)))
268       {
269          OWERROR(OWERROR_PAGE_LOCKED);
270          return FALSE;
271       }
272    }
273 
274    // check if write exceeds memory
275    if((str_add + len) > (getPageLengthEPROM(bank,SNum) * getNumberPagesEPROM(bank,SNum)))
276    {
277       OWERROR(OWERROR_WRITE_OUT_OF_RANGE);
278       return FALSE;
279    }
280 
281    // loop while still have bytes to write
282    write_continue = TRUE;
283 
284    crc_type = numCRCbytes(bank,SNum) - 1;
285 
286    for (i=0;i<len;i++)
287    {
288       result = owProgramByte(portnum,buff[i],str_add+i+getStartingAddressEPROM(bank,SNum),
289                              writeMemCmd(bank,SNum),crc_type,write_continue);
290       if(verify[i])
291       {
292          if((result == -1) || ((uchar) result != buff[i]))
293          {
294             OWERROR(OWERROR_READBACK_EPROM_FAILED);
295             return FALSE;
296          }
297          else
298             write_continue = FALSE;
299       }
300    }
301 
302    return TRUE;
303 }
304 
305 /**
306  * Read  page in the current bank with no
307  * CRC checking (device or data). The resulting data from this API
308  * may or may not be what is on the 1-Wire device.  It is recommends
309  * that the data contain some kind of checking (CRC) like in the
310  * readPagePacketEPROM() method or have the 1-Wire device provide the
311  * CRC as in readPageCRCEPROM().  readPageCRCEPROM() however is not
312  * supported on all memory types, see 'hasPageAutoCRCEPROM()'.
313  * If neither is an option then this method could be called more
314  * then once to at least verify that the same thing is read consistantly.
315  *
316  * bank     to tell what memory bank of the ibutton to use.
317  * portnum  the port number of the port being used for the
318  *          1-Wire Network.
319  * SNum     the serial number for the part.
320  * page     the page to read
321  * rd_cont  if 'true' then device read is continued without
322  *          re-selecting.  This can only be used if the new
323  *          read() continious where the last one led off
324  *          and it is inside a 'beginExclusive/endExclusive'
325  *          block.
326  * buff     byte array containing data that was read.
327  * len      length in bytes to write
328  *
329  * @return - returns '0' if the read page wasn't completed.
330  *                   '1' if the operation is complete.
331  */
readPageEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,SMALLINT rd_cont,uchar * buff)332 SMALLINT readPageEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
333                        SMALLINT rd_cont, uchar *buff)
334 {
335    uchar extra[1];
336 
337    if(hasPageAutoCRCEPROM(bank,SNum))
338    {
339       if(!readPageExtraCRCEPROM(bank,portnum,SNum,page,buff,extra))
340          return FALSE;
341    }
342    else
343    {
344       if(!readEPROM(bank,portnum,SNum,(page*getPageLengthEPROM(bank,SNum)),FALSE,
345                     buff,getPageLengthEPROM(bank,SNum)))
346          return FALSE;
347    }
348 
349    return TRUE;
350 }
351 
352 /**
353  * Read  page with extra information in the current bank with no
354  * CRC checking (device or data). The resulting data from this API
355  * may or may not be what is on the 1-Wire device.  It is recommends
356  * that the data contain some kind of checking (CRC) like in the
357  * readPagePacketEPROM() method or have the 1-Wire device provide the
358  * CRC as in readPageCRCEPROM().  readPageCRCEPROM() however is not
359  * supported on all memory types, see 'hasPageAutoCRCEPROM()'.
360  * If neither is an option then this method could be called more
361  * then once to at least verify that the same thing is read consistantly.
362  * See the method 'hasExtraInfoEPROM()' for a description of the optional
363  * extra information some devices have.
364  *
365  * bank     to tell what memory bank of the ibutton to use.
366  * portnum  the port number of the port being used for the
367  *          1-Wire Network.
368  * SNum     the serial number for the part.
369  * page     the page to read
370  * rd_cont  if 'true' then device read is continued without
371  *          re-selecting.  This can only be used if the new
372  *          read() continious where the last one led off
373  *          and it is inside a 'beginExclusive/endExclusive'
374  *          block.
375  * buff     byte array containing data that was read
376  * len      length in bytes to write
377  * extra    the extra information
378  *
379  * @return - returns '0' if the read page wasn't completed with extra info.
380  *                   '1' if the operation is complete.
381  */
readPageExtraEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,SMALLINT rd_cont,uchar * buff,uchar * extra)382 SMALLINT readPageExtraEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
383                             SMALLINT rd_cont, uchar *buff, uchar *extra)
384 {
385    // check if current bank is not scratchpad bank, or not page 0
386    if(!hasExtraInfoEPROM(bank,SNum))
387    {
388       OWERROR(OWERROR_EXTRA_INFO_NOT_SUPPORTED);
389       return FALSE;
390    }
391 
392    return readPageExtraCRCEPROM(bank,portnum,SNum,page,buff,extra);
393 }
394 
395 /**
396  * Read a complete memory page with CRC verification provided by the
397  * device with extra information.  Not supported by all devices.
398  * See the method 'hasPageAutoCRCEPROM()'.
399  * See the method 'haveExtraInfoEPROM()' for a description of the optional
400  * extra information.
401  *
402  * bank     to tell what memory bank of the ibutton to use.
403  * portnum  the port number of the port being used for the
404  *          1-Wire Network.
405  * SNum     the serial number for the part.
406  * page     the page to read
407  * buff     byte array containing data that was read.
408  * extra    the extra information
409  *
410  * @return - returns '0' if the read page wasn't completed with extra info.
411  *                   '1' if the operation is complete.
412  */
readPageExtraCRCEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,uchar * read_buff,uchar * extra)413 SMALLINT readPageExtraCRCEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
414                                uchar *read_buff, uchar *extra)
415 {
416    int    i, len = 0, lastcrc = 0, addr, extractPnt;
417    uchar raw_buf[PAGE_LENGTH_EPROM + 6];
418 
419    owSerialNum(portnum,SNum,FALSE);
420 
421    // only needs to be implemented if supported by hardware
422    if(!hasPageAutoCRCEPROM(bank,SNum))
423    {
424       OWERROR(OWERROR_CRC_NOT_SUPPORTED);
425       return FALSE;
426    }
427 
428    // check if read exceeds memory
429    if(page > (getNumberPagesEPROM(bank,SNum)))
430    {
431       OWERROR(OWERROR_READ_OUT_OF_RANGE);
432       return FALSE;
433    }
434 
435 
436    // select the device
437    if (!owAccess(portnum))
438    {
439       OWERROR(OWERROR_DEVICE_SELECT_FAIL);
440       return FALSE;
441    }
442 
443    // build start reading memory block with: command, address, (extraInfo?), (crc?)
444    len = 3 + getExtraInfoLengthEPROM(bank,SNum);
445 
446    if(crcAfterAdd(bank,SNum))
447    {
448       len += numCRCbytes(bank,SNum);
449    }
450 
451    for(i=0;i<len;i++)
452       raw_buf[i] = 0xFF;
453 
454    raw_buf[0] = readPageWithCRC(bank,SNum);
455 
456    addr = page * getPageLengthEPROM(bank,SNum) + getStartingAddressEPROM(bank,SNum);
457 
458    raw_buf[1] = addr & 0xFF;
459    raw_buf[2] = ((addr & 0xFFFF) >> 8) & 0xFF;
460 
461    // do the first block
462    if(!owBlock(portnum,FALSE,&raw_buf[0],len))
463    {
464       OWERROR(OWERROR_BLOCK_FAILED);
465       return FALSE;
466    }
467 
468    // check CRC
469    if (numCRCbytes(bank,SNum) == 2)
470    {
471       setcrc16(portnum,0);
472       for(i=0;i<len;i++)
473          lastcrc = docrc16(portnum,raw_buf[i]);
474    }
475    else
476    {
477       setcrc8(portnum,0);
478       for(i=0;i<len;i++)
479          lastcrc = docrc8(portnum,raw_buf[i]);
480    }
481 
482    if((getExtraInfoLengthEPROM(bank,SNum) > 0) || (crcAfterAdd(bank,SNum)))
483    {
484       // check CRC
485       if(numCRCbytes(bank,SNum) == 2)
486       {
487          if (lastcrc != 0xB001)
488          {
489             OWERROR(OWERROR_CRC_FAILED);
490             return FALSE;
491          }
492       }
493       else
494       {
495          if (lastcrc != 0)
496          {
497             return FALSE;
498          }
499       }
500 
501       lastcrc = 0;
502 
503       // extract the extra information
504       extractPnt = len - getExtraInfoLengthEPROM(bank,SNum) - numCRCbytes(bank,SNum);
505       if(getExtraInfoLengthEPROM(bank,SNum))
506          for(i=extractPnt;i<(extractPnt+getExtraInfoLengthEPROM(bank,SNum));i++)
507             extra[i-extractPnt] = raw_buf[i];
508    }
509 
510    // pre-fill with 0xFF
511    for(i=0;i<(getPageLengthEPROM(bank,SNum) + numCRCbytes(bank,SNum));i++)
512       raw_buf[i] = 0xFF;
513 
514    // send block to read data + crc
515    if(!owBlock(portnum,FALSE,&raw_buf[0],(getPageLengthEPROM(bank,SNum)+numCRCbytes(bank,SNum))))
516    {
517       OWERROR(OWERROR_BLOCK_FAILED);
518       return FALSE;
519    }
520 
521    // check the CRC
522    if (numCRCbytes(bank,SNum) == 2)
523    {
524       setcrc16(portnum, (ushort) lastcrc);
525       for(i=0;i<(getPageLengthEPROM(bank,SNum)+numCRCbytes(bank,SNum));i++)
526          lastcrc = docrc16(portnum,raw_buf[i]);
527 
528       if (lastcrc != 0xB001)
529       {
530          OWERROR(OWERROR_CRC_FAILED);
531          return FALSE;
532       }
533    }
534    else
535    {
536       setcrc8(portnum, (uchar) lastcrc);
537       for(i=0;i<(getPageLengthEPROM(bank,SNum)+numCRCbytes(bank,SNum));i++)
538          lastcrc = docrc8(portnum,raw_buf[i]);
539 
540       if (lastcrc != 0)
541       {
542          OWERROR(OWERROR_CRC_FAILED);
543          return FALSE;
544       }
545    }
546 
547    // extract the page data
548    for(i=0;i<getPageLengthEPROM(bank,SNum);i++)
549    {
550       read_buff[i] = raw_buf[i];
551    }
552 
553    return TRUE;
554 }
555 
556 /**
557  * Read a complete memory page with CRC verification provided by the
558  * device.  Not supported by all devices.  See the method
559  * 'hasPageAutoCRCEPROM()'.
560  *
561  * bank     to tell what memory bank of the ibutton to use.
562  * portnum  the port number of the port being used for the
563  *          1-Wire Network.
564  * SNum     the serial number for the part.
565  * page     the page to read
566  * buff     byte array containing data that was read
567  *
568  * @return - returns '0' if the read page wasn't completed.
569  *                   '1' if the operation is complete.
570  */
readPageCRCEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,uchar * buff)571 SMALLINT readPageCRCEPROM(SMALLINT bank, int portnum, uchar *SNum, int page, uchar *buff)
572 {
573    uchar extra[1];
574 
575    return readPageExtraCRCEPROM(bank,portnum,SNum,page,buff,extra);
576 }
577 
578 /**
579  * Read a Universal Data Packet.
580  *
581  * The Universal Data Packet always starts on page boundaries but
582  * can end anywhere in the page.  The structure specifies the length of
583  * data bytes not including the length byte and the CRC16 bytes.
584  * There is one length byte. The CRC16 is first initialized to
585  * the page number.  This provides a check to verify the page that
586  * was intended is being read.  The CRC16 is then calculated over
587  * the length and data bytes.  The CRC16 is then inverted and stored
588  * low byte first followed by the high byte.  This is structure is
589  * used by this method to verify the data but is not returned, only
590  * the data payload is returned.
591  *
592  * bank     to tell what memory bank of the ibutton to use.
593  * portnum  the port number of the port being used for the
594  *          1-Wire Network.
595  * SNum     the serial number for the part.
596  * page     the page to read
597  * rd_cont  if 'true' then device read is continued without
598  *          re-selecting.  This can only be used if the new
599  *          read() continious where the last one led off
600  *          and it is inside a 'beginExclusive/endExclusive'
601  *          block.
602  * buff     byte array containing data that was read.
603  * len      length of the packet
604  *
605  * @return - returns '0' if the read page packet wasn't completed
606  *                   '1' if the operation is complete.
607  */
readPagePacketEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,SMALLINT rd_cont,uchar * buff,int * len)608 SMALLINT readPagePacketEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
609                              SMALLINT rd_cont, uchar *buff, int *len)
610 {
611    uchar  raw_buf[PAGE_LENGTH_EPROM];
612    uchar  extra[1];
613    ushort lastcrc16;
614    int i;
615 
616    // read entire page with read page CRC
617    if(!readPageExtraCRCEPROM(bank,portnum,SNum,page,&raw_buf[0],&extra[0]))
618       return FALSE;
619 
620    // check if length is realistic
621    if ((raw_buf[0] & 0xFF) > getMaxPacketDataLengthEPROM(bank,SNum))
622    {
623       OWERROR(OWERROR_INVALID_PACKET_LENGTH);
624       return FALSE;
625    }
626 
627    // verify the CRC is correct
628    setcrc16(portnum,(ushort) ((getStartingAddressEPROM(bank,SNum)/PAGE_LENGTH_EPROM) + page));
629    for(i=0;i<(raw_buf[0]+3);i++)
630       lastcrc16 = docrc16(portnum,raw_buf[i]);
631 
632    if(lastcrc16 == 0xB001)
633    {
634       // extract the data out of the packet
635       for(i=0;i<raw_buf[0];i++)
636          buff[i] = raw_buf[i+1];
637 
638       // return the length
639       *len = raw_buf[0];
640    }
641    else
642    {
643       OWERROR(OWERROR_CRC_FAILED);
644       return FALSE;
645    }
646 
647    return TRUE;
648 }
649 
650 /**
651  * Read a Universal Data Packet and extra information.  See the
652  * method 'readPagePacketEPROM()' for a description of the packet structure.
653  * See the method 'hasExtraInfoEPROM()' for a description of the optional
654  * extra information some devices have.
655  *
656  * bank     to tell what memory bank of the ibutton to use.
657  * portnum  the port number of the port being used for the
658  *          1-Wire Network.
659  * SNum     the serial number for the part.
660  * page     the page to read
661  * rd_cont  if 'true' then device read is continued without
662  *          re-selecting.  This can only be used if the new
663  *          read() continious where the last one led off
664  *          and it is inside a 'beginExclusive/endExclusive'
665  *          block.
666  * buff     byte array containing data that was read.
667  * len      length of the packet
668  * extra    extra information
669  *
670  * @return - returns '0' if the read page packet wasn't completed
671  *                   '1' if the operation is complete.
672  */
readPagePacketExtraEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,SMALLINT rd_cont,uchar * buff,int * len,uchar * extra)673 SMALLINT readPagePacketExtraEPROM(SMALLINT bank, int portnum, uchar *SNum,
674                                   int page, SMALLINT rd_cont, uchar *buff,
675                                   int *len, uchar *extra)
676 {
677    uchar raw_buf[PAGE_LENGTH_EPROM];
678    ushort lastcrc16;
679    int i;
680 
681    // check if current bank is not scratchpad bank, or not page 0
682    if (!hasExtraInfoEPROM(bank,SNum))
683    {
684       OWERROR(OWERROR_EXTRA_INFO_NOT_SUPPORTED);
685       return FALSE;
686    }
687 
688    // read entire page with read page CRC
689    if(!readPageExtraCRCEPROM(bank,portnum,SNum,page,raw_buf,extra))
690       return FALSE;
691 
692    // check if length is realistic
693    if ((raw_buf[0] & 0xFF) > getMaxPacketDataLengthEPROM(bank,SNum))
694    {
695       OWERROR(OWERROR_INVALID_PACKET_LENGTH);
696       return FALSE;
697    }
698 
699    // verify the CRC is correct
700    setcrc16(portnum,(ushort) ((getStartingAddressEPROM(bank,SNum)/PAGE_LENGTH_EPROM) + page));
701    for(i=0;i<(raw_buf[0]+3);i++)
702       lastcrc16 = docrc16(portnum,raw_buf[i]);
703 
704    if(lastcrc16 == 0xB001)
705    {
706       // extract the data out of the packet
707       for(i=0;i<raw_buf[0];i++)
708          buff[i] = raw_buf[i+1];
709 
710       // return the length
711       *len = raw_buf [0];
712    }
713    else
714    {
715       OWERROR(OWERROR_CRC_FAILED);
716       return FALSE;
717    }
718 
719    return TRUE;
720 }
721 
722 /**
723  * Write a Universal Data Packet.  See the method 'readPagePacketEPROM()'
724  * for a description of the packet structure.
725  *
726  * bank     to tell what memory bank of the ibutton to use.
727  * portnum  the port number of the port being used for the
728  *          1-Wire Network.
729  * SNum     the serial number for the part.
730  * page     the page the packet is being written to.
731  * rd_cont  if 'true' then device read is continued without
732  *          re-selecting.  This can only be used if the new
733  *          read() continious where the last one led off
734  *          and it is inside a 'beginExclusive/endExclusive'
735  *          block.
736  * buff     byte array containing data that to write.
737  * len      length of the packet
738  *
739  * @return - returns '0' if the write page packet wasn't completed
740  *                   '1' if the operation is complete.
741  */
writePagePacketEPROM(SMALLINT bank,int portnum,uchar * SNum,int page,uchar * buff,int len)742 SMALLINT writePagePacketEPROM(SMALLINT bank, int portnum, uchar *SNum, int page,
743                               uchar *buff, int len)
744 {
745    uchar raw_buf[PAGE_LENGTH_EPROM];
746    int   crc, i;
747 
748    // make sure length does not exceed max
749    if (len > getMaxPacketDataLengthEPROM(bank,SNum))
750    {
751       OWERROR(OWERROR_INVALID_PACKET_LENGTH);
752       return FALSE;
753    }
754 
755    // see if this bank is general read/write
756    if (!isGeneralPurposeMemoryEPROM(bank,SNum))
757    {
758       OWERROR(OWERROR_NOT_GENERAL_PURPOSE);
759       return FALSE;
760    }
761 
762    // construct the packet to write
763    raw_buf[0] = (uchar) len;
764 
765    for(i=0;i<len;i++)
766       raw_buf[i+1] = buff[i];
767 
768    setcrc16(portnum,(ushort) ((getStartingAddressEPROM(bank,SNum)/PAGE_LENGTH_EPROM) + page));
769    for(i=0;i<len+1;i++)
770       crc = docrc16(portnum,raw_buf[i]);
771 
772    raw_buf[len + 1] = ~crc & 0xFF;
773    raw_buf[len + 2] = ((~crc & 0xFFFF) >> 8) & 0xFF;
774 
775    // write the packet, return result
776    if(!writeEPROM(bank,portnum,SNum,page*getPageLengthEPROM(bank,SNum)+
777                   getStartingAddressEPROM(bank,SNum),&raw_buf[0],len+3))
778       return FALSE;
779 
780    return TRUE;
781 }
782 
783 /**
784  * Query to get the number of pages in current memory bank.
785  *
786  * bank     to tell what memory bank of the ibutton to use.
787  * SNum     the serial number for the part.
788  *
789  * @return  number of pages in current memory bank
790  */
getNumberPagesEPROM(SMALLINT bank,uchar * SNum)791 SMALLINT getNumberPagesEPROM(SMALLINT bank, uchar *SNum)
792 {
793    int pages = numPages;
794 
795    switch(SNum[0])
796    {
797       case 0x09:
798          if(bank == 0)
799             pages = 4;
800          else if(bank == 1)
801             pages = 1;
802          break;
803 
804       case 0x0B:
805          if((bank == 1) || (bank == 2) || (bank == 3))
806             pages = 1;
807          else if(bank == 4)
808             pages = 8;
809          break;
810 
811       case 0x0F:
812          if(bank == 0)
813             pages = 256;
814          else if((bank == 1) || (bank == 2))
815             pages = 4;
816          else if(bank == 3)
817             pages = 3;
818          else if(bank == 4)
819             pages = 32;
820          break;
821 
822       case 0x12:
823          if(bank == 0)
824             pages = 4;
825          else if(bank == 1)
826             pages = 1;
827          break;
828 
829       case 0x13:
830          if(bank == 0)
831             pages = 16;
832          else if(bank == 4)
833             pages = 2;
834          else if((bank == 1) || (bank == 2) || (bank == 3))
835             pages = 1;
836          break;
837 
838       default:
839          pages = numPages;
840          break;
841    }
842 
843    return pages;
844 }
845 
846 /**
847  * Query to get the memory bank size in bytes.
848  *
849  * bank     to tell what memory bank of the ibutton to use.
850  * SNum     the serial number for the part.
851  *
852  * @return  memory bank size in bytes.
853  */
getSizeEPROM(SMALLINT bank,uchar * SNum)854 int getSizeEPROM(SMALLINT bank, uchar *SNum)
855 {
856    int size = SIZE_EPROM;
857 
858    switch(SNum[0])
859    {
860       case 0x09:
861          if(bank == 0)
862             size = 128;
863          else if(bank == 1)
864             size = 8;
865          break;
866 
867       case 0x0B:
868          if((bank == 1) || (bank == 2) || (bank == 3))
869             size = 8;
870          else if(bank == 4)
871             size = 64;
872          break;
873 
874       case 0x0F:
875          if(bank == 0)
876             size = 8192;
877          else if((bank == 1) || (bank == 2))
878             size = 32;
879          else if(bank == 3)
880             size = 24;
881          else if(bank == 4)
882             size = 256;
883          break;
884 
885       case 0x12:
886          if(bank == 0)
887             size = 128;
888          else if(bank == 1)
889             size = 8;
890          break;
891 
892       case 0x13:
893          if(bank == 0)
894             size = 512;
895          else if(bank == 4)
896             size = 16;
897          else if((bank == 1) || (bank == 2) || (bank == 3))
898             size = 8;
899          break;
900 
901       default:
902          size = SIZE_EPROM;
903          break;
904    }
905 
906    return size;
907 }
908 
909 /**
910  * Query to get the starting physical address of this bank.  Physical
911  * banks are sometimes sub-divided into logical banks due to changes
912  * in attributes.
913  *
914  * bank     to tell what memory bank of the ibutton to use.
915  * SNum     the serial number for the part.
916  *
917  * @return  physical starting address of this logical bank.
918  */
getStartingAddressEPROM(SMALLINT bank,uchar * SNum)919 int getStartingAddressEPROM(SMALLINT bank, uchar *SNum)
920 {
921    int addr = 0;
922 
923    switch(SNum[0])
924    {
925       case 0x0B:
926          if(bank == 2)
927             addr = 32;
928          else if(bank == 3)
929             addr = 64;
930          else if(bank == 4)
931             addr = 256;
932          break;
933 
934       case 0x0F:
935          if(bank == 2)
936             addr = 32;
937          else if(bank == 3)
938             addr = 64;
939          else if(bank == 4)
940             addr = 256;
941          break;
942 
943       case 0x13:
944          if(bank == 2)
945             addr = 32;
946          else if(bank == 3)
947             addr = 64;
948          else if(bank == 4)
949             addr = 256;
950          break;
951 
952       default:
953          addr = 0;
954          break;
955    }
956 
957    return addr;
958 }
959 
960 /**
961  * Query to get page length in bytes in current memory bank.
962  *
963  * bank     to tell what memory bank of the ibutton to use.
964  * SNum     the serial number for the part.
965  *
966  * @return   page length in bytes in current memory bank
967  */
getPageLengthEPROM(SMALLINT bank,uchar * SNum)968 SMALLINT getPageLengthEPROM(SMALLINT bank, uchar *SNum)
969 {
970    int len = PAGE_LENGTH_EPROM;
971 
972    switch(SNum[0])
973    {
974       case 0x09:
975          if(bank == 1)
976             len = 8;
977          break;
978 
979       case 0x0B:
980          if((bank > 0) && (bank < 5))
981             len = 8;
982 
983       case 0x0F:
984          if((bank > 0) && (bank <5))
985             len = 8;
986          break;
987 
988       case 0x12:
989          if(bank == 1)
990             len = 8;
991          break;
992 
993       case 0x13:
994          if((bank > 0) && (bank < 5))
995             len = 8;
996          break;
997 
998       default:
999          len = PAGE_LENGTH_EPROM;
1000          break;
1001    }
1002 
1003    return len;
1004 }
1005 
1006 /**
1007  * Query to see get a string description of the current memory bank.
1008  *
1009  * bank     to tell what memory bank of the ibutton to use.
1010  * SNum     the serial number for the part.
1011  *
1012  * @return  String containing the memory bank description
1013  */
getBankDescriptionEPROM(SMALLINT bank,uchar * SNum)1014 char *getBankDescriptionEPROM(SMALLINT bank, uchar *SNum)
1015 {
1016    switch(SNum[0])
1017    {
1018       case 0x09:
1019          if(bank == 1)
1020             return "Write protect pages and page redirection";
1021          break;
1022 
1023       case 0x0B:
1024          if(bank == 1)
1025             return "Write protect pages";
1026          else if(bank == 2)
1027             return "Write protect redirection";
1028          else if(bank == 3)
1029             return "Bitmap of used pages for file structure";
1030          else if(bank == 4)
1031             return "Page redirection bytes";
1032          break;
1033 
1034       case 0x0F:
1035          if(bank == 1)
1036             return "Write protect pages";
1037          else if(bank == 2)
1038             return "Write protect redirection";
1039          else if(bank == 3)
1040             return "Bitmap of used pages for file structure";
1041          else if(bank == 4)
1042             return "Pages redirection bytes";
1043          break;
1044 
1045       case 0x12:
1046          if(bank == 1)
1047             return "Write protect pages, page redirection, switch control";
1048          break;
1049 
1050       case 0x13:
1051          if(bank == 1)
1052             return "Write protect pages";
1053          else if(bank == 2)
1054             return "Write protect redirection";
1055          else if(bank == 3)
1056             return "Bitmap of used pages for file structure";
1057          else if(bank == 4)
1058             return "Page redirection bytes";
1059          break;
1060 
1061       default:
1062          return bankDescription_eprom;
1063          break;
1064    }
1065 
1066    return bankDescription_eprom;
1067 }
1068 
1069 /**
1070  * Query to see if the current memory bank is general purpose
1071  * user memory.  If it is NOT then it is Memory-Mapped and writing
1072  * values to this memory will affect the behavior of the 1-Wire
1073  * device.
1074  *
1075  * bank     to tell what memory bank of the ibutton to use.
1076  * SNum     the serial number for the part.
1077  *
1078  * @return  'true' if current memory bank is general purpose
1079  */
isGeneralPurposeMemoryEPROM(SMALLINT bank,uchar * SNum)1080 SMALLINT isGeneralPurposeMemoryEPROM(SMALLINT bank, uchar *SNum)
1081 {
1082    int gp_mem = generalPurposeMemory_eprom;
1083 
1084    switch(SNum[0])
1085    {
1086       case 0x09:
1087          if(bank == 1)
1088             gp_mem = FALSE;
1089          break;
1090 
1091       case 0x0B:
1092          if((bank > 0) && (bank < 5))
1093             gp_mem = FALSE;
1094 
1095       case 0x0F:
1096          if((bank > 0) && (bank <5))
1097             gp_mem = FALSE;
1098          break;
1099 
1100       case 0x12:
1101          if(bank == 1)
1102             gp_mem = FALSE;
1103          break;
1104 
1105       case 0x13:
1106          if((bank > 0) && (bank < 5))
1107             gp_mem = FALSE;
1108          break;
1109 
1110       default:
1111          gp_mem = generalPurposeMemory_eprom;
1112          break;
1113    }
1114 
1115    return gp_mem;
1116 }
1117 
1118 /**
1119  * Query to see if current memory bank is read/write.
1120  *
1121  * bank     to tell what memory bank of the ibutton to use.
1122  * SNum     the serial number for the part.
1123  *
1124  * @return  'true' if current memory bank is read/write
1125  */
isReadWriteEPROM(SMALLINT bank,int portnum,uchar * SNum)1126 SMALLINT isReadWriteEPROM(SMALLINT bank, int portnum, uchar *SNum)
1127 {
1128    return readWrite_eprom;
1129 }
1130 
1131 /**
1132  * Query to see if current memory bank is write write once such
1133  * as with EPROM technology.
1134  *
1135  * bank     to tell what memory bank of the ibutton to use.
1136  * SNum     the serial number for the part.
1137  *
1138  * @return  'true' if current memory bank can only be written once
1139  */
isWriteOnceEPROM(SMALLINT bank,int portnum,uchar * SNum)1140 SMALLINT isWriteOnceEPROM(SMALLINT bank, int portnum, uchar *SNum)
1141 {
1142    return writeOnce_eprom;
1143 }
1144 
1145 /**
1146  * Query to see if current memory bank is read only.
1147  *
1148  * @return  'true' if current memory bank can only be read
1149  */
isReadOnlyEPROM(SMALLINT bank,int portnum,uchar * SNum)1150 SMALLINT isReadOnlyEPROM(SMALLINT bank, int portnum, uchar *SNum)
1151 {
1152    return readOnly_eprom;
1153 }
1154 
1155 /**
1156  * Query to see if current memory bank non-volatile.  Memory is
1157  * non-volatile if it retains its contents even when removed from
1158  * the 1-Wire network.
1159  *
1160  * bank     to tell what memory bank of the ibutton to use.
1161  * SNum     the serial number for the part.
1162  *
1163  * @return  'true' if current memory bank non volatile.
1164  */
isNonVolatileEPROM(SMALLINT bank,uchar * SNum)1165 SMALLINT isNonVolatileEPROM(SMALLINT bank, uchar *SNum)
1166 {
1167    return nonVolatile_eprom;
1168 }
1169 
1170 /**
1171  * Query to see if current memory bank pages need the adapter to
1172  * have a 'ProgramPulse' in order to write to the memory.
1173  *
1174  * bank     to tell what memory bank of the ibutton to use.
1175  * SNum     the serial number for the part.
1176  *
1177  * @return  'true' if writing to the current memory bank pages
1178  *                 requires a 'ProgramPulse'.
1179  */
needsProgramPulseEPROM(SMALLINT bank,uchar * SNum)1180 SMALLINT needsProgramPulseEPROM(SMALLINT bank, uchar *SNum)
1181 {
1182    return needsProgramPulse_eprom;
1183 }
1184 
1185 /**
1186  * Query to see if current memory bank pages need the adapter to
1187  * have a 'PowerDelivery' feature in order to write to the memory.
1188  *
1189  * bank     to tell what memory bank of the ibutton to use.
1190  * SNum     the serial number for the part.
1191  *
1192  * @return  'true' if writing to the current memory bank pages
1193  *                 requires 'PowerDelivery'.
1194  */
needsPowerDeliveryEPROM(SMALLINT bank,uchar * SNum)1195 SMALLINT needsPowerDeliveryEPROM(SMALLINT bank, uchar *SNum)
1196 {
1197    return needsPowerDelivery_eprom;
1198 }
1199 
1200 /**
1201  * Checks to see if this memory bank's pages deliver extra
1202  * information outside of the normal data space,  when read.  Examples
1203  * of this may be a redirection byte, counter, tamper protection
1204  * bytes, or SHA-1 result.  If this method returns true then the
1205  * methods with an 'extraInfo' parameter can be used.
1206  *
1207  * bank     to tell what memory bank of the ibutton to use.
1208  * SNum     the serial number for the part.
1209  *
1210  * @return  true if reading the this memory bank's
1211  *               pages provides extra information
1212  */
hasExtraInfoEPROM(SMALLINT bank,uchar * SNum)1213 SMALLINT hasExtraInfoEPROM(SMALLINT bank, uchar *SNum)
1214 {
1215    SMALLINT hasExtra = hasExtraInfo_eprom;
1216 
1217    switch(SNum[0])
1218    {
1219       case 0x09:
1220          hasExtra = FALSE;
1221          break;
1222 
1223       case 0x0B:
1224          if((bank > 0) && (bank < 5))
1225             hasExtra = FALSE;
1226          break;
1227 
1228       case 0x0F:
1229          if((bank > 0) && (bank < 5))
1230             hasExtra = FALSE;
1231          break;
1232 
1233       case 0x12:
1234          if(bank == 1)
1235             hasExtra = FALSE;
1236          break;
1237 
1238       case 0x13:
1239          if((bank > 0) && (bank < 5))
1240             hasExtra = FALSE;
1241          break;
1242 
1243       default:
1244          hasExtra = hasExtraInfo_eprom;
1245          break;
1246    }
1247 
1248    return hasExtra;
1249 }
1250 
1251 /**
1252  * Query to get the length in bytes of extra information that
1253  * is read when read a page in the current memory bank.  See
1254  * 'hasExtraInfoEPROM()'.
1255  *
1256  * bank     to tell what memory bank of the ibutton to use.
1257  * SNum     the serial number for the part.
1258  *
1259  * @return  number of bytes in Extra Information read when reading
1260  *          pages in the current memory bank.
1261  */
getExtraInfoLengthEPROM(SMALLINT bank,uchar * SNum)1262 SMALLINT getExtraInfoLengthEPROM(SMALLINT bank, uchar *SNum)
1263 {
1264    SMALLINT len = extraInfoLength_eprom;
1265 
1266    switch(SNum[0])
1267    {
1268       case 0x09:
1269          len = 0;
1270          break;
1271 
1272       case 0x0B:
1273          if((bank > 0) && (bank < 5))
1274             len = 0;
1275          break;
1276 
1277       case 0x0F:
1278          if((bank > 0) && (bank < 5))
1279             len = 0;
1280          break;
1281 
1282       case 0x12:
1283          if(bank == 1)
1284             len = 0;
1285          break;
1286 
1287       case 0x13:
1288          if((bank > 0) && (bank < 5))
1289             len = 0;
1290          break;
1291 
1292       default:
1293          len = extraInfoLength_eprom;
1294          break;
1295    }
1296 
1297    return len;
1298 }
1299 
1300 /**
1301  * Query to get a string description of what is contained in
1302  * the Extra Informationed return when reading pages in the current
1303  * memory bank.  See 'hasExtraInfoEPROM()'.
1304  *
1305  * bank     to tell what memory bank of the ibutton to use.
1306  * SNum     the serial number for the part.
1307  *
1308  * @return string describing extra information.
1309  */
getExtraInfoDescEPROM(SMALLINT bank,uchar * SNum)1310 char *getExtraInfoDescEPROM(SMALLINT bank, uchar *SNum)
1311 {
1312    switch(SNum[0])
1313    {
1314       case 0x09:
1315          return " ";
1316          break;
1317 
1318       case 0x0B:
1319          if((bank > 0) && (bank < 5))
1320             return " ";
1321          break;
1322 
1323       case 0x0F:
1324          if((bank > 0) && (bank < 5))
1325             return " ";
1326          break;
1327 
1328       case 0x12:
1329          if(bank == 1)
1330             return " ";
1331          break;
1332 
1333       case 0x13:
1334          if((bank > 0) && (bank < 5))
1335             return " ";
1336          break;
1337 
1338       default:
1339          return extraInfoDesc_eprom;
1340          break;
1341    }
1342 
1343 
1344    return extraInfoDesc_eprom;
1345 }
1346 
1347 /**
1348  * Query to see if current memory bank pages can be read with
1349  * the contents being verified by a device generated CRC.
1350  * This is used to see if the 'ReadPageCRCEPROM()' can be used.
1351  *
1352  * bank     to tell what memory bank of the ibutton to use.
1353  * SNum     the serial number for the part.
1354  *
1355  * @return  'true' if current memory bank can be read with self
1356  *          generated CRC.
1357  */
hasPageAutoCRCEPROM(SMALLINT bank,uchar * SNum)1358 SMALLINT hasPageAutoCRCEPROM(SMALLINT bank, uchar *SNum)
1359 {
1360    return pageAutoCRC_eprom;
1361 }
1362 
1363 /**
1364  * Query to get Maximum data page length in bytes for a packet
1365  * read or written in the current memory bank.  See the 'ReadPagePacket()'
1366  * and 'WritePagePacket()' methods.  This method is only usefull
1367  * if the current memory bank is general purpose memory.
1368  *
1369  * @return  max packet page length in bytes in current memory bank
1370  */
getMaxPacketDataLengthEPROM(SMALLINT bank,uchar * SNum)1371 SMALLINT getMaxPacketDataLengthEPROM(SMALLINT bank, uchar *SNum)
1372 {
1373    return getPageLengthEPROM(bank,SNum) - 3;
1374 }
1375 
1376 //--------
1377 //-------- OTPMemoryBank I/O methods
1378 //--------
1379 
1380 /**
1381  * Lock the specifed page in the current memory bank.  Not supported
1382  * by all devices.  See the method 'canLockPageEPROM()'.
1383  *
1384  * bank     to tell what memory bank of the ibutton to use.
1385  * portnum  the port number of the port being used for the
1386  *          1-Wire Network.
1387  * SNum     the serial number for the part.
1388  * page     the page to be locked
1389  *
1390  * @return  true if the page was locked
1391  *          false otherwise
1392  */
lockPage(SMALLINT bank,int portnum,uchar * SNum,int page)1393 SMALLINT lockPage(SMALLINT bank, int portnum, uchar *SNum, int page)
1394 {
1395    int nbyt,nbit;
1396    SMALLINT write_bank;
1397    uchar wr_byte[1];
1398 
1399    // setting the bank to write
1400    // and since all the page lock info is in
1401    // bank 1 for all the EPROM parts.
1402    write_bank = 1;
1403 
1404    if(isPageLocked(write_bank,portnum,SNum,page))
1405    {
1406       OWERROR(OWERROR_PAGE_ALREADY_LOCKED);
1407       return FALSE;
1408    }
1409 
1410    // create byte to write to mlLock to lock page
1411    nbyt    = (page >> 3);
1412    nbit    = page - (nbyt << 3);
1413 
1414    wr_byte[0] = (uchar) ~(0x01 << nbit);
1415 
1416    // write the lock bit
1417    if(!writeEPROM(write_bank,portnum,SNum,nbyt + lockOffset,wr_byte,1))
1418       return FALSE;
1419 
1420    // read back to verify
1421    if(!isPageLocked(write_bank,portnum,SNum,page))
1422    {
1423       OWERROR(OWERROR_READ_BACK_NOT_VALID);
1424       return FALSE;
1425    }
1426 
1427    return TRUE;
1428 }
1429 
1430 /**
1431  * Query to see if the specified page is locked.
1432  * See the method 'canLockPage()'.
1433  *
1434  * bank     to tell what memory bank of the ibutton to use.
1435  * portnum  the port number of the port being used for the
1436  *          1-Wire Network.
1437  * SNum     the serial number for the part.
1438  * page     the page to check if locked
1439  *
1440  * @return  true if page locked.
1441  */
isPageLocked(SMALLINT bank,int portnum,uchar * SNum,int page)1442 SMALLINT isPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page)
1443 {
1444    int pg_len, read_pg, index, nbyt, nbit;
1445    SMALLINT read_bank;
1446    uchar read_buf[PAGE_LENGTH_EPROM];
1447 
1448    // setting the bank to read for information
1449    // and since all the page lock info is in
1450    // bank 1 for all the EPROM parts.
1451    read_bank = 1;
1452 
1453    // read page that locked bit is on
1454    pg_len  = getPageLengthEPROM(read_bank,SNum);
1455    read_pg = (page + lockOffset) / (pg_len * 8);
1456 
1457    if(!readPageCRCEPROM(read_bank,portnum,SNum,read_pg,read_buf))
1458       return FALSE;
1459 
1460    // return boolean on locked bit
1461    index = (page + lockOffset) - (read_pg * 8 * pg_len);
1462    nbyt  = (index >> 3);
1463    nbit  = index - (nbyt << 3);
1464 
1465    return !(((read_buf[nbyt] >> nbit) & 0x01) == 0x01);
1466 }
1467 
1468 /**
1469  * Redirect the specifed page in the current memory bank to a new page.
1470  * Not supported by all devices.  See the method 'canRedirectPage()'.
1471  *
1472  * bank     to tell what memory bank of the ibutton to use.
1473  * portnum  the port number of the port being used for the
1474  *          1-Wire Network.
1475  * SNum     the serial number for the part.
1476  * page     the page to be locked
1477  * newPage  new page number to redirect to
1478  *
1479  * @return  true if the page was redirected
1480  */
redirectPage(SMALLINT bank,int portnum,uchar * SNum,int page,int newPage)1481 SMALLINT redirectPage(SMALLINT bank, int portnum, uchar *SNum, int page, int newPage)
1482 {
1483    uchar wr_byte[1];  // create byte to redirect page
1484    SMALLINT write_bank;
1485 
1486    if(isRedirectPageLocked(bank,portnum,SNum,page))
1487    {
1488       OWERROR(OWERROR_REDIRECTED_PAGE);
1489       return FALSE;
1490    }
1491 
1492    // setting the bank to write
1493    switch(SNum[0])
1494    {
1495       case 0x09: case 0x12:
1496          write_bank = 1;
1497          break;
1498 
1499       case 0x0B: case 0x0F: case 0x13:
1500          write_bank = 4;
1501          break;
1502 
1503       default:
1504          write_bank = 4;
1505          break;
1506    }
1507 
1508    wr_byte[0] = (uchar) ~newPage;
1509 
1510    // write the redirection byte
1511    if(!writeEPROM(write_bank,portnum,SNum,page + redirectOffset(bank,SNum),wr_byte,1))
1512       return FALSE;
1513 
1514    return TRUE;
1515 }
1516 
1517 
1518 /**
1519  * Gets the page redirection of the specified page.
1520  * Not supported by all devices.
1521  *
1522  * bank     to tell what memory bank of the ibutton to use.
1523  * portnum  the port number of the port being used for the
1524  *          1-Wire Network.
1525  * SNum     the serial number for the part.
1526  * page     number of page check for redirection
1527  *
1528  * @return  the new page number or 0 if not redirected
1529  */
getRedirectedPage(SMALLINT bank,int portnum,uchar * SNum,int page)1530 SMALLINT getRedirectedPage(SMALLINT bank, int portnum, uchar *SNum, int page)
1531 {
1532    int pg_len, read_pg;
1533    SMALLINT read_bank;
1534    uchar read_buf[PAGE_LENGTH_EPROM];
1535 
1536    // setting the bank to read for information
1537    switch(SNum[0])
1538    {
1539       case 0x09: case 0x12:
1540          read_bank = 1;
1541          break;
1542 
1543       case 0x0B: case 0x0F: case 0x13:
1544          read_bank = 4;
1545          break;
1546 
1547       default:
1548          read_bank = 4;
1549          break;
1550    }
1551 
1552    // read page that redirect byte is on
1553    pg_len  = getPageLengthEPROM(read_bank,SNum);
1554    read_pg = (page + redirectOffset(bank,SNum)) / pg_len;
1555 
1556    if(!readPageCRCEPROM(read_bank,portnum,SNum,read_pg,read_buf))
1557       return FALSE;
1558 
1559    // return page
1560    return (SMALLINT) (~read_buf[(page + redirectOffset(bank,SNum)) % pg_len] & 0x000000FF);
1561 }
1562 
1563 /**
1564  * Lock the redirection option for the specifed page in the current
1565  * memory bank. Not supported by all devices.  See the method
1566  * 'canLockRedirectPage()'.
1567  *
1568  * bank     to tell what memory bank of the ibutton to use.
1569  * portnum  the port number of the port being used for the
1570  *          1-Wire Network.
1571  * SNum     the serial number for the part.
1572  * page     number of page to redirect
1573  *
1574  * @return  true if the redirected page is locked.
1575  */
lockRedirectPage(SMALLINT bank,int portnum,uchar * SNum,int page)1576 SMALLINT lockRedirectPage(SMALLINT bank, int portnum, uchar *SNum, int page)
1577 {
1578    int nbyt, nbit;
1579    SMALLINT write_bank;
1580    uchar wr_byte[1];
1581 
1582    if(isRedirectPageLocked(bank,portnum,SNum,page))
1583    {
1584       OWERROR(OWERROR_LOCKING_REDIRECTED_PAGE_AGAIN);
1585       return FALSE;
1586    }
1587 
1588    // setting the bank to write
1589    switch(SNum[0])
1590    {
1591       case 0x0B: case 0x0F: case 0x13:
1592          write_bank = 2;
1593          break;
1594 
1595       default:
1596          write_bank = 0;
1597          break;
1598    }
1599 
1600    // create byte to write to mlLock to lock page
1601    nbyt    = (page >> 3);
1602    nbit    = page - (nbyt << 3);
1603 
1604    wr_byte[0] = (uchar) ~(0x01 << nbit);
1605 
1606    // write the lock bit
1607    if(!writeEPROM(write_bank,portnum,SNum,nbyt + lockRedirectOffset,wr_byte,1))
1608       return FALSE;
1609 
1610    // read back to verify
1611    if (!isRedirectPageLocked(bank,portnum,SNum,page) || (write_bank == 0))
1612    {
1613       OWERROR(OWERROR_COULD_NOT_LOCK_REDIRECT);
1614       return FALSE;
1615    }
1616 
1617    return TRUE;
1618 }
1619 
1620 /**
1621  * Query to see if the specified page has redirection locked.
1622  * Not supported by all devices.  See the method 'canRedirectPage()'.
1623  *
1624  * bank     to tell what memory bank of the ibutton to use.
1625  * portnum  the port number of the port being used for the
1626  *          1-Wire Network.
1627  * SNum     the serial number for the part.
1628  * page     number of page to check for redirection
1629  *
1630  * @return  true if redirection is locked for this page
1631  */
isRedirectPageLocked(SMALLINT bank,int portnum,uchar * SNum,int page)1632 SMALLINT isRedirectPageLocked(SMALLINT bank, int portnum, uchar *SNum, int page)
1633 {
1634    int pg_len, read_pg, index, nbyt, nbit;
1635    SMALLINT read_bank;
1636    uchar read_buf[PAGE_LENGTH_EPROM];
1637 
1638    // setting the bank to read for information
1639    switch(SNum[0])
1640    {
1641       case 0x0B: case 0x0F: case 0x13:
1642          read_bank = 2;
1643          break;
1644 
1645       default:
1646          return FALSE;
1647          break;
1648    }
1649 
1650    // read page that lock redirect bit is on
1651    pg_len  = getPageLengthEPROM(read_bank,SNum);
1652    read_pg = (page + lockRedirectOffset) / (pg_len * 8);
1653 
1654    if(!readPageCRCEPROM(read_bank,portnum,SNum,read_pg,read_buf))
1655       return FALSE;
1656 
1657    // return boolean on lock redirect bit
1658    index = (page + lockRedirectOffset) - (read_pg * 8 * pg_len);
1659    nbyt  = (index >> 3);
1660    nbit  = index - (nbyt << 3);
1661 
1662    return !(((read_buf[nbyt] >> nbit) & 0x01) == 0x01);
1663 }
1664 
1665 /**
1666  * Query to see if current memory bank pages can be redirected
1667  * to another pages.  This is mostly used in Write-Once memory
1668  * to provide a means to update.
1669  *
1670  * bank     to tell what memory bank of the ibutton to use.
1671  * SNum     the serial number for the part.
1672  *
1673  * @return  'true' if current memory bank pages can be redirected
1674  *          to a new page.
1675  */
canRedirectPageEPROM(SMALLINT bank,uchar * SNum)1676 SMALLINT canRedirectPageEPROM(SMALLINT bank, uchar *SNum)
1677 {
1678    SMALLINT canRedirect = canredirectPage;
1679 
1680    switch(SNum[0])
1681    {
1682       case 0x09:
1683          if(bank == 0)
1684             canRedirect = TRUE;
1685          break;
1686 
1687       case 0x0B:
1688          if(bank == 0)
1689             canRedirect = TRUE;
1690          break;
1691 
1692       case 0x0F:
1693          if(bank == 0)
1694             canRedirect = TRUE;
1695          break;
1696 
1697       case 0x12:
1698          if(bank == 0)
1699             canRedirect = TRUE;
1700          break;
1701 
1702       case 0x13:
1703          if(bank == 0)
1704             canRedirect = TRUE;
1705          break;
1706 
1707       default:
1708          canRedirect = canredirectPage;
1709          break;
1710    }
1711 
1712    return canRedirect;
1713 }
1714 
1715 /**
1716  * Query to see if current memory bank pages can be locked.  A
1717  * locked page would prevent any changes to the memory.
1718  *
1719  * bank     to tell what memory bank of the ibutton to use.
1720  * SNum     the serial number for the part.
1721  *
1722  * @return  'true' if current memory bank pages can be redirected
1723  *          to a new page.
1724  */
canLockPageEPROM(SMALLINT bank,uchar * SNum)1725 SMALLINT canLockPageEPROM(SMALLINT bank, uchar *SNum)
1726 {
1727    SMALLINT canLock = canlockPage;
1728 
1729    switch(SNum[0])
1730    {
1731       case 0x09:
1732          if(bank == 0)
1733             canLock = TRUE;
1734          break;
1735 
1736       case 0x0B:
1737          if(bank == 0)
1738             canLock = TRUE;
1739          break;
1740 
1741       case 0x0F:
1742          if(bank == 0)
1743             canLock = TRUE;
1744          break;
1745 
1746       case 0x12:
1747          if(bank == 0)
1748             canLock = TRUE;
1749          break;
1750 
1751       case 0x13:
1752          if(bank == 0)
1753             canLock = TRUE;
1754          break;
1755 
1756       default:
1757          canLock = canlockPage;
1758          break;
1759    }
1760 
1761    return canLock;
1762 }
1763 
1764 /**
1765  * Query to see if current memory bank pages can be locked from
1766  * being redirected.  This would prevent a Write-Once memory from
1767  * being updated.
1768  *
1769  * bank     to tell what memory bank of the ibutton to use.
1770  * SNum     the serial number for the part.
1771  *
1772  * @return  'true' if current memory bank pages can be locked from
1773  *          being redirected to a new page.
1774  */
canLockRedirectPageEPROM(SMALLINT bank,uchar * SNum)1775 SMALLINT canLockRedirectPageEPROM(SMALLINT bank, uchar *SNum)
1776 {
1777    SMALLINT lockRedirect = canlockRedirectPage;
1778 
1779    switch(SNum[0])
1780    {
1781       case 0x0B:
1782          if(bank == 0)
1783             lockRedirect = TRUE;
1784          break;
1785 
1786       case 0x0F:
1787          if(bank == 0)
1788             lockRedirect = TRUE;
1789          break;
1790 
1791       case 0x13:
1792          if(bank == 0)
1793             lockRedirect = TRUE;
1794          break;
1795 
1796       default:
1797          lockRedirect = canlockRedirectPage;
1798          break;
1799    }
1800 
1801    return lockRedirect;
1802 }
1803 
1804 
1805 //--------
1806 //-------- Local functions
1807 //--------
1808 
1809 /**
1810  * Send the command for writing to memory for a device given
1811  * the memory bank and serial number.
1812  *
1813  * bank     to tell what memory bank of the ibutton to use.
1814  * SNum     the serial number for the part.
1815  *
1816  * @return  the command for writing to the memory bank.
1817  */
writeMemCmd(SMALLINT bank,uchar * SNum)1818 uchar writeMemCmd(SMALLINT bank, uchar *SNum)
1819 {
1820    uchar command = MAIN_WRITE_COMMAND_EPROM;
1821 
1822    switch(SNum[0])
1823    {
1824       case 0x09:
1825          if(bank == 1)
1826             command = STATUS_WRITE_COMMAND_EPROM;
1827          break;
1828 
1829       case 0x0B:
1830          if((bank > 0) && (bank < 5))
1831             command = STATUS_WRITE_COMMAND_EPROM;
1832          break;
1833 
1834       case 0x0F:
1835          if((bank > 0) && (bank < 5))
1836             command = STATUS_WRITE_COMMAND_EPROM;
1837          break;
1838 
1839       case 0x12:
1840          if(bank == 1)
1841             command = STATUS_WRITE_COMMAND_EPROM;
1842          break;
1843 
1844       case 0x13:
1845          if((bank > 0) && (bank < 5))
1846             command = STATUS_WRITE_COMMAND_EPROM;
1847          break;
1848 
1849       default:
1850          command = MAIN_WRITE_COMMAND_EPROM;
1851          break;
1852    }
1853 
1854    return command;
1855 }
1856 
1857 /**
1858  * Get the number of CRC bytes for the device.
1859  *
1860  * bank     to tell what memory bank of the ibutton to use.
1861  * SNum     the serial number for the part.
1862  *
1863  * @return  the number of CRC bytes.
1864  */
numCRCbytes(SMALLINT bank,uchar * SNum)1865 SMALLINT numCRCbytes(SMALLINT bank, uchar *SNum)
1866 {
1867    SMALLINT numbytes = CRCbytes;
1868 
1869    switch(SNum[0])
1870    {
1871       case 0x09:
1872          if((bank == 0) || (bank == 1))
1873             numbytes = 1;
1874          break;
1875 
1876       default:
1877          numbytes = CRCbytes;
1878          break;
1879    }
1880 
1881    return numbytes;
1882 }
1883 
1884 /**
1885  * Get the status of the page the pages write verification
1886  *
1887  * bank     to tell what memory bank of the ibutton to use.
1888  * SNum     the serial number for the part.
1889  *
1890  * @return  true if write verification is used and
1891  *          false if it is not used.
1892  */
writeVerify(SMALLINT bank,int portnum,uchar * SNum,int page)1893 SMALLINT writeVerify(SMALLINT bank, int portnum, uchar *SNum, int page)
1894 {
1895    if(isPageLocked(bank,portnum,SNum,page) ||
1896       isRedirectPageLocked(bank,portnum,SNum,page))
1897       return FALSE;
1898 
1899    return writeVerification_eprom;
1900 }
1901 
1902 /**
1903  * Get crc after sending command,address
1904  *
1905  * bank     to tell what memory bank of the ibutton to use.
1906  * SNum     the serial number for the part.
1907  *
1908  * @return  true if crc is can be gotten after sending command,address
1909  *          false otherwise
1910  */
crcAfterAdd(SMALLINT bank,uchar * SNum)1911 SMALLINT crcAfterAdd(SMALLINT bank, uchar *SNum)
1912 {
1913    SMALLINT crcAfter = TRUE;
1914 
1915    switch(SNum[0])
1916    {
1917       case 0x0B:
1918          if((bank > 0) && (bank < 5))
1919             crcAfter = FALSE;
1920          break;
1921 
1922       case 0x0F:
1923          if((bank > 0) && (bank < 5))
1924             crcAfter = FALSE;
1925          break;
1926 
1927       case 0x12:
1928          if(bank == 1)
1929             crcAfter = FALSE;
1930          break;
1931 
1932       case 0x13:
1933          if((bank > 0) && (bank < 5))
1934             crcAfter = FALSE;
1935          break;
1936 
1937       default:
1938          crcAfter = TRUE;
1939          break;
1940    }
1941 
1942    return crcAfter;
1943 }
1944 
1945 /**
1946  * Get the byte command for reading the page with crc.
1947  *
1948  * bank     to tell what memory bank of the ibutton to use.
1949  * SNum     the serial number for the part.
1950  *
1951  * @return  the byte command for reading the page
1952  */
readPageWithCRC(SMALLINT bank,uchar * SNum)1953 uchar readPageWithCRC(SMALLINT bank, uchar *SNum)
1954 {
1955    uchar readPage = MAIN_READ_PAGE_COMMAND_EPROM;
1956 
1957    switch(SNum[0])
1958    {
1959       case 0x09:
1960          if(bank == 0)
1961             readPage = 0xC3;
1962          else if(bank == 1)
1963             readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1964          break;
1965 
1966       case 0x0B:
1967          if((bank > 0) && (bank < 5))
1968             readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1969          break;
1970 
1971       case 0x0F:
1972          if((bank > 0) && (bank < 5))
1973             readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1974          break;
1975 
1976       case 0x12:
1977          if(bank == 1)
1978             readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1979          break;
1980 
1981       case 0x13:
1982          if((bank > 0) && (bank < 5))
1983             readPage = STATUS_READ_PAGE_COMMAND_EPROM;
1984          break;
1985 
1986       default:
1987          readPage = MAIN_READ_PAGE_COMMAND_EPROM;
1988          break;
1989    }
1990 
1991    return readPage;
1992 }
1993 
1994 /**
1995  * Get the offset into the redirection status information.
1996  *
1997  * bank     to tell what memory bank of the ibutton to use.
1998  * SNum     the serial number for the part.
1999  *
2000  * @return  the offset into the redirection status
2001  */
redirectOffset(SMALLINT bank,uchar * SNum)2002 SMALLINT redirectOffset(SMALLINT bank, uchar *SNum)
2003 {
2004    int offset = 0;
2005 
2006    switch(SNum[0])
2007    {
2008       case 0x09:
2009          if(bank == 0)
2010             offset = 1;
2011          break;
2012 
2013       case 0x12:
2014          if(bank == 0)
2015             offset = 1;
2016          break;
2017 
2018       default:
2019          offset = 0;
2020          break;
2021    }
2022 
2023    return offset;
2024 }
2025