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