diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/dvb/ttpci/av7110.c | 113 | ||||
-rw-r--r-- | drivers/media/dvb/ttpci/av7110.h | 1 | ||||
-rw-r--r-- | drivers/media/dvb/ttpci/av7110_av.c | 3 |
3 files changed, 92 insertions, 25 deletions
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 3b641804f6cb..404108f09d77 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c | |||
@@ -88,6 +88,7 @@ static int budgetpatch; | |||
88 | static int wss_cfg_4_3 = 0x4008; | 88 | static int wss_cfg_4_3 = 0x4008; |
89 | static int wss_cfg_16_9 = 0x0007; | 89 | static int wss_cfg_16_9 = 0x0007; |
90 | static int tv_standard; | 90 | static int tv_standard; |
91 | static int full_ts; | ||
91 | 92 | ||
92 | module_param_named(debug, av7110_debug, int, 0644); | 93 | module_param_named(debug, av7110_debug, int, 0644); |
93 | MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); | 94 | MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); |
@@ -106,6 +107,8 @@ module_param(volume, int, 0444); | |||
106 | MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); | 107 | MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); |
107 | module_param(budgetpatch, int, 0444); | 108 | module_param(budgetpatch, int, 0444); |
108 | MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); | 109 | MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); |
110 | module_param(full_ts, int, 0444); | ||
111 | MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable"); | ||
109 | module_param(wss_cfg_4_3, int, 0444); | 112 | module_param(wss_cfg_4_3, int, 0444); |
110 | MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); | 113 | MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); |
111 | module_param(wss_cfg_16_9, int, 0444); | 114 | module_param(wss_cfg_16_9, int, 0444); |
@@ -116,6 +119,8 @@ MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); | |||
116 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 119 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
117 | 120 | ||
118 | static void restart_feeds(struct av7110 *av7110); | 121 | static void restart_feeds(struct av7110 *av7110); |
122 | static int budget_start_feed(struct dvb_demux_feed *feed); | ||
123 | static int budget_stop_feed(struct dvb_demux_feed *feed); | ||
119 | 124 | ||
120 | static int av7110_num; | 125 | static int av7110_num; |
121 | 126 | ||
@@ -806,6 +811,9 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) | |||
806 | 811 | ||
807 | dprintk(4, "%p\n", av7110); | 812 | dprintk(4, "%p\n", av7110); |
808 | 813 | ||
814 | if (av7110->full_ts) | ||
815 | return 0; | ||
816 | |||
809 | if (dvbdmxfilter->type == DMX_TYPE_SEC) { | 817 | if (dvbdmxfilter->type == DMX_TYPE_SEC) { |
810 | if (hw_sections) { | 818 | if (hw_sections) { |
811 | buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | | 819 | buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | |
@@ -854,6 +862,9 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) | |||
854 | 862 | ||
855 | dprintk(4, "%p\n", av7110); | 863 | dprintk(4, "%p\n", av7110); |
856 | 864 | ||
865 | if (av7110->full_ts) | ||
866 | return 0; | ||
867 | |||
857 | handle = dvbdmxfilter->hw_handle; | 868 | handle = dvbdmxfilter->hw_handle; |
858 | if (handle >= 32) { | 869 | if (handle >= 32) { |
859 | printk("%s tried to stop invalid filter %04x, filter type = %x\n", | 870 | printk("%s tried to stop invalid filter %04x, filter type = %x\n", |
@@ -913,7 +924,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) | |||
913 | return ret; | 924 | return ret; |
914 | } | 925 | } |
915 | 926 | ||
916 | if ((dvbdmxfeed->ts_type & TS_PACKET)) { | 927 | if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) { |
917 | if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) | 928 | if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) |
918 | ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); | 929 | ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); |
919 | if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) | 930 | if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) |
@@ -974,7 +985,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) | |||
974 | if (!demux->dmx.frontend) | 985 | if (!demux->dmx.frontend) |
975 | return -EINVAL; | 986 | return -EINVAL; |
976 | 987 | ||
977 | if (feed->pid > 0x1fff) | 988 | if (!av7110->full_ts && feed->pid > 0x1fff) |
978 | return -EINVAL; | 989 | return -EINVAL; |
979 | 990 | ||
980 | if (feed->type == DMX_TYPE_TS) { | 991 | if (feed->type == DMX_TYPE_TS) { |
@@ -1003,7 +1014,12 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) | |||
1003 | } | 1014 | } |
1004 | } | 1015 | } |
1005 | 1016 | ||
1006 | else if (feed->type == DMX_TYPE_SEC) { | 1017 | if (av7110->full_ts) { |
1018 | budget_start_feed(feed); | ||
1019 | return ret; | ||
1020 | } | ||
1021 | |||
1022 | if (feed->type == DMX_TYPE_SEC) { | ||
1007 | int i; | 1023 | int i; |
1008 | 1024 | ||
1009 | for (i = 0; i < demux->filternum; i++) { | 1025 | for (i = 0; i < demux->filternum; i++) { |
@@ -1050,7 +1066,12 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) | |||
1050 | ret = StopHWFilter(feed->filter); | 1066 | ret = StopHWFilter(feed->filter); |
1051 | } | 1067 | } |
1052 | 1068 | ||
1053 | if (!ret && feed->type == DMX_TYPE_SEC) { | 1069 | if (av7110->full_ts) { |
1070 | budget_stop_feed(feed); | ||
1071 | return ret; | ||
1072 | } | ||
1073 | |||
1074 | if (feed->type == DMX_TYPE_SEC) { | ||
1054 | for (i = 0; i<demux->filternum; i++) { | 1075 | for (i = 0; i<demux->filternum; i++) { |
1055 | if (demux->filter[i].state == DMX_STATE_GO && | 1076 | if (demux->filter[i].state == DMX_STATE_GO && |
1056 | demux->filter[i].filter.parent == &feed->feed.sec) { | 1077 | demux->filter[i].filter.parent == &feed->feed.sec) { |
@@ -1074,6 +1095,7 @@ static void restart_feeds(struct av7110 *av7110) | |||
1074 | struct dvb_demux *dvbdmx = &av7110->demux; | 1095 | struct dvb_demux *dvbdmx = &av7110->demux; |
1075 | struct dvb_demux_feed *feed; | 1096 | struct dvb_demux_feed *feed; |
1076 | int mode; | 1097 | int mode; |
1098 | int feeding; | ||
1077 | int i, j; | 1099 | int i, j; |
1078 | 1100 | ||
1079 | dprintk(4, "%p\n", av7110); | 1101 | dprintk(4, "%p\n", av7110); |
@@ -1082,6 +1104,8 @@ static void restart_feeds(struct av7110 *av7110) | |||
1082 | av7110->playing = 0; | 1104 | av7110->playing = 0; |
1083 | av7110->rec_mode = 0; | 1105 | av7110->rec_mode = 0; |
1084 | 1106 | ||
1107 | feeding = av7110->feeding1; /* full_ts mod */ | ||
1108 | |||
1085 | for (i = 0; i < dvbdmx->feednum; i++) { | 1109 | for (i = 0; i < dvbdmx->feednum; i++) { |
1086 | feed = &dvbdmx->feed[i]; | 1110 | feed = &dvbdmx->feed[i]; |
1087 | if (feed->state == DMX_STATE_GO) { | 1111 | if (feed->state == DMX_STATE_GO) { |
@@ -1099,6 +1123,8 @@ static void restart_feeds(struct av7110 *av7110) | |||
1099 | } | 1123 | } |
1100 | } | 1124 | } |
1101 | 1125 | ||
1126 | av7110->feeding1 = feeding; /* full_ts mod */ | ||
1127 | |||
1102 | if (mode) | 1128 | if (mode) |
1103 | av7110_av_start_play(av7110, mode); | 1129 | av7110_av_start_play(av7110, mode); |
1104 | } | 1130 | } |
@@ -1197,8 +1223,9 @@ static int start_ts_capture(struct av7110 *budget) | |||
1197 | 1223 | ||
1198 | if (budget->feeding1) | 1224 | if (budget->feeding1) |
1199 | return ++budget->feeding1; | 1225 | return ++budget->feeding1; |
1200 | memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH); | 1226 | memset(budget->grabbing, 0x00, TS_BUFLEN); |
1201 | budget->ttbp = 0; | 1227 | budget->ttbp = 0; |
1228 | SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ | ||
1202 | SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ | 1229 | SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ |
1203 | saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ | 1230 | saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ |
1204 | return ++budget->feeding1; | 1231 | return ++budget->feeding1; |
@@ -1239,12 +1266,8 @@ static void vpeirq(unsigned long data) | |||
1239 | u8 *mem = (u8 *) (budget->grabbing); | 1266 | u8 *mem = (u8 *) (budget->grabbing); |
1240 | u32 olddma = budget->ttbp; | 1267 | u32 olddma = budget->ttbp; |
1241 | u32 newdma = saa7146_read(budget->dev, PCI_VDP3); | 1268 | u32 newdma = saa7146_read(budget->dev, PCI_VDP3); |
1269 | struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1; | ||
1242 | 1270 | ||
1243 | if (!budgetpatch) { | ||
1244 | printk("av7110.c: vpeirq() called while budgetpatch disabled!" | ||
1245 | " check saa7146 IER register\n"); | ||
1246 | BUG(); | ||
1247 | } | ||
1248 | /* nearest lower position divisible by 188 */ | 1271 | /* nearest lower position divisible by 188 */ |
1249 | newdma -= newdma % 188; | 1272 | newdma -= newdma % 188; |
1250 | 1273 | ||
@@ -1268,11 +1291,11 @@ static void vpeirq(unsigned long data) | |||
1268 | 1291 | ||
1269 | if (newdma > olddma) | 1292 | if (newdma > olddma) |
1270 | /* no wraparound, dump olddma..newdma */ | 1293 | /* no wraparound, dump olddma..newdma */ |
1271 | dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188); | 1294 | dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188); |
1272 | else { | 1295 | else { |
1273 | /* wraparound, dump olddma..buflen and 0..newdma */ | 1296 | /* wraparound, dump olddma..buflen and 0..newdma */ |
1274 | dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188); | 1297 | dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188); |
1275 | dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188); | 1298 | dvb_dmx_swfilter_packets(demux, mem, newdma / 188); |
1276 | } | 1299 | } |
1277 | } | 1300 | } |
1278 | 1301 | ||
@@ -1294,8 +1317,8 @@ static int av7110_register(struct av7110 *av7110) | |||
1294 | for (i = 0; i < 32; i++) | 1317 | for (i = 0; i < 32; i++) |
1295 | av7110->handle2filter[i] = NULL; | 1318 | av7110->handle2filter[i] = NULL; |
1296 | 1319 | ||
1297 | dvbdemux->filternum = 32; | 1320 | dvbdemux->filternum = (av7110->full_ts) ? 256 : 32; |
1298 | dvbdemux->feednum = 32; | 1321 | dvbdemux->feednum = (av7110->full_ts) ? 256 : 32; |
1299 | dvbdemux->start_feed = av7110_start_feed; | 1322 | dvbdemux->start_feed = av7110_start_feed; |
1300 | dvbdemux->stop_feed = av7110_stop_feed; | 1323 | dvbdemux->stop_feed = av7110_stop_feed; |
1301 | dvbdemux->write_to_decoder = av7110_write_to_decoder; | 1324 | dvbdemux->write_to_decoder = av7110_write_to_decoder; |
@@ -1305,7 +1328,7 @@ static int av7110_register(struct av7110 *av7110) | |||
1305 | dvb_dmx_init(&av7110->demux); | 1328 | dvb_dmx_init(&av7110->demux); |
1306 | av7110->demux.dmx.get_stc = dvb_get_stc; | 1329 | av7110->demux.dmx.get_stc = dvb_get_stc; |
1307 | 1330 | ||
1308 | av7110->dmxdev.filternum = 32; | 1331 | av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32; |
1309 | av7110->dmxdev.demux = &dvbdemux->dmx; | 1332 | av7110->dmxdev.demux = &dvbdemux->dmx; |
1310 | av7110->dmxdev.capabilities = 0; | 1333 | av7110->dmxdev.capabilities = 0; |
1311 | 1334 | ||
@@ -1422,7 +1445,6 @@ int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val) | |||
1422 | return i2c_transfer(&av7110->i2c_adap, &msgs, 1); | 1445 | return i2c_transfer(&av7110->i2c_adap, &msgs, 1); |
1423 | } | 1446 | } |
1424 | 1447 | ||
1425 | #if 0 | ||
1426 | u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) | 1448 | u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) |
1427 | { | 1449 | { |
1428 | u8 mm1[] = {0x00}; | 1450 | u8 mm1[] = {0x00}; |
@@ -1439,7 +1461,6 @@ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) | |||
1439 | 1461 | ||
1440 | return mm2[0]; | 1462 | return mm2[0]; |
1441 | } | 1463 | } |
1442 | #endif | ||
1443 | 1464 | ||
1444 | /**************************************************************************** | 1465 | /**************************************************************************** |
1445 | * INITIALIZATION | 1466 | * INITIALIZATION |
@@ -2484,7 +2505,47 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, | |||
2484 | av7110->dvb_adapter.proposed_mac); | 2505 | av7110->dvb_adapter.proposed_mac); |
2485 | ret = -ENOMEM; | 2506 | ret = -ENOMEM; |
2486 | 2507 | ||
2487 | if (budgetpatch) { | 2508 | /* full-ts mod? */ |
2509 | if (full_ts) | ||
2510 | av7110->full_ts = true; | ||
2511 | |||
2512 | /* check for full-ts flag in eeprom */ | ||
2513 | if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) { | ||
2514 | u8 flags = i2c_readreg(av7110, 0xaa, 2); | ||
2515 | if (flags != 0xff && (flags & 0x01)) | ||
2516 | av7110->full_ts = true; | ||
2517 | } | ||
2518 | |||
2519 | if (av7110->full_ts) { | ||
2520 | printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n"); | ||
2521 | spin_lock_init(&av7110->feedlock1); | ||
2522 | av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, | ||
2523 | &av7110->pt); | ||
2524 | if (!av7110->grabbing) | ||
2525 | goto err_i2c_del_3; | ||
2526 | |||
2527 | saa7146_write(dev, DD1_STREAM_B, 0x00000000); | ||
2528 | saa7146_write(dev, MC2, (MASK_10 | MASK_26)); | ||
2529 | |||
2530 | saa7146_write(dev, DD1_INIT, 0x00000600); | ||
2531 | saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); | ||
2532 | |||
2533 | saa7146_write(dev, BRS_CTRL, 0x60000000); | ||
2534 | saa7146_write(dev, MC2, MASK_08 | MASK_24); | ||
2535 | |||
2536 | /* dma3 */ | ||
2537 | saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); | ||
2538 | saa7146_write(dev, BASE_ODD3, 0); | ||
2539 | saa7146_write(dev, BASE_EVEN3, 0); | ||
2540 | saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); | ||
2541 | saa7146_write(dev, PITCH3, TS_WIDTH); | ||
2542 | saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); | ||
2543 | saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); | ||
2544 | saa7146_write(dev, MC2, MASK_04 | MASK_20); | ||
2545 | |||
2546 | tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); | ||
2547 | |||
2548 | } else if (budgetpatch) { | ||
2488 | spin_lock_init(&av7110->feedlock1); | 2549 | spin_lock_init(&av7110->feedlock1); |
2489 | av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, | 2550 | av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, |
2490 | &av7110->pt); | 2551 | &av7110->pt); |
@@ -2710,11 +2771,13 @@ static int __devexit av7110_detach(struct saa7146_dev* saa) | |||
2710 | #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) | 2771 | #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) |
2711 | av7110_ir_exit(av7110); | 2772 | av7110_ir_exit(av7110); |
2712 | #endif | 2773 | #endif |
2713 | if (budgetpatch) { | 2774 | if (budgetpatch || av7110->full_ts) { |
2714 | /* Disable RPS1 */ | 2775 | if (budgetpatch) { |
2715 | saa7146_write(saa, MC1, MASK_29); | 2776 | /* Disable RPS1 */ |
2716 | /* VSYNC LOW (inactive) */ | 2777 | saa7146_write(saa, MC1, MASK_29); |
2717 | saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); | 2778 | /* VSYNC LOW (inactive) */ |
2779 | saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); | ||
2780 | } | ||
2718 | saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ | 2781 | saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ |
2719 | SAA7146_IER_DISABLE(saa, MASK_10); | 2782 | SAA7146_IER_DISABLE(saa, MASK_10); |
2720 | SAA7146_ISR_CLEAR(saa, MASK_10); | 2783 | SAA7146_ISR_CLEAR(saa, MASK_10); |
@@ -2794,7 +2857,7 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr) | |||
2794 | tasklet_schedule(&av7110->gpio_tasklet); | 2857 | tasklet_schedule(&av7110->gpio_tasklet); |
2795 | } | 2858 | } |
2796 | 2859 | ||
2797 | if ((*isr & MASK_10) && budgetpatch) | 2860 | if (*isr & MASK_10) |
2798 | tasklet_schedule(&av7110->vpe_tasklet); | 2861 | tasklet_schedule(&av7110->vpe_tasklet); |
2799 | } | 2862 | } |
2800 | 2863 | ||
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 55f23ddcb994..d85b8512ac30 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h | |||
@@ -192,6 +192,7 @@ struct av7110 { | |||
192 | unsigned char *grabbing; | 192 | unsigned char *grabbing; |
193 | struct saa7146_pgtable pt; | 193 | struct saa7146_pgtable pt; |
194 | struct tasklet_struct vpe_tasklet; | 194 | struct tasklet_struct vpe_tasklet; |
195 | bool full_ts; | ||
195 | 196 | ||
196 | int fe_synced; | 197 | int fe_synced; |
197 | struct mutex pid_mutex; | 198 | struct mutex pid_mutex; |
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 184647ad1c7c..bdc62acf2099 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c | |||
@@ -788,6 +788,9 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l | |||
788 | 788 | ||
789 | dprintk(2, "av7110:%p, \n", av7110); | 789 | dprintk(2, "av7110:%p, \n", av7110); |
790 | 790 | ||
791 | if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE) | ||
792 | return 0; | ||
793 | |||
791 | switch (feed->pes_type) { | 794 | switch (feed->pes_type) { |
792 | case 0: | 795 | case 0: |
793 | if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) | 796 | if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) |