diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c | 337 | ||||
-rw-r--r-- | firmware/target/arm/tms320dm320/creative-zvm/ata-target.h | 24 |
2 files changed, 316 insertions, 45 deletions
diff --git a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c index 1732c5d2c4..5f325a5e54 100644 --- a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c +++ b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c | |||
@@ -31,7 +31,10 @@ | |||
31 | #include "ata.h" | 31 | #include "ata.h" |
32 | #include "string.h" | 32 | #include "string.h" |
33 | 33 | ||
34 | void sleep_ms(int ms) | 34 | #undef ata_read_sectors |
35 | #undef ata_write_sectors | ||
36 | |||
37 | static void sleep_ms(int ms) | ||
35 | { | 38 | { |
36 | sleep(ms*HZ/1000); | 39 | sleep(ms*HZ/1000); |
37 | } | 40 | } |
@@ -99,7 +102,7 @@ bool ata_is_coldstart(void) | |||
99 | void ata_device_init(void) | 102 | void ata_device_init(void) |
100 | { | 103 | { |
101 | IO_INTC_EINT1 |= INTR_EINT1_EXT2; /* enable GIO2 interrupt */ | 104 | IO_INTC_EINT1 |= INTR_EINT1_EXT2; /* enable GIO2 interrupt */ |
102 | //TODO: mimic OF inits... | 105 | /* TODO: mimic OF inits... */ |
103 | return; | 106 | return; |
104 | } | 107 | } |
105 | 108 | ||
@@ -114,38 +117,308 @@ void GIO2(void) | |||
114 | 117 | ||
115 | /* | 118 | /* |
116 | --------------------------------------------------------------------------- | 119 | --------------------------------------------------------------------------- |
117 | Creative File Systems parsing code | 120 | CreativeFileSystem parsing/handling code |
118 | --------------------------------------------------------------------------- | 121 | --------------------------------------------------------------------------- |
119 | */ | 122 | */ |
120 | 123 | ||
124 | #define VFAT_SECTOR_SIZE ( (1*1024*1024*1024)/0x8000 ) /* 1GB array requires 80kB of RAM */ | ||
125 | |||
126 | extern int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf); | ||
127 | extern int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf); | ||
128 | |||
121 | struct main_header | 129 | struct main_header |
122 | { | 130 | { |
123 | char mblk[4]; | 131 | char mblk[4]; |
124 | unsigned char sector_size[4]; | 132 | unsigned int sector_size; |
125 | unsigned char disk_size[8]; | 133 | long long disk_size; |
126 | struct partition_header | 134 | struct partition_header |
127 | { | 135 | { |
128 | unsigned char end[4]; | 136 | unsigned long end; |
129 | unsigned char start[4]; | 137 | unsigned long start; |
130 | char name[8]; | 138 | char name[8]; |
131 | } partitions[31]; | 139 | } partitions[31]; |
132 | }; | 140 | }; |
133 | 141 | ||
142 | struct cfs_header | ||
143 | { | ||
144 | unsigned int unk; | ||
145 | unsigned int unk2; | ||
146 | unsigned int sector_size; | ||
147 | unsigned int unk4; | ||
148 | unsigned int unk5; | ||
149 | char identifier[4]; | ||
150 | unsigned int first_inode; | ||
151 | unsigned int unk8; | ||
152 | unsigned int unk9; | ||
153 | unsigned int unk10; | ||
154 | unsigned int unk11; | ||
155 | }; | ||
156 | |||
157 | struct cfs_inode | ||
158 | { | ||
159 | unsigned char magic[4]; | ||
160 | unsigned int number; | ||
161 | unsigned int parent; | ||
162 | unsigned int unk; | ||
163 | unsigned int type; | ||
164 | unsigned int created_time; | ||
165 | unsigned int lastmodified_time; | ||
166 | unsigned int unk2; | ||
167 | unsigned int first_class_chain[12]; | ||
168 | unsigned int unk3; | ||
169 | unsigned int unk4; | ||
170 | unsigned int second_class_chain_first_cluster; | ||
171 | unsigned int unk9; | ||
172 | unsigned int unk10; | ||
173 | unsigned int second_class_chain_second_cluster; | ||
174 | unsigned int unk11; | ||
175 | unsigned int unk12; | ||
176 | unsigned int unk13; | ||
177 | unsigned int filesize; | ||
178 | unsigned int serial_number; | ||
179 | unsigned int number_of_metadata_records; | ||
180 | }; | ||
181 | |||
182 | struct cfs_direntry | ||
183 | { | ||
184 | unsigned char identifier[4]; | ||
185 | unsigned int unk; | ||
186 | unsigned int items; | ||
187 | unsigned int unk2; | ||
188 | unsigned char maxlen[2]; | ||
189 | unsigned char padding[202]; | ||
190 | /* struct cfs_direntry_item _items[items]; */ | ||
191 | }; | ||
192 | struct cfs_direntry_item | ||
193 | { | ||
194 | unsigned int inode_number; | ||
195 | unsigned short strlen; | ||
196 | unsigned short bytesperchar; | ||
197 | char string[32]; | ||
198 | }; | ||
199 | |||
200 | static bool cfs_inited = false; | ||
201 | static unsigned long cfs_start; | ||
202 | static unsigned long sectors[VFAT_SECTOR_SIZE]; | ||
203 | |||
204 | #define CFS_START ( ((hdr->partitions[1].start*hdr->sector_size) & ~0xFFFF) + 0x10000 ) | ||
205 | #define CFS_CLUSTER2CLUSTER(x) ( CFS_START+((x)-1)*64 ) | ||
206 | |||
207 | /* Limited version of UCS -> ASCII */ | ||
208 | static char* ucs2letostring(unsigned char* s) | ||
209 | { | ||
210 | static char res[256]; | ||
211 | int i; | ||
212 | |||
213 | for(i=0; (s[i] == 0 && s[i+1] == 0); i++) | ||
214 | res[i] = s[i*2]; | ||
215 | |||
216 | return (char*)&res; | ||
217 | } | ||
218 | |||
219 | static void cfs_init(void) | ||
220 | { | ||
221 | struct main_header *hdr; | ||
222 | struct cfs_header *cfs; | ||
223 | struct cfs_inode *root_inode, *vfat_inode, *inode; | ||
224 | struct cfs_direntry *root_direntry, *vfat_direntry; | ||
225 | struct cfs_direntry_item *root_direntry_items, *vfat_direntry_items; | ||
226 | unsigned int i, j, k, vfat_inode_nr=0, vfat_inodes_nr[10], vfat_sector_count; | ||
227 | unsigned char sector[512]; | ||
228 | static unsigned int vfat_data[2][0x8000]; | ||
229 | static unsigned char sector2[0x8000]; | ||
230 | |||
231 | if(cfs_inited) | ||
232 | return; | ||
233 | |||
234 | /* Read MBLK */ | ||
235 | _ata_read_sectors(0, 1, §or); | ||
236 | hdr = (struct main_header*)§or; | ||
237 | |||
238 | //printf("CFS is at 0x%x", CFS_START); | ||
239 | |||
240 | /* Read CFS header */ | ||
241 | _ata_read_sectors(CFS_START/512, 64, §or2); | ||
242 | cfs = (struct cfs_header*)§or2; | ||
243 | |||
244 | //printf("First inode = %d", cfs->first_inode); | ||
245 | |||
246 | /* Read root inode */ | ||
247 | _ata_read_sectors(CFS_CLUSTER2CLUSTER(cfs->first_inode), 64, §or2); | ||
248 | root_inode = (struct cfs_inode*)§or2; | ||
249 | |||
250 | /* Read root inode's first sector */ | ||
251 | _ata_read_sectors(CFS_CLUSTER2CLUSTER(root_inode->first_class_chain[0]), 64, §or2); | ||
252 | root_direntry = (struct cfs_direntry*)§or2; | ||
253 | root_direntry_items = (struct cfs_direntry_item*)(§or2+sizeof(struct cfs_direntry)); | ||
254 | |||
255 | /* Search VFAT inode */ | ||
256 | for(i=0; i < root_direntry->items; i++) | ||
257 | { | ||
258 | //printf(" * [%s] at 0x%x\n", ucs2letostring(&root_direntry_items[i].string[0]), root_direntry_items[i].inode_number); | ||
259 | if(strcmp(ucs2letostring(&root_direntry_items[i].string[0]), "VFAT") == 0) | ||
260 | vfat_inode_nr = root_direntry_items[i].inode_number; | ||
261 | } | ||
262 | |||
263 | /* Read VFAT inode */ | ||
264 | _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_inode_nr), 64, §or2); | ||
265 | vfat_inode = (struct cfs_inode*)§or2; | ||
266 | |||
267 | /* Read VFAT inode's first sector */ | ||
268 | _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_inode->first_class_chain[0]), 64, §or2); | ||
269 | vfat_direntry = (struct cfs_direntry*)§or2; | ||
270 | vfat_direntry_items = (struct cfs_direntry_item*)(§or2+sizeof(struct cfs_direntry)); | ||
271 | |||
272 | /* Search for VFAT's subinodes */ | ||
273 | for(i=0; i < vfat_direntry->items; i++) | ||
274 | { | ||
275 | //printf(" * [%s] at 0x%x\n", ucs2letostring(&vfat_direntry_items[i].string[0]), vfat_direntry_items[i].inode_number); | ||
276 | if(i > 0) | ||
277 | vfat_inodes_nr[i-1] = vfat_direntry_items[i].inode_number; | ||
278 | } | ||
279 | |||
280 | /* Read all data sectors' addresses in memory */ | ||
281 | vfat_sector_count = 0; | ||
282 | memset(§ors, 0, VFAT_SECTOR_SIZE*sizeof(unsigned int)); | ||
283 | for(i=0; vfat_inodes_nr[i] != 0; i++) | ||
284 | { | ||
285 | _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_inodes_nr[i]), 1, §or); | ||
286 | inode = (struct cfs_inode*)§or; | ||
287 | |||
288 | /* Read second & third class chain */ | ||
289 | _ata_read_sectors(CFS_CLUSTER2CLUSTER(inode->second_class_chain_first_cluster), 64, &vfat_data[0]); | ||
290 | _ata_read_sectors(CFS_CLUSTER2CLUSTER(inode->second_class_chain_second_cluster), 64, &vfat_data[1]); | ||
291 | |||
292 | /* First class chain */ | ||
293 | for(j=0; j<12; j++) | ||
294 | { | ||
295 | if( (inode->first_class_chain[j] & 0xFFFF) != 0xFFFF && | ||
296 | inode->first_class_chain[j] != 0 | ||
297 | ) | ||
298 | sectors[vfat_sector_count++] = inode->first_class_chain[j]; | ||
299 | } | ||
300 | |||
301 | /* Second class chain */ | ||
302 | for(j=0; j<0x8000/4; j++) | ||
303 | { | ||
304 | if( (vfat_data[0][j] & 0xFFFF) != 0xFFFF && | ||
305 | vfat_data[0][j] != 0 | ||
306 | ) | ||
307 | sectors[vfat_sector_count++] = vfat_data[0][j]; | ||
308 | } | ||
309 | |||
310 | /* Third class chain */ | ||
311 | for(j=0; j<0x8000/4; j++) | ||
312 | { | ||
313 | if( (vfat_data[1][j] & 0xFFFF) != 0xFFFF && | ||
314 | vfat_data[1][j] != 0 | ||
315 | ) | ||
316 | { | ||
317 | memset(&vfat_data[0], 0, 0x8000*sizeof(unsigned int)); | ||
318 | |||
319 | /* Read third class subchain(s) */ | ||
320 | _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_data[1][j]), 64, &vfat_data[0]); | ||
321 | |||
322 | for(k=0; k<0x8000/4; k++) | ||
323 | { | ||
324 | if( (vfat_data[0][k] & 0xFFFF) != 0xFFFF && | ||
325 | vfat_data[0][k] != 0 | ||
326 | ) | ||
327 | sectors[vfat_sector_count++] = vfat_data[0][k]; | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | //printf("Sector count: %d 0x%x", vfat_sector_count, vfat_sector_count); | ||
334 | |||
335 | cfs_inited = true; | ||
336 | } | ||
337 | |||
338 | static inline unsigned long map_sector(unsigned long sector) | ||
339 | { | ||
340 | /* | ||
341 | * Sector mapping: start of CFS + FAT_SECTOR2CFS_SECTOR(sector) + missing part | ||
342 | * FAT works with sectors of 0x200 bytes, CFS with sectors of 0x8000 bytes. | ||
343 | */ | ||
344 | return cfs_start+sectors[sector/64]*64+sector%64; | ||
345 | } | ||
346 | |||
347 | int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf) | ||
348 | { | ||
349 | if(!cfs_inited) | ||
350 | cfs_init(); | ||
351 | |||
352 | /* Check if count is lesser than or equal to 1 native CFS sector */ | ||
353 | if(count <= 64) | ||
354 | return _ata_read_sectors(IF_MV2(drive,) map_sector(start), count, buf); | ||
355 | else | ||
356 | { | ||
357 | int i, ret; | ||
358 | unsigned char* dest = (unsigned char*)buf; | ||
359 | |||
360 | /* Read sectors in parts of 0x8000 */ | ||
361 | for(i=0; i<count; i+=64) | ||
362 | { | ||
363 | ret = _ata_read_sectors(IF_MV2(drive,) map_sector(start+i), (count-i >= 64 ? 64 : count-i), (void*)dest); | ||
364 | if(ret != 0) | ||
365 | return ret; | ||
366 | |||
367 | dest += (count-i >= 64 ? 0x8000 : (count-i)*512); | ||
368 | } | ||
369 | |||
370 | return ret; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf) | ||
375 | { | ||
376 | if(!cfs_inited) | ||
377 | cfs_init(); | ||
378 | |||
379 | /* Check if count is lesser than or equal to 1 native CFS sector */ | ||
380 | if(count <= 64) | ||
381 | return _ata_write_sectors(IF_MV2(drive,) map_sector(start), count, buf); | ||
382 | else | ||
383 | { | ||
384 | int i, ret; | ||
385 | unsigned char* dest = (unsigned char*)buf; | ||
386 | |||
387 | /* Read sectors in parts of 0x8000 */ | ||
388 | for(i=0; i<count; i+=64) | ||
389 | { | ||
390 | ret = _ata_write_sectors(IF_MV2(drive,) map_sector(start+i), (count-i >= 64 ? 64 : count-i), (const void*)dest); | ||
391 | if(ret != 0) | ||
392 | return ret; | ||
393 | |||
394 | dest += (count-i >= 64 ? 0x8000 : (count-i)*512); | ||
395 | } | ||
396 | |||
397 | return ret; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | --------------------------------------------------------------------------- | ||
403 | MiniFileSystem parsing code | ||
404 | --------------------------------------------------------------------------- | ||
405 | */ | ||
406 | |||
134 | struct minifs_file | 407 | struct minifs_file |
135 | { | 408 | { |
136 | char name[0x10]; | 409 | char name[0x10]; |
137 | unsigned char unk[4]; | 410 | unsigned int unk; |
138 | unsigned char size[4]; | 411 | unsigned long size; |
139 | unsigned char chain1[4]; | 412 | unsigned int chain1; |
140 | unsigned char chain2[4]; | 413 | unsigned int chain2; |
141 | }; | 414 | }; |
142 | 415 | ||
143 | struct minifs_chain | 416 | struct minifs_chain |
144 | { | 417 | { |
145 | unsigned char unknown[4]; | 418 | unsigned int unknown; |
146 | unsigned char chain[2*0x27FE]; | 419 | unsigned short chain[0x27FE]; |
147 | unsigned char unknown2[4]; | 420 | unsigned int unknown2; |
148 | unsigned char length[4]; | 421 | unsigned long length; |
149 | }; | 422 | }; |
150 | 423 | ||
151 | 424 | ||
@@ -160,16 +433,6 @@ struct minifs_chain | |||
160 | #define CLUSTER_CHAIN_CHAIN 0x0002 | 433 | #define CLUSTER_CHAIN_CHAIN 0x0002 |
161 | 434 | ||
162 | 435 | ||
163 | static unsigned short le2int16(unsigned char* buf) | ||
164 | { | ||
165 | return (buf[1] << 8) | buf[0]; | ||
166 | } | ||
167 | |||
168 | static unsigned int le2int32(unsigned char* buf) | ||
169 | { | ||
170 | return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
171 | } | ||
172 | |||
173 | int load_minifs_file(char* filename, unsigned char* location) | 436 | int load_minifs_file(char* filename, unsigned char* location) |
174 | { | 437 | { |
175 | struct main_header *hdr; | 438 | struct main_header *hdr; |
@@ -180,13 +443,13 @@ int load_minifs_file(char* filename, unsigned char* location) | |||
180 | unsigned char sector[512]; | 443 | unsigned char sector[512]; |
181 | static unsigned char chain_data[42*512]; /* stack overflow if not static */ | 444 | static unsigned char chain_data[42*512]; /* stack overflow if not static */ |
182 | 445 | ||
183 | /* Reading MBLK */ | 446 | /* Read MBLK */ |
184 | ata_read_sectors(0, 1, §or); | 447 | _ata_read_sectors(0, 1, §or); |
185 | hdr = (struct main_header*)§or; | 448 | hdr = (struct main_header*)§or; |
186 | 449 | ||
187 | /* Reading directory listing */ | 450 | /* Read directory listing */ |
188 | #define CLUSTER2SECTOR(x) ( (le2int32(hdr->partitions[0].start) + (x)*8) ) | 451 | #define CLUSTER2SECTOR(x) ( (hdr->partitions[0].start + (x)*8) ) |
189 | ata_read_sectors(CLUSTER2SECTOR(DIR_START), 8, &files); | 452 | _ata_read_sectors(CLUSTER2SECTOR(DIR_START), 8, &files); |
190 | 453 | ||
191 | for(i=0; i<127; i++) | 454 | for(i=0; i<127; i++) |
192 | { | 455 | { |
@@ -200,17 +463,17 @@ int load_minifs_file(char* filename, unsigned char* location) | |||
200 | #define GET_CHAIN(x) ( CLUSTER2SECTOR(CLUSTER_CHAIN_CHAIN)*512 + (x)*CLUSTER_CHAIN_SIZE ) | 463 | #define GET_CHAIN(x) ( CLUSTER2SECTOR(CLUSTER_CHAIN_CHAIN)*512 + (x)*CLUSTER_CHAIN_SIZE ) |
201 | #define FILE2SECTOR(x) ( CLUSTER2SECTOR(DATASPACE_START + (x)) ) | 464 | #define FILE2SECTOR(x) ( CLUSTER2SECTOR(DATASPACE_START + (x)) ) |
202 | 465 | ||
203 | /* Reading chain list */ | 466 | /* Read chain list */ |
204 | ata_read_sectors(GET_CHAIN(le2int32(files[found].chain1))/512, 41, &chain_data[0]); | 467 | _ata_read_sectors(GET_CHAIN(files[found].chain1)/512, 41, &chain_data[0]); |
205 | 468 | ||
206 | chain = (struct minifs_chain*)&chain_data[GET_CHAIN(le2int32(files[found].chain1))%512]; | 469 | chain = (struct minifs_chain*)&chain_data[GET_CHAIN(files[found].chain1)%512]; |
207 | 470 | ||
208 | /* Copying data */ | 471 | /* Copy data */ |
209 | for(i=0; i<le2int32(chain->length); i++) | 472 | for(i=0; i<chain->length; i++) |
210 | { | 473 | { |
211 | ata_read_sectors(FILE2SECTOR(le2int16(&chain->chain[i*2])), 8, location); | 474 | _ata_read_sectors(FILE2SECTOR(chain->chain[i]), 8, location); |
212 | location += 0x1000; | 475 | location += 0x1000; |
213 | } | 476 | } |
214 | 477 | ||
215 | return le2int32(files[found].size); | 478 | return files[found].size; |
216 | } | 479 | } |
diff --git a/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h b/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h index 6e5699e887..ba877a1496 100644 --- a/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h +++ b/firmware/target/arm/tms320dm320/creative-zvm/ata-target.h | |||
@@ -22,6 +22,8 @@ | |||
22 | #ifndef ATA_TARGET_H | 22 | #ifndef ATA_TARGET_H |
23 | #define ATA_TARGET_H | 23 | #define ATA_TARGET_H |
24 | 24 | ||
25 | #include "ata.h" | ||
26 | |||
25 | /* DMA optimized reading and writing */ | 27 | /* DMA optimized reading and writing */ |
26 | #define ATA_OPTIMIZED_READING | 28 | #define ATA_OPTIMIZED_READING |
27 | #define ATA_OPTIMIZED_WRITING | 29 | #define ATA_OPTIMIZED_WRITING |
@@ -33,6 +35,12 @@ | |||
33 | void copy_read_sectors(const unsigned char* buf, int wordcount); | 35 | void copy_read_sectors(const unsigned char* buf, int wordcount); |
34 | void copy_write_sectors(const unsigned char* buf, int wordcount); | 36 | void copy_write_sectors(const unsigned char* buf, int wordcount); |
35 | 37 | ||
38 | /* Nasty hack, but Creative is nasty... */ | ||
39 | #define ata_read_sectors _ata_read_sectors | ||
40 | #define ata_write_sectors _ata_write_sectors | ||
41 | extern int _ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf); | ||
42 | extern int _ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf); | ||
43 | |||
36 | /* General purpose memory region #1 */ | 44 | /* General purpose memory region #1 */ |
37 | #define ATA_IOBASE 0x50FEE000 | 45 | #define ATA_IOBASE 0x50FEE000 |
38 | #define ATA_DATA (*((volatile unsigned short*)(ATA_IOBASE))) | 46 | #define ATA_DATA (*((volatile unsigned short*)(ATA_IOBASE))) |
@@ -52,15 +60,15 @@ void copy_write_sectors(const unsigned char* buf, int wordcount); | |||
52 | #define STATUS_ERR 0x01 | 60 | #define STATUS_ERR 0x01 |
53 | #define ERROR_ABRT 0x04 | 61 | #define ERROR_ABRT 0x04 |
54 | 62 | ||
55 | #define WRITE_PATTERN1 0xa5 | 63 | #define WRITE_PATTERN1 0xa5 |
56 | #define WRITE_PATTERN2 0x5a | 64 | #define WRITE_PATTERN2 0x5a |
57 | #define WRITE_PATTERN3 0xaa | 65 | #define WRITE_PATTERN3 0xaa |
58 | #define WRITE_PATTERN4 0x55 | 66 | #define WRITE_PATTERN4 0x55 |
59 | 67 | ||
60 | #define READ_PATTERN1 0xa5 | 68 | #define READ_PATTERN1 0xa5 |
61 | #define READ_PATTERN2 0x5a | 69 | #define READ_PATTERN2 0x5a |
62 | #define READ_PATTERN3 0xaa | 70 | #define READ_PATTERN3 0xaa |
63 | #define READ_PATTERN4 0x55 | 71 | #define READ_PATTERN4 0x55 |
64 | 72 | ||
65 | #define READ_PATTERN1_MASK 0xff | 73 | #define READ_PATTERN1_MASK 0xff |
66 | #define READ_PATTERN2_MASK 0xff | 74 | #define READ_PATTERN2_MASK 0xff |