File Index
Files and directories
Sign in
FILE

cec-splitter.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/cec/usb/extron-da-hd-4k-plus/cec-splitter.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3/*
  4 * Copyright 2021-2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
  5 */
  6
  7#include <media/cec.h>
  8
  9#include "cec-splitter.h"
 10
 11/*
 12 * Helper function to reply to a received message with a Feature Abort
 13 * message.
 14 */
 15static int cec_feature_abort_reason(struct cec_adapter *adap,
 16				    struct cec_msg *msg, u8 reason)
 17{
 18	struct cec_msg tx_msg = { };
 19
 20	/*
 21	 * Don't reply with CEC_MSG_FEATURE_ABORT to a CEC_MSG_FEATURE_ABORT
 22	 * message!
 23	 */
 24	if (msg->msg[1] == CEC_MSG_FEATURE_ABORT)
 25		return 0;
 26	/* Don't Feature Abort messages from 'Unregistered' */
 27	if (cec_msg_initiator(msg) == CEC_LOG_ADDR_UNREGISTERED)
 28		return 0;
 29	cec_msg_set_reply_to(&tx_msg, msg);
 30	cec_msg_feature_abort(&tx_msg, msg->msg[1], reason);
 31	return cec_transmit_msg(adap, &tx_msg, false);
 32}
 33
 34/* Transmit an Active Source message from this output port to a sink */
 35static void cec_port_out_active_source(struct cec_splitter_port *p)
 36{
 37	struct cec_adapter *adap = p->adap;
 38	struct cec_msg msg;
 39
 40	if (!adap->is_configured)
 41		return;
 42	p->is_active_source = true;
 43	cec_msg_init(&msg, adap->log_addrs.log_addr[0], 0);
 44	cec_msg_active_source(&msg, adap->phys_addr);
 45	cec_transmit_msg(adap, &msg, false);
 46}
 47
 48/* Transmit Active Source messages from all output ports to the sinks */
 49static void cec_out_active_source(struct cec_splitter *splitter)
 50{
 51	unsigned int i;
 52
 53	for (i = 0; i < splitter->num_out_ports; i++)
 54		cec_port_out_active_source(splitter->ports[i]);
 55}
 56
 57/* Transmit a Standby message from this output port to a sink */
 58static void cec_port_out_standby(struct cec_splitter_port *p)
 59{
 60	struct cec_adapter *adap = p->adap;
 61	struct cec_msg msg;
 62
 63	if (!adap->is_configured)
 64		return;
 65	cec_msg_init(&msg, adap->log_addrs.log_addr[0], 0);
 66	cec_msg_standby(&msg);
 67	cec_transmit_msg(adap, &msg, false);
 68}
 69
 70/* Transmit Standby messages from all output ports to the sinks */
 71static void cec_out_standby(struct cec_splitter *splitter)
 72{
 73	unsigned int i;
 74
 75	for (i = 0; i < splitter->num_out_ports; i++)
 76		cec_port_out_standby(splitter->ports[i]);
 77}
 78
 79/* Transmit an Image/Text View On message from this output port to a sink */
 80static void cec_port_out_wakeup(struct cec_splitter_port *p, u8 opcode)
 81{
 82	struct cec_adapter *adap = p->adap;
 83	u8 la = adap->log_addrs.log_addr[0];
 84	struct cec_msg msg;
 85
 86	if (la == CEC_LOG_ADDR_INVALID)
 87		la = CEC_LOG_ADDR_UNREGISTERED;
 88	cec_msg_init(&msg, la, 0);
 89	msg.len = 2;
 90	msg.msg[1] = opcode;
 91	cec_transmit_msg(adap, &msg, false);
 92}
 93
 94/* Transmit Image/Text View On messages from all output ports to the sinks */
 95static void cec_out_wakeup(struct cec_splitter *splitter, u8 opcode)
 96{
 97	unsigned int i;
 98
 99	for (i = 0; i < splitter->num_out_ports; i++)
100		cec_port_out_wakeup(splitter->ports[i], opcode);
101}
102
103/*
104 * Update the power state of the unconfigured CEC device to either
105 * Off or On depending on the current state of the splitter.
106 * This keeps the outputs in a consistent state.
107 */
108void cec_splitter_unconfigured_output(struct cec_splitter_port *p)
109{
110	p->video_latency = 1;
111	p->power_status = p->splitter->is_standby ?
112		CEC_OP_POWER_STATUS_TO_STANDBY : CEC_OP_POWER_STATUS_TO_ON;
113
114	/* The adapter was unconfigured, so clear the sequence and ts values */
115	p->out_give_device_power_status_seq = 0;
116	p->out_give_device_power_status_ts = ktime_set(0, 0);
117	p->out_request_current_latency_seq = 0;
118	p->out_request_current_latency_ts = ktime_set(0, 0);
119}
120
121/*
122 * Update the power state of the newly configured CEC device to either
123 * Off or On depending on the current state of the splitter.
124 * This keeps the outputs in a consistent state.
125 */
126void cec_splitter_configured_output(struct cec_splitter_port *p)
127{
128	p->video_latency = 1;
129	p->power_status = p->splitter->is_standby ?
130		CEC_OP_POWER_STATUS_TO_STANDBY : CEC_OP_POWER_STATUS_TO_ON;
131
132	if (p->splitter->is_standby) {
133		/*
134		 * Some sinks only obey Standby if it comes from the
135		 * active source.
136		 */
137		cec_port_out_active_source(p);
138		cec_port_out_standby(p);
139	} else {
140		cec_port_out_wakeup(p, CEC_MSG_IMAGE_VIEW_ON);
141	}
142}
143
144/* Pass the in_msg on to all output ports */
145static void cec_out_passthrough(struct cec_splitter *splitter,
146				const struct cec_msg *in_msg)
147{
148	unsigned int i;
149
150	for (i = 0; i < splitter->num_out_ports; i++) {
151		struct cec_splitter_port *p = splitter->ports[i];
152		struct cec_adapter *adap = p->adap;
153		struct cec_msg msg;
154
155		if (!adap->is_configured)
156			continue;
157		cec_msg_init(&msg, adap->log_addrs.log_addr[0], 0);
158		msg.len = in_msg->len;
159		memcpy(msg.msg + 1, in_msg->msg + 1, msg.len - 1);
160		cec_transmit_msg(adap, &msg, false);
161	}
162}
163
164/*
165 * See if all output ports received the Report Current Latency message,
166 * and if so, transmit the result from the input port to the video source.
167 */
168static void cec_out_report_current_latency(struct cec_splitter *splitter,
169					   struct cec_adapter *input_adap)
170{
171	struct cec_msg reply = {};
172	unsigned int reply_lat = 0;
173	unsigned int cnt = 0;
174	unsigned int i;
175
176	for (i = 0; i < splitter->num_out_ports; i++) {
177		struct cec_splitter_port *p = splitter->ports[i];
178		struct cec_adapter *adap = p->adap;
179
180		/* Skip unconfigured ports */
181		if (!adap->is_configured)
182			continue;
183		/* Return if a port is still waiting for a reply */
184		if (p->out_request_current_latency_seq)
185			return;
186		reply_lat += p->video_latency - 1;
187		cnt++;
188	}
189
190	/*
191	 * All ports that can reply, replied, so clear the sequence
192	 * and timestamp values.
193	 */
194	for (i = 0; i < splitter->num_out_ports; i++) {
195		struct cec_splitter_port *p = splitter->ports[i];
196
197		p->out_request_current_latency_seq = 0;
198		p->out_request_current_latency_ts = ktime_set(0, 0);
199	}
200
201	/*
202	 * Return if there were no replies or the input port is no longer
203	 * configured.
204	 */
205	if (!cnt || !input_adap->is_configured)
206		return;
207
208	/* Reply with the average latency */
209	reply_lat = 1 + reply_lat / cnt;
210	cec_msg_init(&reply, input_adap->log_addrs.log_addr[0],
211		     splitter->request_current_latency_dest);
212	cec_msg_report_current_latency(&reply, input_adap->phys_addr,
213				       reply_lat, 1, 1, 1);
214	cec_transmit_msg(input_adap, &reply, false);
215}
216
217/* Transmit Request Current Latency to all output ports */
218static int cec_out_request_current_latency(struct cec_splitter *splitter)
219{
220	ktime_t now = ktime_get();
221	bool error = true;
222	unsigned int i;
223
224	for (i = 0; i < splitter->num_out_ports; i++) {
225		struct cec_splitter_port *p = splitter->ports[i];
226		struct cec_adapter *adap = p->adap;
227
228		if (!adap->is_configured) {
229			/* Clear if not configured */
230			p->out_request_current_latency_seq = 0;
231			p->out_request_current_latency_ts = ktime_set(0, 0);
232		} else if (!p->out_request_current_latency_seq) {
233			/*
234			 * Keep the old ts if an earlier request is still
235			 * pending. This ensures that the request will
236			 * eventually time out based on the timestamp of
237			 * the first request if the sink is unresponsive.
238			 */
239			p->out_request_current_latency_ts = now;
240		}
241	}
242
243	for (i = 0; i < splitter->num_out_ports; i++) {
244		struct cec_splitter_port *p = splitter->ports[i];
245		struct cec_adapter *adap = p->adap;
246		struct cec_msg msg;
247
248		if (!adap->is_configured)
249			continue;
250		cec_msg_init(&msg, adap->log_addrs.log_addr[0], 0);
251		cec_msg_request_current_latency(&msg, true, adap->phys_addr);
252		if (cec_transmit_msg(adap, &msg, false))
253			continue;
254		p->out_request_current_latency_seq = msg.sequence | (1U << 31);
255		error = false;
256	}
257	return error ? -ENODEV : 0;
258}
259
260/*
261 * See if all output ports received the Report Power Status message,
262 * and if so, transmit the result from the input port to the video source.
263 */
264static void cec_out_report_power_status(struct cec_splitter *splitter,
265					struct cec_adapter *input_adap)
266{
267	struct cec_msg reply = {};
268	/* The target power status of the splitter itself */
269	u8 splitter_pwr = splitter->is_standby ?
270		CEC_OP_POWER_STATUS_STANDBY : CEC_OP_POWER_STATUS_ON;
271	/*
272	 * The transient power status of the splitter, used if not all
273	 * output report the target power status.
274	 */
275	u8 splitter_transient_pwr = splitter->is_standby ?
276		CEC_OP_POWER_STATUS_TO_STANDBY : CEC_OP_POWER_STATUS_TO_ON;
277	u8 reply_pwr = splitter_pwr;
278	unsigned int i;
279
280	for (i = 0; i < splitter->num_out_ports; i++) {
281		struct cec_splitter_port *p = splitter->ports[i];
282
283		/* Skip if no sink was found (HPD was low for more than 5s) */
284		if (!p->found_sink)
285			continue;
286
287		/* Return if a port is still waiting for a reply */
288		if (p->out_give_device_power_status_seq)
289			return;
290		if (p->power_status != splitter_pwr)
291			reply_pwr = splitter_transient_pwr;
292	}
293
294	/*
295	 * All ports that can reply, replied, so clear the sequence
296	 * and timestamp values.
297	 */
298	for (i = 0; i < splitter->num_out_ports; i++) {
299		struct cec_splitter_port *p = splitter->ports[i];
300
301		p->out_give_device_power_status_seq = 0;
302		p->out_give_device_power_status_ts = ktime_set(0, 0);
303	}
304
305	/* Return if the input port is no longer configured. */
306	if (!input_adap->is_configured)
307		return;
308
309	/* Reply with the new power status */
310	cec_msg_init(&reply, input_adap->log_addrs.log_addr[0],
311		     splitter->give_device_power_status_dest);
312	cec_msg_report_power_status(&reply, reply_pwr);
313	cec_transmit_msg(input_adap, &reply, false);
314}
315
316/* Transmit Give Device Power Status to all output ports */
317static int cec_out_give_device_power_status(struct cec_splitter *splitter)
318{
319	ktime_t now = ktime_get();
320	bool error = true;
321	unsigned int i;
322
323	for (i = 0; i < splitter->num_out_ports; i++) {
324		struct cec_splitter_port *p = splitter->ports[i];
325		struct cec_adapter *adap = p->adap;
326
327		/*
328		 * Keep the old ts if an earlier request is still
329		 * pending. This ensures that the request will
330		 * eventually time out based on the timestamp of
331		 * the first request if the sink is unresponsive.
332		 */
333		if (adap->is_configured && !p->out_give_device_power_status_seq)
334			p->out_give_device_power_status_ts = now;
335	}
336
337	for (i = 0; i < splitter->num_out_ports; i++) {
338		struct cec_splitter_port *p = splitter->ports[i];
339		struct cec_adapter *adap = p->adap;
340		struct cec_msg msg;
341
342		if (!adap->is_configured)
343			continue;
344
345		cec_msg_init(&msg, adap->log_addrs.log_addr[0], 0);
346		cec_msg_give_device_power_status(&msg, true);
347		if (cec_transmit_msg(adap, &msg, false))
348			continue;
349		p->out_give_device_power_status_seq = msg.sequence | (1U << 31);
350		error = false;
351	}
352	return error ? -ENODEV : 0;
353}
354
355/*
356 * CEC messages received on the HDMI input of the splitter are
357 * forwarded (if relevant) to the HDMI outputs of the splitter.
358 */
359int cec_splitter_received_input(struct cec_splitter_port *p, struct cec_msg *msg)
360{
361	if (!cec_msg_status_is_ok(msg))
362		return 0;
363
364	if (msg->len < 2)
365		return -ENOMSG;
366
367	switch (msg->msg[1]) {
368	case CEC_MSG_DEVICE_VENDOR_ID:
369	case CEC_MSG_REPORT_POWER_STATUS:
370	case CEC_MSG_SET_STREAM_PATH:
371	case CEC_MSG_ROUTING_CHANGE:
372	case CEC_MSG_REQUEST_ACTIVE_SOURCE:
373	case CEC_MSG_SYSTEM_AUDIO_MODE_STATUS:
374		return 0;
375
376	case CEC_MSG_STANDBY:
377		p->splitter->is_standby = true;
378		cec_out_standby(p->splitter);
379		return 0;
380
381	case CEC_MSG_IMAGE_VIEW_ON:
382	case CEC_MSG_TEXT_VIEW_ON:
383		p->splitter->is_standby = false;
384		cec_out_wakeup(p->splitter, msg->msg[1]);
385		return 0;
386
387	case CEC_MSG_ACTIVE_SOURCE:
388		cec_out_active_source(p->splitter);
389		return 0;
390
391	case CEC_MSG_SET_SYSTEM_AUDIO_MODE:
392		cec_out_passthrough(p->splitter, msg);
393		return 0;
394
395	case CEC_MSG_GIVE_DEVICE_POWER_STATUS:
396		p->splitter->give_device_power_status_dest =
397			cec_msg_initiator(msg);
398		if (cec_out_give_device_power_status(p->splitter))
399			cec_feature_abort_reason(p->adap, msg,
400						 CEC_OP_ABORT_INCORRECT_MODE);
401		return 0;
402
403	case CEC_MSG_REQUEST_CURRENT_LATENCY: {
404		u16 pa;
405
406		p->splitter->request_current_latency_dest =
407			cec_msg_initiator(msg);
408		cec_ops_request_current_latency(msg, &pa);
409		if (pa == p->adap->phys_addr &&
410		    cec_out_request_current_latency(p->splitter))
411			cec_feature_abort_reason(p->adap, msg,
412						 CEC_OP_ABORT_INCORRECT_MODE);
413		return 0;
414	}
415
416	default:
417		return -ENOMSG;
418	}
419	return -ENOMSG;
420}
421
422void cec_splitter_nb_transmit_canceled_output(struct cec_splitter_port *p,
423					      const struct cec_msg *msg,
424					      struct cec_adapter *input_adap)
425{
426	struct cec_splitter *splitter = p->splitter;
427	u32 seq = msg->sequence | (1U << 31);
428
429	/*
430	 * If this is the result of a failed non-blocking transmit, or it is
431	 * the result of the failed reply to a non-blocking transmit, then
432	 * check if the original transmit was to get the current power status
433	 * or latency and, if so, assume that the remove device is for one
434	 * reason or another unavailable and assume that it is in the same
435	 * power status as the splitter, or has no video latency.
436	 */
437	if ((cec_msg_recv_is_tx_result(msg) && !(msg->tx_status & CEC_TX_STATUS_OK)) ||
438	    (cec_msg_recv_is_rx_result(msg) && !(msg->rx_status & CEC_RX_STATUS_OK))) {
439		u8 tx_op = msg->msg[1];
440
441		if (msg->len < 2)
442			return;
443		if (cec_msg_recv_is_rx_result(msg) &&
444		    (msg->rx_status & CEC_RX_STATUS_FEATURE_ABORT))
445			tx_op = msg->msg[2];
446		switch (tx_op) {
447		case CEC_MSG_GIVE_DEVICE_POWER_STATUS:
448			if (p->out_give_device_power_status_seq != seq)
449				break;
450			p->out_give_device_power_status_seq = 0;
451			p->out_give_device_power_status_ts = ktime_set(0, 0);
452			p->power_status = splitter->is_standby ?
453					  CEC_OP_POWER_STATUS_STANDBY :
454					  CEC_OP_POWER_STATUS_ON;
455			cec_out_report_power_status(splitter, input_adap);
456			break;
457		case CEC_MSG_REQUEST_CURRENT_LATENCY:
458			if (p->out_request_current_latency_seq != seq)
459				break;
460			p->video_latency = 1;
461			p->out_request_current_latency_seq = 0;
462			p->out_request_current_latency_ts = ktime_set(0, 0);
463			cec_out_report_current_latency(splitter, input_adap);
464			break;
465		}
466		return;
467	}
468
469	if (cec_msg_recv_is_tx_result(msg)) {
470		if (p->out_request_current_latency_seq != seq)
471			return;
472		p->out_request_current_latency_ts = ns_to_ktime(msg->tx_ts);
473		return;
474	}
475}
476
477/*
478 * CEC messages received on an HDMI output of the splitter
479 * are processed here.
480 */
481int cec_splitter_received_output(struct cec_splitter_port *p, struct cec_msg *msg,
482				 struct cec_adapter *input_adap)
483{
484	struct cec_adapter *adap = p->adap;
485	struct cec_splitter *splitter = p->splitter;
486	u32 seq = msg->sequence | (1U << 31);
487	struct cec_msg reply = {};
488	u16 pa;
489
490	if (!adap->is_configured || msg->len < 2)
491		return -ENOMSG;
492
493	switch (msg->msg[1]) {
494	case CEC_MSG_REPORT_POWER_STATUS: {
495		u8 pwr;
496
497		cec_ops_report_power_status(msg, &pwr);
498		if (pwr > CEC_OP_POWER_STATUS_TO_STANDBY)
499			pwr = splitter->is_standby ?
500				CEC_OP_POWER_STATUS_TO_STANDBY :
501				CEC_OP_POWER_STATUS_TO_ON;
502		p->power_status = pwr;
503		if (p->out_give_device_power_status_seq == seq) {
504			p->out_give_device_power_status_seq = 0;
505			p->out_give_device_power_status_ts = ktime_set(0, 0);
506		}
507		cec_out_report_power_status(splitter, input_adap);
508		return 0;
509	}
510
511	case CEC_MSG_REPORT_CURRENT_LATENCY: {
512		u8 video_lat;
513		u8 low_lat_mode;
514		u8 audio_out_comp;
515		u8 audio_out_delay;
516
517		cec_ops_report_current_latency(msg, &pa,
518					       &video_lat, &low_lat_mode,
519					       &audio_out_comp, &audio_out_delay);
520		if (!video_lat || video_lat >= 252)
521			video_lat = 1;
522		p->video_latency = video_lat;
523		if (p->out_request_current_latency_seq == seq) {
524			p->out_request_current_latency_seq = 0;
525			p->out_request_current_latency_ts = ktime_set(0, 0);
526		}
527		cec_out_report_current_latency(splitter, input_adap);
528		return 0;
529	}
530
531	case CEC_MSG_STANDBY:
532	case CEC_MSG_ROUTING_CHANGE:
533	case CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS:
534		return 0;
535
536	case CEC_MSG_ACTIVE_SOURCE:
537		cec_ops_active_source(msg, &pa);
538		if (pa == 0)
539			p->is_active_source = false;
540		return 0;
541
542	case CEC_MSG_REQUEST_ACTIVE_SOURCE:
543		if (!p->is_active_source)
544			return 0;
545		cec_msg_set_reply_to(&reply, msg);
546		cec_msg_active_source(&reply, adap->phys_addr);
547		cec_transmit_msg(adap, &reply, false);
548		return 0;
549
550	case CEC_MSG_GIVE_DEVICE_POWER_STATUS:
551		cec_msg_set_reply_to(&reply, msg);
552		cec_msg_report_power_status(&reply, splitter->is_standby ?
553					    CEC_OP_POWER_STATUS_STANDBY :
554					    CEC_OP_POWER_STATUS_ON);
555		cec_transmit_msg(adap, &reply, false);
556		return 0;
557
558	case CEC_MSG_SET_STREAM_PATH:
559		cec_ops_set_stream_path(msg, &pa);
560		if (pa == adap->phys_addr) {
561			cec_msg_set_reply_to(&reply, msg);
562			cec_msg_active_source(&reply, pa);
563			cec_transmit_msg(adap, &reply, false);
564		}
565		return 0;
566
567	default:
568		return -ENOMSG;
569	}
570	return -ENOMSG;
571}
572
573/*
574 * Called every second to check for timed out messages and whether there
575 * still is a video sink connected or not.
576 *
577 * Returns true if sinks were lost.
578 */
579bool cec_splitter_poll(struct cec_splitter *splitter,
580		       struct cec_adapter *input_adap, bool debug)
581{
582	ktime_t now = ktime_get();
583	u8 pwr = splitter->is_standby ?
584		 CEC_OP_POWER_STATUS_STANDBY : CEC_OP_POWER_STATUS_ON;
585	unsigned int max_delay_ms = input_adap->xfer_timeout_ms + 2000;
586	unsigned int i;
587	bool res = false;
588
589	for (i = 0; i < splitter->num_out_ports; i++) {
590		struct cec_splitter_port *p = splitter->ports[i];
591		s64 pwr_delta, lat_delta;
592		bool pwr_timeout, lat_timeout;
593
594		if (!p)
595			continue;
596
597		pwr_delta = ktime_ms_delta(now, p->out_give_device_power_status_ts);
598		pwr_timeout = p->out_give_device_power_status_seq &&
599			      pwr_delta >= max_delay_ms;
600		lat_delta = ktime_ms_delta(now, p->out_request_current_latency_ts);
601		lat_timeout = p->out_request_current_latency_seq &&
602			      lat_delta >= max_delay_ms;
603
604		/*
605		 * If the HPD is low for more than 5 seconds, then assume no display
606		 * is connected.
607		 */
608		if (p->found_sink && ktime_to_ns(p->lost_sink_ts) &&
609		    ktime_ms_delta(now, p->lost_sink_ts) > 5000) {
610			if (debug)
611				dev_info(splitter->dev,
612					 "port %u: HPD low for more than 5s, assume no sink is connected.\n",
613					 p->port);
614			p->found_sink = false;
615			p->lost_sink_ts = ktime_set(0, 0);
616			res = true;
617		}
618
619		/*
620		 * If the power status request timed out, then set the port's
621		 * power status to that of the splitter, ensuring a consistent
622		 * power state.
623		 */
624		if (pwr_timeout) {
625			mutex_lock(&p->adap->lock);
626			if (debug)
627				dev_info(splitter->dev,
628					 "port %u: give up on power status for seq %u\n",
629					 p->port,
630					 p->out_give_device_power_status_seq & ~(1 << 31));
631			p->power_status = pwr;
632			p->out_give_device_power_status_seq = 0;
633			p->out_give_device_power_status_ts = ktime_set(0, 0);
634			mutex_unlock(&p->adap->lock);
635			cec_out_report_power_status(splitter, input_adap);
636		}
637
638		/*
639		 * If the current latency request timed out, then set the port's
640		 * latency to 1.
641		 */
642		if (lat_timeout) {
643			mutex_lock(&p->adap->lock);
644			if (debug)
645				dev_info(splitter->dev,
646					 "port %u: give up on latency for seq %u\n",
647					 p->port,
648					 p->out_request_current_latency_seq & ~(1 << 31));
649			p->video_latency = 1;
650			p->out_request_current_latency_seq = 0;
651			p->out_request_current_latency_ts = ktime_set(0, 0);
652			mutex_unlock(&p->adap->lock);
653			cec_out_report_current_latency(splitter, input_adap);
654		}
655	}
656	return res;
657}
~/ Read-only file preview.