[go: nahoru, domu]

1/***********************************************************************
2 *
3 * Copyright(c) 2013 Mauro Carvalho Chehab
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9
10 *  This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 ***********************************************************************/
19
20#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21
22#include <linux/module.h>
23#include <linux/slab.h>
24#include <linux/init.h>
25#include <linux/debugfs.h>
26#include <linux/spinlock.h>
27#include <linux/usb.h>
28
29#include "dmxdev.h"
30#include "dvbdev.h"
31#include "dvb_demux.h"
32#include "dvb_frontend.h"
33
34#include "smscoreapi.h"
35
36#include "smsdvb.h"
37
38static struct dentry *smsdvb_debugfs_usb_root;
39
40struct smsdvb_debugfs {
41	struct kref		refcount;
42	spinlock_t		lock;
43
44	char			stats_data[PAGE_SIZE];
45	unsigned		stats_count;
46	bool			stats_was_read;
47
48	wait_queue_head_t	stats_queue;
49};
50
51static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data,
52			    struct sms_stats *p)
53{
54	int n = 0;
55	char *buf;
56
57	spin_lock(&debug_data->lock);
58	if (debug_data->stats_count) {
59		spin_unlock(&debug_data->lock);
60		return;
61	}
62
63	buf = debug_data->stats_data;
64
65	n += snprintf(&buf[n], PAGE_SIZE - n,
66		      "is_rf_locked = %d\n", p->is_rf_locked);
67	n += snprintf(&buf[n], PAGE_SIZE - n,
68		      "is_demod_locked = %d\n", p->is_demod_locked);
69	n += snprintf(&buf[n], PAGE_SIZE - n,
70		      "is_external_lna_on = %d\n", p->is_external_lna_on);
71	n += snprintf(&buf[n], PAGE_SIZE - n,
72		      "SNR = %d\n", p->SNR);
73	n += snprintf(&buf[n], PAGE_SIZE - n,
74		      "ber = %d\n", p->ber);
75	n += snprintf(&buf[n], PAGE_SIZE - n,
76		      "FIB_CRC = %d\n", p->FIB_CRC);
77	n += snprintf(&buf[n], PAGE_SIZE - n,
78		      "ts_per = %d\n", p->ts_per);
79	n += snprintf(&buf[n], PAGE_SIZE - n,
80		      "MFER = %d\n", p->MFER);
81	n += snprintf(&buf[n], PAGE_SIZE - n,
82		      "RSSI = %d\n", p->RSSI);
83	n += snprintf(&buf[n], PAGE_SIZE - n,
84		      "in_band_pwr = %d\n", p->in_band_pwr);
85	n += snprintf(&buf[n], PAGE_SIZE - n,
86		      "carrier_offset = %d\n", p->carrier_offset);
87	n += snprintf(&buf[n], PAGE_SIZE - n,
88		      "modem_state = %d\n", p->modem_state);
89	n += snprintf(&buf[n], PAGE_SIZE - n,
90		      "frequency = %d\n", p->frequency);
91	n += snprintf(&buf[n], PAGE_SIZE - n,
92		      "bandwidth = %d\n", p->bandwidth);
93	n += snprintf(&buf[n], PAGE_SIZE - n,
94		      "transmission_mode = %d\n", p->transmission_mode);
95	n += snprintf(&buf[n], PAGE_SIZE - n,
96		      "modem_state = %d\n", p->modem_state);
97	n += snprintf(&buf[n], PAGE_SIZE - n,
98		      "guard_interval = %d\n", p->guard_interval);
99	n += snprintf(&buf[n], PAGE_SIZE - n,
100		      "code_rate = %d\n", p->code_rate);
101	n += snprintf(&buf[n], PAGE_SIZE - n,
102		      "lp_code_rate = %d\n", p->lp_code_rate);
103	n += snprintf(&buf[n], PAGE_SIZE - n,
104		      "hierarchy = %d\n", p->hierarchy);
105	n += snprintf(&buf[n], PAGE_SIZE - n,
106		      "constellation = %d\n", p->constellation);
107	n += snprintf(&buf[n], PAGE_SIZE - n,
108		      "burst_size = %d\n", p->burst_size);
109	n += snprintf(&buf[n], PAGE_SIZE - n,
110		      "burst_duration = %d\n", p->burst_duration);
111	n += snprintf(&buf[n], PAGE_SIZE - n,
112		      "burst_cycle_time = %d\n", p->burst_cycle_time);
113	n += snprintf(&buf[n], PAGE_SIZE - n,
114		      "calc_burst_cycle_time = %d\n",
115		      p->calc_burst_cycle_time);
116	n += snprintf(&buf[n], PAGE_SIZE - n,
117		      "num_of_rows = %d\n", p->num_of_rows);
118	n += snprintf(&buf[n], PAGE_SIZE - n,
119		      "num_of_padd_cols = %d\n", p->num_of_padd_cols);
120	n += snprintf(&buf[n], PAGE_SIZE - n,
121		      "num_of_punct_cols = %d\n", p->num_of_punct_cols);
122	n += snprintf(&buf[n], PAGE_SIZE - n,
123		      "error_ts_packets = %d\n", p->error_ts_packets);
124	n += snprintf(&buf[n], PAGE_SIZE - n,
125		      "total_ts_packets = %d\n", p->total_ts_packets);
126	n += snprintf(&buf[n], PAGE_SIZE - n,
127		      "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs);
128	n += snprintf(&buf[n], PAGE_SIZE - n,
129		      "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs);
130	n += snprintf(&buf[n], PAGE_SIZE - n,
131		      "num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs);
132	n += snprintf(&buf[n], PAGE_SIZE - n,
133		      "ber_error_count = %d\n", p->ber_error_count);
134	n += snprintf(&buf[n], PAGE_SIZE - n,
135		      "ber_bit_count = %d\n", p->ber_bit_count);
136	n += snprintf(&buf[n], PAGE_SIZE - n,
137		      "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
138	n += snprintf(&buf[n], PAGE_SIZE - n,
139		      "pre_ber = %d\n", p->pre_ber);
140	n += snprintf(&buf[n], PAGE_SIZE - n,
141		      "cell_id = %d\n", p->cell_id);
142	n += snprintf(&buf[n], PAGE_SIZE - n,
143		      "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp);
144	n += snprintf(&buf[n], PAGE_SIZE - n,
145		      "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp);
146	n += snprintf(&buf[n], PAGE_SIZE - n,
147		      "num_mpe_received = %d\n", p->num_mpe_received);
148
149	debug_data->stats_count = n;
150	spin_unlock(&debug_data->lock);
151	wake_up(&debug_data->stats_queue);
152}
153
154static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data,
155			     struct sms_isdbt_stats *p)
156{
157	int i, n = 0;
158	char *buf;
159
160	spin_lock(&debug_data->lock);
161	if (debug_data->stats_count) {
162		spin_unlock(&debug_data->lock);
163		return;
164	}
165
166	buf = debug_data->stats_data;
167
168	n += snprintf(&buf[n], PAGE_SIZE - n,
169		      "statistics_type = %d\t", p->statistics_type);
170	n += snprintf(&buf[n], PAGE_SIZE - n,
171		      "full_size = %d\n", p->full_size);
172
173	n += snprintf(&buf[n], PAGE_SIZE - n,
174		      "is_rf_locked = %d\t\t", p->is_rf_locked);
175	n += snprintf(&buf[n], PAGE_SIZE - n,
176		      "is_demod_locked = %d\t", p->is_demod_locked);
177	n += snprintf(&buf[n], PAGE_SIZE - n,
178		      "is_external_lna_on = %d\n", p->is_external_lna_on);
179	n += snprintf(&buf[n], PAGE_SIZE - n,
180		      "SNR = %d dB\t\t", p->SNR);
181	n += snprintf(&buf[n], PAGE_SIZE - n,
182		      "RSSI = %d dBm\t\t", p->RSSI);
183	n += snprintf(&buf[n], PAGE_SIZE - n,
184		      "in_band_pwr = %d dBm\n", p->in_band_pwr);
185	n += snprintf(&buf[n], PAGE_SIZE - n,
186		      "carrier_offset = %d\t", p->carrier_offset);
187	n += snprintf(&buf[n], PAGE_SIZE - n,
188		      "bandwidth = %d\t\t", p->bandwidth);
189	n += snprintf(&buf[n], PAGE_SIZE - n,
190		      "frequency = %d Hz\n", p->frequency);
191	n += snprintf(&buf[n], PAGE_SIZE - n,
192		      "transmission_mode = %d\t", p->transmission_mode);
193	n += snprintf(&buf[n], PAGE_SIZE - n,
194		      "modem_state = %d\t\t", p->modem_state);
195	n += snprintf(&buf[n], PAGE_SIZE - n,
196		      "guard_interval = %d\n", p->guard_interval);
197	n += snprintf(&buf[n], PAGE_SIZE - n,
198		      "system_type = %d\t\t", p->system_type);
199	n += snprintf(&buf[n], PAGE_SIZE - n,
200		      "partial_reception = %d\t", p->partial_reception);
201	n += snprintf(&buf[n], PAGE_SIZE - n,
202		      "num_of_layers = %d\n", p->num_of_layers);
203	n += snprintf(&buf[n], PAGE_SIZE - n,
204		      "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
205
206	for (i = 0; i < 3; i++) {
207		if (p->layer_info[i].number_of_segments < 1 ||
208		    p->layer_info[i].number_of_segments > 13)
209			continue;
210
211		n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
212		n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
213			      p->layer_info[i].code_rate);
214		n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
215			      p->layer_info[i].constellation);
216		n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
217			      p->layer_info[i].ber);
218		n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t",
219			      p->layer_info[i].ber_error_count);
220		n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
221			      p->layer_info[i].ber_bit_count);
222		n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
223			      p->layer_info[i].pre_ber);
224		n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
225			      p->layer_info[i].ts_per);
226		n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t",
227			      p->layer_info[i].error_ts_packets);
228		n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t",
229			      p->layer_info[i].total_ts_packets);
230		n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
231			      p->layer_info[i].ti_ldepth_i);
232		n += snprintf(&buf[n], PAGE_SIZE - n,
233			      "\tnumber_of_segments = %d\t",
234			      p->layer_info[i].number_of_segments);
235		n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
236			      p->layer_info[i].tmcc_errors);
237	}
238
239	debug_data->stats_count = n;
240	spin_unlock(&debug_data->lock);
241	wake_up(&debug_data->stats_queue);
242}
243
244static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data,
245				struct sms_isdbt_stats_ex *p)
246{
247	int i, n = 0;
248	char *buf;
249
250	spin_lock(&debug_data->lock);
251	if (debug_data->stats_count) {
252		spin_unlock(&debug_data->lock);
253		return;
254	}
255
256	buf = debug_data->stats_data;
257
258	n += snprintf(&buf[n], PAGE_SIZE - n,
259		      "statistics_type = %d\t", p->statistics_type);
260	n += snprintf(&buf[n], PAGE_SIZE - n,
261		      "full_size = %d\n", p->full_size);
262
263	n += snprintf(&buf[n], PAGE_SIZE - n,
264		      "is_rf_locked = %d\t\t", p->is_rf_locked);
265	n += snprintf(&buf[n], PAGE_SIZE - n,
266		      "is_demod_locked = %d\t", p->is_demod_locked);
267	n += snprintf(&buf[n], PAGE_SIZE - n,
268		      "is_external_lna_on = %d\n", p->is_external_lna_on);
269	n += snprintf(&buf[n], PAGE_SIZE - n,
270		      "SNR = %d dB\t\t", p->SNR);
271	n += snprintf(&buf[n], PAGE_SIZE - n,
272		      "RSSI = %d dBm\t\t", p->RSSI);
273	n += snprintf(&buf[n], PAGE_SIZE - n,
274		      "in_band_pwr = %d dBm\n", p->in_band_pwr);
275	n += snprintf(&buf[n], PAGE_SIZE - n,
276		      "carrier_offset = %d\t", p->carrier_offset);
277	n += snprintf(&buf[n], PAGE_SIZE - n,
278		      "bandwidth = %d\t\t", p->bandwidth);
279	n += snprintf(&buf[n], PAGE_SIZE - n,
280		      "frequency = %d Hz\n", p->frequency);
281	n += snprintf(&buf[n], PAGE_SIZE - n,
282		      "transmission_mode = %d\t", p->transmission_mode);
283	n += snprintf(&buf[n], PAGE_SIZE - n,
284		      "modem_state = %d\t\t", p->modem_state);
285	n += snprintf(&buf[n], PAGE_SIZE - n,
286		      "guard_interval = %d\n", p->guard_interval);
287	n += snprintf(&buf[n], PAGE_SIZE - n,
288		      "system_type = %d\t\t", p->system_type);
289	n += snprintf(&buf[n], PAGE_SIZE - n,
290		      "partial_reception = %d\t", p->partial_reception);
291	n += snprintf(&buf[n], PAGE_SIZE - n,
292		      "num_of_layers = %d\n", p->num_of_layers);
293	n += snprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t",
294		      p->segment_number);
295	n += snprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n",
296		      p->tune_bw);
297
298	for (i = 0; i < 3; i++) {
299		if (p->layer_info[i].number_of_segments < 1 ||
300		    p->layer_info[i].number_of_segments > 13)
301			continue;
302
303		n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
304		n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
305			      p->layer_info[i].code_rate);
306		n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
307			      p->layer_info[i].constellation);
308		n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
309			      p->layer_info[i].ber);
310		n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t",
311			      p->layer_info[i].ber_error_count);
312		n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
313			      p->layer_info[i].ber_bit_count);
314		n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
315			      p->layer_info[i].pre_ber);
316		n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
317			      p->layer_info[i].ts_per);
318		n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t",
319			      p->layer_info[i].error_ts_packets);
320		n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t",
321			      p->layer_info[i].total_ts_packets);
322		n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
323			      p->layer_info[i].ti_ldepth_i);
324		n += snprintf(&buf[n], PAGE_SIZE - n,
325			      "\tnumber_of_segments = %d\t",
326			      p->layer_info[i].number_of_segments);
327		n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
328			      p->layer_info[i].tmcc_errors);
329	}
330
331
332	debug_data->stats_count = n;
333	spin_unlock(&debug_data->lock);
334
335	wake_up(&debug_data->stats_queue);
336}
337
338static int smsdvb_stats_open(struct inode *inode, struct file *file)
339{
340	struct smsdvb_client_t *client = inode->i_private;
341	struct smsdvb_debugfs *debug_data = client->debug_data;
342
343	kref_get(&debug_data->refcount);
344
345	spin_lock(&debug_data->lock);
346	debug_data->stats_count = 0;
347	debug_data->stats_was_read = false;
348	spin_unlock(&debug_data->lock);
349
350	file->private_data = debug_data;
351
352	return 0;
353}
354
355static void smsdvb_debugfs_data_release(struct kref *ref)
356{
357	struct smsdvb_debugfs *debug_data;
358
359	debug_data = container_of(ref, struct smsdvb_debugfs, refcount);
360	kfree(debug_data);
361}
362
363static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data)
364{
365	int rc = 1;
366
367	spin_lock(&debug_data->lock);
368
369	if (debug_data->stats_was_read)
370		goto exit;
371
372	rc = debug_data->stats_count;
373
374exit:
375	spin_unlock(&debug_data->lock);
376	return rc;
377}
378
379static unsigned int smsdvb_stats_poll(struct file *file, poll_table *wait)
380{
381	struct smsdvb_debugfs *debug_data = file->private_data;
382	int rc;
383
384	kref_get(&debug_data->refcount);
385
386	poll_wait(file, &debug_data->stats_queue, wait);
387
388	rc = smsdvb_stats_wait_read(debug_data);
389	if (rc > 0)
390		rc = POLLIN | POLLRDNORM;
391
392	kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
393
394	return rc;
395}
396
397static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf,
398				      size_t nbytes, loff_t *ppos)
399{
400	int rc = 0, len;
401	struct smsdvb_debugfs *debug_data = file->private_data;
402
403	kref_get(&debug_data->refcount);
404
405	if (file->f_flags & O_NONBLOCK) {
406		rc = smsdvb_stats_wait_read(debug_data);
407		if (!rc) {
408			rc = -EWOULDBLOCK;
409			goto ret;
410		}
411	} else {
412		rc = wait_event_interruptible(debug_data->stats_queue,
413				      smsdvb_stats_wait_read(debug_data));
414		if (rc < 0)
415			goto ret;
416	}
417
418	if (debug_data->stats_was_read) {
419		rc = 0;	/* EOF */
420		goto ret;
421	}
422
423	len = debug_data->stats_count - *ppos;
424	if (len >= 0)
425		rc = simple_read_from_buffer(user_buf, nbytes, ppos,
426					     debug_data->stats_data, len);
427	else
428		rc = 0;
429
430	if (*ppos >= debug_data->stats_count) {
431		spin_lock(&debug_data->lock);
432		debug_data->stats_was_read = true;
433		spin_unlock(&debug_data->lock);
434	}
435ret:
436	kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
437	return rc;
438}
439
440static int smsdvb_stats_release(struct inode *inode, struct file *file)
441{
442	struct smsdvb_debugfs *debug_data = file->private_data;
443
444	spin_lock(&debug_data->lock);
445	debug_data->stats_was_read = true;	/* return EOF to read() */
446	spin_unlock(&debug_data->lock);
447	wake_up_interruptible_sync(&debug_data->stats_queue);
448
449	kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
450	file->private_data = NULL;
451
452	return 0;
453}
454
455static const struct file_operations debugfs_stats_ops = {
456	.open = smsdvb_stats_open,
457	.poll = smsdvb_stats_poll,
458	.read = smsdvb_stats_read,
459	.release = smsdvb_stats_release,
460	.llseek = generic_file_llseek,
461};
462
463/*
464 * Functions used by smsdvb, in order to create the interfaces
465 */
466
467int smsdvb_debugfs_create(struct smsdvb_client_t *client)
468{
469	struct smscore_device_t *coredev = client->coredev;
470	struct dentry *d;
471	struct smsdvb_debugfs *debug_data;
472
473	if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device)
474		return -ENODEV;
475
476	client->debugfs = debugfs_create_dir(coredev->devpath,
477					     smsdvb_debugfs_usb_root);
478	if (IS_ERR_OR_NULL(client->debugfs)) {
479		pr_info("Unable to create debugfs %s directory.\n",
480			coredev->devpath);
481		return -ENODEV;
482	}
483
484	d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs,
485				client, &debugfs_stats_ops);
486	if (!d) {
487		debugfs_remove(client->debugfs);
488		return -ENOMEM;
489	}
490
491	debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL);
492	if (!debug_data)
493		return -ENOMEM;
494
495	client->debug_data        = debug_data;
496	client->prt_dvb_stats     = smsdvb_print_dvb_stats;
497	client->prt_isdb_stats    = smsdvb_print_isdb_stats;
498	client->prt_isdb_stats_ex = smsdvb_print_isdb_stats_ex;
499
500	init_waitqueue_head(&debug_data->stats_queue);
501	spin_lock_init(&debug_data->lock);
502	kref_init(&debug_data->refcount);
503
504	return 0;
505}
506
507void smsdvb_debugfs_release(struct smsdvb_client_t *client)
508{
509	if (!client->debugfs)
510		return;
511
512	client->prt_dvb_stats     = NULL;
513	client->prt_isdb_stats    = NULL;
514	client->prt_isdb_stats_ex = NULL;
515
516	debugfs_remove_recursive(client->debugfs);
517	kref_put(&client->debug_data->refcount, smsdvb_debugfs_data_release);
518
519	client->debug_data = NULL;
520	client->debugfs = NULL;
521}
522
523int smsdvb_debugfs_register(void)
524{
525	struct dentry *d;
526
527	/*
528	 * FIXME: This was written to debug Siano USB devices. So, it creates
529	 * the debugfs node under <debugfs>/usb.
530	 * A similar logic would be needed for Siano sdio devices, but, in that
531	 * case, usb_debug_root is not a good choice.
532	 *
533	 * Perhaps the right fix here would be to create another sysfs root
534	 * node for sdio-based boards, but this may need some logic at sdio
535	 * subsystem.
536	 */
537	d = debugfs_create_dir("smsdvb", usb_debug_root);
538	if (IS_ERR_OR_NULL(d)) {
539		sms_err("Couldn't create sysfs node for smsdvb");
540		return PTR_ERR(d);
541	} else {
542		smsdvb_debugfs_usb_root = d;
543	}
544	return 0;
545}
546
547void smsdvb_debugfs_unregister(void)
548{
549	debugfs_remove_recursive(smsdvb_debugfs_usb_root);
550	smsdvb_debugfs_usb_root = NULL;
551}
552