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