aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/Kconfig7
-rw-r--r--fs/jffs2/Makefile3
-rw-r--r--fs/jffs2/erase.c13
-rw-r--r--fs/jffs2/fs.c21
-rw-r--r--fs/jffs2/os-linux.h18
-rw-r--r--fs/jffs2/scan.c11
-rw-r--r--fs/jffs2/wbuf.c35
-rw-r--r--include/linux/jffs2_fs_sb.h4
-rw-r--r--include/mtd/mtd-abi.h3
9 files changed, 98 insertions, 17 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index 6a4ad4bb7a5..07835d24c78 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1084,6 +1084,13 @@ config JFFS2_FS_NOR_ECC
1084 ECC for JFFS2. This type of flash chip is not common, however it is 1084 ECC for JFFS2. This type of flash chip is not common, however it is
1085 available from ST Microelectronics. 1085 available from ST Microelectronics.
1086 1086
1087config JFFS2_FS_DATAFLASH
1088 bool "JFFS2 support for DataFlash (EXPERIMENTAL)"
1089 depends on JFFS2_FS && EXPERIMENTAL
1090 default n
1091 help
1092 This enables the experimental support for JFFS2 on DataFlash devices.
1093
1087config JFFS2_COMPRESSION_OPTIONS 1094config JFFS2_COMPRESSION_OPTIONS
1088 bool "Advanced compression options for JFFS2" 1095 bool "Advanced compression options for JFFS2"
1089 depends on JFFS2_FS 1096 depends on JFFS2_FS
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index e3c38ccf9c7..6c2ebe176b4 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -1,7 +1,7 @@
1# 1#
2# Makefile for the Linux Journalling Flash File System v2 (JFFS2) 2# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
3# 3#
4# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $ 4# $Id: Makefile.common,v 1.8 2005/02/09 09:17:40 pavlov Exp $
5# 5#
6 6
7obj-$(CONFIG_JFFS2_FS) += jffs2.o 7obj-$(CONFIG_JFFS2_FS) += jffs2.o
@@ -13,6 +13,7 @@ jffs2-y += super.o
13 13
14jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o 14jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o
15jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o 15jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o
16jffs2-$(CONFIG_JFFS2_FS_DATAFLASH) += wbuf.o
16jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o 17jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
17jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o 18jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
18jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o 19jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index ae858f87887..a3c6cc15049 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: erase.c,v 1.70 2005/02/09 09:09:01 pavlov Exp $ 10 * $Id: erase.c,v 1.71 2005/02/09 09:17:40 pavlov Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -310,7 +310,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
310 int ret; 310 int ret;
311 uint32_t bad_offset; 311 uint32_t bad_offset;
312 312
313 if (!jffs2_cleanmarker_oob(c)) { 313 if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) {
314 marker_ref = jffs2_alloc_raw_node_ref(); 314 marker_ref = jffs2_alloc_raw_node_ref();
315 if (!marker_ref) { 315 if (!marker_ref) {
316 printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); 316 printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
@@ -351,7 +351,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
351 bad_offset += i; 351 bad_offset += i;
352 printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset); 352 printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
353 bad: 353 bad:
354 if (!jffs2_cleanmarker_oob(c)) 354 if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0))
355 jffs2_free_raw_node_ref(marker_ref); 355 jffs2_free_raw_node_ref(marker_ref);
356 kfree(ebuf); 356 kfree(ebuf);
357 bad2: 357 bad2:
@@ -387,6 +387,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
387 jeb->used_size = 0; 387 jeb->used_size = 0;
388 jeb->dirty_size = 0; 388 jeb->dirty_size = 0;
389 jeb->wasted_size = 0; 389 jeb->wasted_size = 0;
390 } else if (c->cleanmarker_size == 0) {
391 jeb->first_node = jeb->last_node = NULL;
392
393 jeb->free_size = c->sector_size;
394 jeb->used_size = 0;
395 jeb->dirty_size = 0;
396 jeb->wasted_size = 0;
390 } else { 397 } else {
391 struct kvec vecs[1]; 398 struct kvec vecs[1];
392 struct jffs2_unknown_node marker = { 399 struct jffs2_unknown_node marker = {
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 30ab233fe42..5b7c960a047 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $ 10 * $Id: fs.c,v 1.52 2005/02/09 09:17:40 pavlov Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -456,6 +456,12 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
456 return -EINVAL; 456 return -EINVAL;
457 } 457 }
458#endif 458#endif
459#ifndef CONFIG_JFFS2_FS_DATAFLASH
460 if (c->mtd->type == MTD_DATAFLASH) {
461 printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n");
462 return -EINVAL;
463 }
464#endif
459 465
460 c->flash_size = c->mtd->size; 466 c->flash_size = c->mtd->size;
461 467
@@ -661,6 +667,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) {
661 if (ret) 667 if (ret)
662 return ret; 668 return ret;
663 } 669 }
670
671 /* and Dataflash */
672 if (jffs2_dataflash(c)) {
673 ret = jffs2_dataflash_setup(c);
674 if (ret)
675 return ret;
676 }
677
664 return ret; 678 return ret;
665} 679}
666 680
@@ -674,4 +688,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
674 if (jffs2_nor_ecc(c)) { 688 if (jffs2_nor_ecc(c)) {
675 jffs2_nor_ecc_flash_cleanup(c); 689 jffs2_nor_ecc_flash_cleanup(c);
676 } 690 }
691
692 /* and DataFlash */
693 if (jffs2_dataflash(c)) {
694 jffs2_dataflash_cleanup(c);
695 }
677} 696}
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 0412416d1f2..af27b84007a 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: os-linux.h,v 1.52 2005/02/09 09:09:01 pavlov Exp $ 10 * $Id: os-linux.h,v 1.53 2005/02/09 09:17:41 pavlov Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -97,12 +97,16 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
97#endif 97#endif
98} 98}
99 99
100#ifdef CONFIG_JFFS2_FS_DATAFLASH
101#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size )
102#else
100#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) 103#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
104#endif
101 105
102#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) 106#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
103#define jffs2_is_writebuffered(c) (c->wbuf != NULL) 107#define jffs2_is_writebuffered(c) (c->wbuf != NULL)
104 108
105#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) 109#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC && !defined CONFIG_JFFS2_FS_DATAFLASH)
106#define jffs2_can_mark_obsolete(c) (1) 110#define jffs2_can_mark_obsolete(c) (1)
107#define jffs2_cleanmarker_oob(c) (0) 111#define jffs2_cleanmarker_oob(c) (0)
108#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) 112#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
@@ -119,6 +123,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
119#define jffs2_wbuf_timeout NULL 123#define jffs2_wbuf_timeout NULL
120#define jffs2_wbuf_process NULL 124#define jffs2_wbuf_process NULL
121#define jffs2_nor_ecc(c) (0) 125#define jffs2_nor_ecc(c) (0)
126#define jffs2_dataflash(c) (0)
122#define jffs2_nor_ecc_flash_setup(c) (0) 127#define jffs2_nor_ecc_flash_setup(c) (0)
123#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) 128#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
124 129
@@ -154,6 +159,15 @@ void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c);
154#define jffs2_nor_ecc_flash_setup(c) (0) 159#define jffs2_nor_ecc_flash_setup(c) (0)
155#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) 160#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
156#endif /* NOR ECC */ 161#endif /* NOR ECC */
162#ifdef CONFIG_JFFS2_FS_DATAFLASH
163#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH)
164int jffs2_dataflash_setup(struct jffs2_sb_info *c);
165void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
166#else
167#define jffs2_dataflash(c) (0)
168#define jffs2_dataflash_setup(c) (0)
169#define jffs2_dataflash_cleanup(c) do {} while (0)
170#endif /* DATAFLASH */
157#endif /* NAND */ 171#endif /* NAND */
158 172
159/* erase.c */ 173/* erase.c */
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 76859ff5343..e8c43746c82 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: scan.c,v 1.116 2005/02/09 09:09:02 pavlov Exp $ 10 * $Id: scan.c,v 1.117 2005/02/09 09:17:41 pavlov Exp $
11 * 11 *
12 */ 12 */
13#include <linux/kernel.h> 13#include <linux/kernel.h>
@@ -68,7 +68,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
68static inline int min_free(struct jffs2_sb_info *c) 68static inline int min_free(struct jffs2_sb_info *c)
69{ 69{
70 uint32_t min = 2 * sizeof(struct jffs2_raw_inode); 70 uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
71#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC 71#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH
72 if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) 72 if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
73 return c->wbuf_pagesize; 73 return c->wbuf_pagesize;
74#endif 74#endif
@@ -228,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
228 c->dirty_size -= c->nextblock->dirty_size; 228 c->dirty_size -= c->nextblock->dirty_size;
229 c->nextblock->dirty_size = 0; 229 c->nextblock->dirty_size = 0;
230 } 230 }
231#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC 231#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH
232 if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { 232 if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
233 /* If we're going to start writing into a block which already 233 /* If we're going to start writing into a block which already
234 contains data, and the end of the data isn't page-aligned, 234 contains data, and the end of the data isn't page-aligned,
@@ -351,7 +351,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
351 } 351 }
352#endif 352#endif
353 D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); 353 D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
354 return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ 354 if (c->cleanmarker_size == 0)
355 return BLK_STATE_CLEANMARKER; /* don't bother with re-erase */
356 else
357 return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
355 } 358 }
356 if (ofs) { 359 if (ofs) {
357 D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, 360 D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 894dea88678..a35e007e5bf 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -9,7 +9,7 @@
9 * 9 *
10 * For licensing information, see the file 'LICENCE' in this directory. 10 * For licensing information, see the file 'LICENCE' in this directory.
11 * 11 *
12 * $Id: wbuf.c,v 1.87 2005/02/09 09:09:02 pavlov Exp $ 12 * $Id: wbuf.c,v 1.88 2005/02/09 09:17:41 pavlov Exp $
13 * 13 *
14 */ 14 */
15 15
@@ -435,7 +435,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
435 if we have a switch to next page, we will not have 435 if we have a switch to next page, we will not have
436 enough remaining space for this. 436 enough remaining space for this.
437 */ 437 */
438 if (pad) { 438 if (pad && !jffs2_dataflash(c)) {
439 c->wbuf_len = PAD(c->wbuf_len); 439 c->wbuf_len = PAD(c->wbuf_len);
440 440
441 /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR 441 /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR
@@ -486,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
486 spin_lock(&c->erase_completion_lock); 486 spin_lock(&c->erase_completion_lock);
487 487
488 /* Adjust free size of the block if we padded. */ 488 /* Adjust free size of the block if we padded. */
489 if (pad) { 489 if (pad && !jffs2_dataflash(c)) {
490 struct jffs2_eraseblock *jeb; 490 struct jffs2_eraseblock *jeb;
491 491
492 jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; 492 jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
@@ -604,8 +604,14 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
604 return ret; 604 return ret;
605} 605}
606 606
607#ifdef CONFIG_JFFS2_FS_DATAFLASH
608#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
609#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
610#else
607#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) 611#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
608#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) 612#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
613#endif
614
609int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) 615int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
610{ 616{
611 struct kvec outvecs[3]; 617 struct kvec outvecs[3];
@@ -1192,6 +1198,29 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
1192 kfree(c->wbuf); 1198 kfree(c->wbuf);
1193} 1199}
1194 1200
1201#ifdef CONFIG_JFFS2_FS_DATAFLASH
1202int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
1203 c->cleanmarker_size = 0; /* No cleanmarkers needed */
1204
1205 /* Initialize write buffer */
1206 init_rwsem(&c->wbuf_sem);
1207 c->wbuf_pagesize = c->sector_size;
1208 c->wbuf_ofs = 0xFFFFFFFF;
1209
1210 c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
1211 if (!c->wbuf)
1212 return -ENOMEM;
1213
1214 printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize);
1215
1216 return 0;
1217}
1218
1219void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
1220 kfree(c->wbuf);
1221}
1222#endif
1223
1195#ifdef CONFIG_JFFS2_FS_NOR_ECC 1224#ifdef CONFIG_JFFS2_FS_NOR_ECC
1196int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { 1225int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
1197 /* Cleanmarker is actually larger on the flashes */ 1226 /* Cleanmarker is actually larger on the flashes */
diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h
index 4afc8d8c2e9..faec29559fe 100644
--- a/include/linux/jffs2_fs_sb.h
+++ b/include/linux/jffs2_fs_sb.h
@@ -1,4 +1,4 @@
1/* $Id: jffs2_fs_sb.h,v 1.48 2004/11/20 10:41:12 dwmw2 Exp $ */ 1/* $Id: jffs2_fs_sb.h,v 1.49 2005/02/09 09:17:41 pavlov Exp $ */
2 2
3#ifndef _JFFS2_FS_SB 3#ifndef _JFFS2_FS_SB
4#define _JFFS2_FS_SB 4#define _JFFS2_FS_SB
@@ -94,7 +94,7 @@ struct jffs2_sb_info {
94 to an obsoleted node. I don't like this. Alternatives welcomed. */ 94 to an obsoleted node. I don't like this. Alternatives welcomed. */
95 struct semaphore erase_free_sem; 95 struct semaphore erase_free_sem;
96 96
97#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC 97#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH
98 /* Write-behind buffer for NAND flash */ 98 /* Write-behind buffer for NAND flash */
99 unsigned char *wbuf; 99 unsigned char *wbuf;
100 uint32_t wbuf_ofs; 100 uint32_t wbuf_ofs;
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index c984cb2c941..cacb9842b19 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * $Id: mtd-abi.h,v 1.9 2005/02/08 17:45:52 nico Exp $ 2 * $Id: mtd-abi.h,v 1.10 2005/02/09 09:17:42 pavlov Exp $
3 * 3 *
4 * Portions of MTD ABI definition which are shared by kernel and user space 4 * Portions of MTD ABI definition which are shared by kernel and user space
5 */ 5 */
@@ -29,6 +29,7 @@ struct mtd_oob_buf {
29#define MTD_NORFLASH 3 29#define MTD_NORFLASH 3
30#define MTD_NANDFLASH 4 30#define MTD_NANDFLASH 4
31#define MTD_PEROM 5 31#define MTD_PEROM 5
32#define MTD_DATAFLASH 6
32#define MTD_OTHER 14 33#define MTD_OTHER 14
33#define MTD_UNKNOWN 15 34#define MTD_UNKNOWN 15
34 35