1/*
2 * Copyright 2004 Digi International (www.digi.com)
3 *      Scott H Kilau <Scott_Kilau at digi dot com>
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, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
12 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 * PURPOSE.  See the GNU General Public License for more details.
14 */
15
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/ctype.h>
20#include <linux/string.h>
21#include <linux/serial_reg.h>
22#include <linux/device.h>
23#include <linux/pci.h>
24#include <linux/kdev_t.h>
25
26#include "dgnc_driver.h"
27#include "dgnc_mgmt.h"
28
29
30static ssize_t dgnc_driver_version_show(struct device_driver *ddp, char *buf)
31{
32	return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
33}
34static DRIVER_ATTR(version, S_IRUSR, dgnc_driver_version_show, NULL);
35
36
37static ssize_t dgnc_driver_boards_show(struct device_driver *ddp, char *buf)
38{
39	return snprintf(buf, PAGE_SIZE, "%d\n", dgnc_NumBoards);
40}
41static DRIVER_ATTR(boards, S_IRUSR, dgnc_driver_boards_show, NULL);
42
43
44static ssize_t dgnc_driver_maxboards_show(struct device_driver *ddp, char *buf)
45{
46	return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
47}
48static DRIVER_ATTR(maxboards, S_IRUSR, dgnc_driver_maxboards_show, NULL);
49
50
51static ssize_t dgnc_driver_pollrate_show(struct device_driver *ddp, char *buf)
52{
53	return snprintf(buf, PAGE_SIZE, "%dms\n", dgnc_poll_tick);
54}
55
56static ssize_t dgnc_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count)
57{
58	int ret;
59
60	ret = sscanf(buf, "%d\n", &dgnc_poll_tick);
61	if (ret != 1)
62		return -EINVAL;
63	return count;
64}
65static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgnc_driver_pollrate_show, dgnc_driver_pollrate_store);
66
67
68void dgnc_create_driver_sysfiles(struct pci_driver *dgnc_driver)
69{
70	int rc = 0;
71	struct device_driver *driverfs = &dgnc_driver->driver;
72
73	rc |= driver_create_file(driverfs, &driver_attr_version);
74	rc |= driver_create_file(driverfs, &driver_attr_boards);
75	rc |= driver_create_file(driverfs, &driver_attr_maxboards);
76	rc |= driver_create_file(driverfs, &driver_attr_pollrate);
77	if (rc)
78		pr_err("DGNC: sysfs driver_create_file failed!\n");
79}
80
81
82void dgnc_remove_driver_sysfiles(struct pci_driver *dgnc_driver)
83{
84	struct device_driver *driverfs = &dgnc_driver->driver;
85
86	driver_remove_file(driverfs, &driver_attr_version);
87	driver_remove_file(driverfs, &driver_attr_boards);
88	driver_remove_file(driverfs, &driver_attr_maxboards);
89	driver_remove_file(driverfs, &driver_attr_pollrate);
90}
91
92
93#define DGNC_VERIFY_BOARD(p, bd)				\
94	do {							\
95		if (!p)						\
96			return 0;				\
97								\
98		bd = dev_get_drvdata(p);			\
99		if (!bd || bd->magic != DGNC_BOARD_MAGIC)	\
100			return 0;				\
101		if (bd->state != BOARD_READY)			\
102			return 0;				\
103	} while (0)
104
105
106
107static ssize_t dgnc_vpd_show(struct device *p, struct device_attribute *attr, char *buf)
108{
109	struct dgnc_board *bd;
110	int count = 0;
111	int i = 0;
112
113	DGNC_VERIFY_BOARD(p, bd);
114
115	count += sprintf(buf + count, "\n      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
116	for (i = 0; i < 0x40 * 2; i++) {
117		if (!(i % 16))
118			count += sprintf(buf + count, "\n%04X ", i * 2);
119		count += sprintf(buf + count, "%02X ", bd->vpd[i]);
120	}
121	count += sprintf(buf + count, "\n");
122
123	return count;
124}
125static DEVICE_ATTR(vpd, S_IRUSR, dgnc_vpd_show, NULL);
126
127static ssize_t dgnc_serial_number_show(struct device *p, struct device_attribute *attr, char *buf)
128{
129	struct dgnc_board *bd;
130	int count = 0;
131
132	DGNC_VERIFY_BOARD(p, bd);
133
134	if (bd->serial_num[0] == '\0')
135		count += sprintf(buf + count, "<UNKNOWN>\n");
136	else
137		count += sprintf(buf + count, "%s\n", bd->serial_num);
138
139	return count;
140}
141static DEVICE_ATTR(serial_number, S_IRUSR, dgnc_serial_number_show, NULL);
142
143
144static ssize_t dgnc_ports_state_show(struct device *p, struct device_attribute *attr, char *buf)
145{
146	struct dgnc_board *bd;
147	int count = 0;
148	int i = 0;
149
150	DGNC_VERIFY_BOARD(p, bd);
151
152	for (i = 0; i < bd->nasync; i++) {
153		count += snprintf(buf + count, PAGE_SIZE - count,
154			"%d %s\n", bd->channels[i]->ch_portnum,
155			bd->channels[i]->ch_open_count ? "Open" : "Closed");
156	}
157	return count;
158}
159static DEVICE_ATTR(ports_state, S_IRUSR, dgnc_ports_state_show, NULL);
160
161
162static ssize_t dgnc_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf)
163{
164	struct dgnc_board *bd;
165	int count = 0;
166	int i = 0;
167
168	DGNC_VERIFY_BOARD(p, bd);
169
170	for (i = 0; i < bd->nasync; i++) {
171		count +=  snprintf(buf + count, PAGE_SIZE - count,
172			"%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_old_baud);
173	}
174	return count;
175}
176static DEVICE_ATTR(ports_baud, S_IRUSR, dgnc_ports_baud_show, NULL);
177
178
179static ssize_t dgnc_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf)
180{
181	struct dgnc_board *bd;
182	int count = 0;
183	int i = 0;
184
185	DGNC_VERIFY_BOARD(p, bd);
186
187	for (i = 0; i < bd->nasync; i++) {
188		if (bd->channels[i]->ch_open_count) {
189			count += snprintf(buf + count, PAGE_SIZE - count,
190				"%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum,
191				(bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
192				(bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
193				(bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
194				(bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
195				(bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
196				(bd->channels[i]->ch_mistat & UART_MSR_RI)  ? "RI"  : "");
197		} else {
198			count += snprintf(buf + count, PAGE_SIZE - count,
199				"%d\n", bd->channels[i]->ch_portnum);
200		}
201	}
202	return count;
203}
204static DEVICE_ATTR(ports_msignals, S_IRUSR, dgnc_ports_msignals_show, NULL);
205
206
207static ssize_t dgnc_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf)
208{
209	struct dgnc_board *bd;
210	int count = 0;
211	int i = 0;
212
213	DGNC_VERIFY_BOARD(p, bd);
214
215	for (i = 0; i < bd->nasync; i++) {
216		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
217			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag);
218	}
219	return count;
220}
221static DEVICE_ATTR(ports_iflag, S_IRUSR, dgnc_ports_iflag_show, NULL);
222
223
224static ssize_t dgnc_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf)
225{
226	struct dgnc_board *bd;
227	int count = 0;
228	int i = 0;
229
230	DGNC_VERIFY_BOARD(p, bd);
231
232	for (i = 0; i < bd->nasync; i++) {
233		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
234			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag);
235	}
236	return count;
237}
238static DEVICE_ATTR(ports_cflag, S_IRUSR, dgnc_ports_cflag_show, NULL);
239
240
241static ssize_t dgnc_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf)
242{
243	struct dgnc_board *bd;
244	int count = 0;
245	int i = 0;
246
247	DGNC_VERIFY_BOARD(p, bd);
248
249	for (i = 0; i < bd->nasync; i++) {
250		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
251			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag);
252	}
253	return count;
254}
255static DEVICE_ATTR(ports_oflag, S_IRUSR, dgnc_ports_oflag_show, NULL);
256
257
258static ssize_t dgnc_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf)
259{
260	struct dgnc_board *bd;
261	int count = 0;
262	int i = 0;
263
264	DGNC_VERIFY_BOARD(p, bd);
265
266	for (i = 0; i < bd->nasync; i++) {
267		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
268			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag);
269	}
270	return count;
271}
272static DEVICE_ATTR(ports_lflag, S_IRUSR, dgnc_ports_lflag_show, NULL);
273
274
275static ssize_t dgnc_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf)
276{
277	struct dgnc_board *bd;
278	int count = 0;
279	int i = 0;
280
281	DGNC_VERIFY_BOARD(p, bd);
282
283	for (i = 0; i < bd->nasync; i++) {
284		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
285			bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags);
286	}
287	return count;
288}
289static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgnc_ports_digi_flag_show, NULL);
290
291
292static ssize_t dgnc_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf)
293{
294	struct dgnc_board *bd;
295	int count = 0;
296	int i = 0;
297
298	DGNC_VERIFY_BOARD(p, bd);
299
300	for (i = 0; i < bd->nasync; i++) {
301		count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
302			bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount);
303	}
304	return count;
305}
306static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgnc_ports_rxcount_show, NULL);
307
308
309static ssize_t dgnc_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf)
310{
311	struct dgnc_board *bd;
312	int count = 0;
313	int i = 0;
314
315	DGNC_VERIFY_BOARD(p, bd);
316
317	for (i = 0; i < bd->nasync; i++) {
318		count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
319			bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount);
320	}
321	return count;
322}
323static DEVICE_ATTR(ports_txcount, S_IRUSR, dgnc_ports_txcount_show, NULL);
324
325
326/* this function creates the sys files that will export each signal status
327 * to sysfs each value will be put in a separate filename
328 */
329void dgnc_create_ports_sysfiles(struct dgnc_board *bd)
330{
331	int rc = 0;
332
333	dev_set_drvdata(&bd->pdev->dev, bd);
334	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state);
335	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud);
336	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
337	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
338	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
339	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
340	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
341	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
342	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
343	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
344	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_vpd);
345	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_serial_number);
346	if (rc)
347		dev_err(&bd->pdev->dev, "dgnc: sysfs device_create_file failed!\n");
348}
349
350
351/* removes all the sys files created for that port */
352void dgnc_remove_ports_sysfiles(struct dgnc_board *bd)
353{
354	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state);
355	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud);
356	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
357	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
358	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
359	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
360	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
361	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
362	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
363	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
364	device_remove_file(&(bd->pdev->dev), &dev_attr_vpd);
365	device_remove_file(&(bd->pdev->dev), &dev_attr_serial_number);
366}
367
368
369static ssize_t dgnc_tty_state_show(struct device *d, struct device_attribute *attr, char *buf)
370{
371	struct dgnc_board *bd;
372	struct channel_t *ch;
373	struct un_t *un;
374
375	if (!d)
376		return 0;
377	un = dev_get_drvdata(d);
378	if (!un || un->magic != DGNC_UNIT_MAGIC)
379		return 0;
380	ch = un->un_ch;
381	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
382		return 0;
383	bd = ch->ch_bd;
384	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
385		return 0;
386	if (bd->state != BOARD_READY)
387		return 0;
388
389	return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed");
390}
391static DEVICE_ATTR(state, S_IRUSR, dgnc_tty_state_show, NULL);
392
393
394static ssize_t dgnc_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf)
395{
396	struct dgnc_board *bd;
397	struct channel_t *ch;
398	struct un_t *un;
399
400	if (!d)
401		return 0;
402	un = dev_get_drvdata(d);
403	if (!un || un->magic != DGNC_UNIT_MAGIC)
404		return 0;
405	ch = un->un_ch;
406	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
407		return 0;
408	bd = ch->ch_bd;
409	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
410		return 0;
411	if (bd->state != BOARD_READY)
412		return 0;
413
414	return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_old_baud);
415}
416static DEVICE_ATTR(baud, S_IRUSR, dgnc_tty_baud_show, NULL);
417
418
419static ssize_t dgnc_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf)
420{
421	struct dgnc_board *bd;
422	struct channel_t *ch;
423	struct un_t *un;
424
425	if (!d)
426		return 0;
427	un = dev_get_drvdata(d);
428	if (!un || un->magic != DGNC_UNIT_MAGIC)
429		return 0;
430	ch = un->un_ch;
431	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
432		return 0;
433	bd = ch->ch_bd;
434	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
435		return 0;
436	if (bd->state != BOARD_READY)
437		return 0;
438
439	if (ch->ch_open_count) {
440		return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
441			(ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
442			(ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
443			(ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
444			(ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
445			(ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
446			(ch->ch_mistat & UART_MSR_RI)  ? "RI"  : "");
447	}
448	return 0;
449}
450static DEVICE_ATTR(msignals, S_IRUSR, dgnc_tty_msignals_show, NULL);
451
452
453static ssize_t dgnc_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf)
454{
455	struct dgnc_board *bd;
456	struct channel_t *ch;
457	struct un_t *un;
458
459	if (!d)
460		return 0;
461	un = dev_get_drvdata(d);
462	if (!un || un->magic != DGNC_UNIT_MAGIC)
463		return 0;
464	ch = un->un_ch;
465	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
466		return 0;
467	bd = ch->ch_bd;
468	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
469		return 0;
470	if (bd->state != BOARD_READY)
471		return 0;
472
473	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
474}
475static DEVICE_ATTR(iflag, S_IRUSR, dgnc_tty_iflag_show, NULL);
476
477
478static ssize_t dgnc_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf)
479{
480	struct dgnc_board *bd;
481	struct channel_t *ch;
482	struct un_t *un;
483
484	if (!d)
485		return 0;
486	un = dev_get_drvdata(d);
487	if (!un || un->magic != DGNC_UNIT_MAGIC)
488		return 0;
489	ch = un->un_ch;
490	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
491		return 0;
492	bd = ch->ch_bd;
493	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
494		return 0;
495	if (bd->state != BOARD_READY)
496		return 0;
497
498	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
499}
500static DEVICE_ATTR(cflag, S_IRUSR, dgnc_tty_cflag_show, NULL);
501
502
503static ssize_t dgnc_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf)
504{
505	struct dgnc_board *bd;
506	struct channel_t *ch;
507	struct un_t *un;
508
509	if (!d)
510		return 0;
511	un = dev_get_drvdata(d);
512	if (!un || un->magic != DGNC_UNIT_MAGIC)
513		return 0;
514	ch = un->un_ch;
515	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
516		return 0;
517	bd = ch->ch_bd;
518	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
519		return 0;
520	if (bd->state != BOARD_READY)
521		return 0;
522
523	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
524}
525static DEVICE_ATTR(oflag, S_IRUSR, dgnc_tty_oflag_show, NULL);
526
527
528static ssize_t dgnc_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf)
529{
530	struct dgnc_board *bd;
531	struct channel_t *ch;
532	struct un_t *un;
533
534	if (!d)
535		return 0;
536	un = dev_get_drvdata(d);
537	if (!un || un->magic != DGNC_UNIT_MAGIC)
538		return 0;
539	ch = un->un_ch;
540	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
541		return 0;
542	bd = ch->ch_bd;
543	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
544		return 0;
545	if (bd->state != BOARD_READY)
546		return 0;
547
548	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
549}
550static DEVICE_ATTR(lflag, S_IRUSR, dgnc_tty_lflag_show, NULL);
551
552
553static ssize_t dgnc_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf)
554{
555	struct dgnc_board *bd;
556	struct channel_t *ch;
557	struct un_t *un;
558
559	if (!d)
560		return 0;
561	un = dev_get_drvdata(d);
562	if (!un || un->magic != DGNC_UNIT_MAGIC)
563		return 0;
564	ch = un->un_ch;
565	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
566		return 0;
567	bd = ch->ch_bd;
568	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
569		return 0;
570	if (bd->state != BOARD_READY)
571		return 0;
572
573	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
574}
575static DEVICE_ATTR(digi_flag, S_IRUSR, dgnc_tty_digi_flag_show, NULL);
576
577
578static ssize_t dgnc_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf)
579{
580	struct dgnc_board *bd;
581	struct channel_t *ch;
582	struct un_t *un;
583
584	if (!d)
585		return 0;
586	un = dev_get_drvdata(d);
587	if (!un || un->magic != DGNC_UNIT_MAGIC)
588		return 0;
589	ch = un->un_ch;
590	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
591		return 0;
592	bd = ch->ch_bd;
593	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
594		return 0;
595	if (bd->state != BOARD_READY)
596		return 0;
597
598	return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
599}
600static DEVICE_ATTR(rxcount, S_IRUSR, dgnc_tty_rxcount_show, NULL);
601
602
603static ssize_t dgnc_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf)
604{
605	struct dgnc_board *bd;
606	struct channel_t *ch;
607	struct un_t *un;
608
609	if (!d)
610		return 0;
611	un = dev_get_drvdata(d);
612	if (!un || un->magic != DGNC_UNIT_MAGIC)
613		return 0;
614	ch = un->un_ch;
615	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
616		return 0;
617	bd = ch->ch_bd;
618	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
619		return 0;
620	if (bd->state != BOARD_READY)
621		return 0;
622
623	return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
624}
625static DEVICE_ATTR(txcount, S_IRUSR, dgnc_tty_txcount_show, NULL);
626
627
628static ssize_t dgnc_tty_name_show(struct device *d, struct device_attribute *attr, char *buf)
629{
630	struct dgnc_board *bd;
631	struct channel_t *ch;
632	struct un_t *un;
633
634	if (!d)
635		return 0;
636	un = dev_get_drvdata(d);
637	if (!un || un->magic != DGNC_UNIT_MAGIC)
638		return 0;
639	ch = un->un_ch;
640	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
641		return 0;
642	bd = ch->ch_bd;
643	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
644		return 0;
645	if (bd->state != BOARD_READY)
646		return 0;
647
648	return snprintf(buf, PAGE_SIZE, "%sn%d%c\n",
649		(un->un_type == DGNC_PRINT) ? "pr" : "tty",
650		bd->boardnum + 1, 'a' + ch->ch_portnum);
651}
652static DEVICE_ATTR(custom_name, S_IRUSR, dgnc_tty_name_show, NULL);
653
654
655static struct attribute *dgnc_sysfs_tty_entries[] = {
656	&dev_attr_state.attr,
657	&dev_attr_baud.attr,
658	&dev_attr_msignals.attr,
659	&dev_attr_iflag.attr,
660	&dev_attr_cflag.attr,
661	&dev_attr_oflag.attr,
662	&dev_attr_lflag.attr,
663	&dev_attr_digi_flag.attr,
664	&dev_attr_rxcount.attr,
665	&dev_attr_txcount.attr,
666	&dev_attr_custom_name.attr,
667	NULL
668};
669
670
671static struct attribute_group dgnc_tty_attribute_group = {
672	.name = NULL,
673	.attrs = dgnc_sysfs_tty_entries,
674};
675
676
677void dgnc_create_tty_sysfs(struct un_t *un, struct device *c)
678{
679	int ret;
680
681	ret = sysfs_create_group(&c->kobj, &dgnc_tty_attribute_group);
682	if (ret) {
683		dev_err(c, "dgnc: failed to create sysfs tty device attributes.\n");
684		sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);
685		return;
686	}
687
688	dev_set_drvdata(c, un);
689
690}
691
692
693void dgnc_remove_tty_sysfs(struct device *c)
694{
695	sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);
696}
697
698