blob: 9112dd2bf4d7757503ea1b53191d213dcbc93785 [file] [log] [blame]
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001/*
2 * Copyright 2003 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.
Masanari Iida818cc6f2014-01-15 00:40:44 +09009 *
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040010 * This program is distributed in the hope that it will be useful,
Masanari Iida818cc6f2014-01-15 00:40:44 +090011 * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
12 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040013 * PURPOSE. See the GNU General Public License for more details.
Masanari Iida818cc6f2014-01-15 00:40:44 +090014 *
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040015 */
16
Mark Hounschellb28ec882014-02-20 08:48:48 -050017/*
18 * In the original out of kernel Digi dgap driver, firmware
19 * loading was done via user land to driver handshaking.
20 *
21 * For cards that support a concentrator (port expander),
22 * I believe the concentrator its self told the card which
23 * concentrator is actually attached and then that info
24 * was used to tell user land which concentrator firmware
25 * image was to be downloaded. I think even the BIOS or
26 * FEP images required could change with the connection
27 * of a particular concentrator.
28 *
29 * Since I have no access to any of these cards or
30 * concentrators, I cannot put the correct concentrator
31 * firmware file names into the firmware_info structure
32 * as is now done for the BIOS and FEP images.
33 *
34 * I think, but am not certain, that the cards supporting
35 * concentrators will function without them. So support
36 * of these cards has been left in this driver.
37 *
38 * In order to fully support those cards, they would
39 * either have to be acquired for dissection or maybe
40 * Digi International could provide some assistance.
41 */
42#undef DIGI_CONCENTRATORS_SUPPORTED
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040043
Daeseok Youn6c66843d2014-08-09 14:39:29 +090044#define pr_fmt(fmt) "dgap: " fmt
45
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040046#include <linux/kernel.h>
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040047#include <linux/module.h>
48#include <linux/pci.h>
49#include <linux/delay.h> /* For udelay */
Geert Uytterhoeven351699d2013-08-29 22:53:25 +020050#include <linux/slab.h>
Mark Hounschell3d9dc5d2014-02-28 12:42:12 -050051#include <linux/uaccess.h>
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040052#include <linux/sched.h>
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040053
Mark Hounschella6792a32014-02-19 13:11:59 -050054#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
55#include <linux/ctype.h>
56#include <linux/tty.h>
57#include <linux/tty_flip.h>
58#include <linux/serial_reg.h>
Mark Hounschell3d9dc5d2014-02-28 12:42:12 -050059#include <linux/io.h> /* For read[bwl]/write[bwl] */
Mark Hounschella6792a32014-02-19 13:11:59 -050060
Mark Hounschell7568f7d2014-02-19 13:12:01 -050061#include <linux/string.h>
62#include <linux/device.h>
63#include <linux/kdev_t.h>
Mark Hounschellb28ec882014-02-20 08:48:48 -050064#include <linux/firmware.h>
Mark Hounschell7568f7d2014-02-19 13:12:01 -050065
Mark Hounschellffc1c1d2014-02-19 13:12:14 -050066#include "dgap.h"
Mark Hounschella6792a32014-02-19 13:11:59 -050067
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040068/*
69 * File operations permitted on Control/Management major.
70 */
Mark Hounschellfea06832014-04-25 16:49:29 -040071static const struct file_operations dgap_board_fops = {
Mark Hounschell305ec872014-02-28 12:42:13 -050072 .owner = THIS_MODULE,
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040073};
74
Mark Hounschellfea06832014-04-25 16:49:29 -040075static uint dgap_numboards;
76static struct board_t *dgap_board[MAXBOARDS];
Mark Hounschellb115b022014-02-28 12:42:15 -050077static ulong dgap_poll_counter;
Mark Hounschellb115b022014-02-28 12:42:15 -050078static int dgap_driver_state = DRIVER_INITIALIZED;
Mark Hounschellb115b022014-02-28 12:42:15 -050079static int dgap_poll_tick = 20; /* Poll interval - 20 ms */
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040080
Mark Hounschellb115b022014-02-28 12:42:15 -050081static struct class *dgap_class;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040082
Mark Hounschellb053bb82014-02-19 13:12:00 -050083static uint dgap_count = 500;
Mark Hounschella6792a32014-02-19 13:11:59 -050084
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040085/*
86 * Poller stuff
87 */
Mark Hounschell45c44dd2014-04-24 10:33:58 -040088static DEFINE_SPINLOCK(dgap_poll_lock); /* Poll scheduling lock */
Mark Hounschellb115b022014-02-28 12:42:15 -050089static ulong dgap_poll_time; /* Time of next poll */
90static uint dgap_poll_stop; /* Used to tell poller to stop */
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -040091static struct timer_list dgap_poll_timer;
92
Mark Hounschellb28ec882014-02-20 08:48:48 -050093/*
94 SUPPORTED PRODUCTS
95
96 Card Model Number of Ports Interface
97 ----------------------------------------------------------------
98 Acceleport Xem 4 - 64 (EIA232 & EIA422)
99 Acceleport Xr 4 & 8 (EIA232)
100 Acceleport Xr 920 4 & 8 (EIA232)
101 Acceleport C/X 8 - 128 (EIA232)
102 Acceleport EPC/X 8 - 224 (EIA232)
103 Acceleport Xr/422 4 & 8 (EIA422)
104 Acceleport 2r/920 2 (EIA232)
105 Acceleport 4r/920 4 (EIA232)
106 Acceleport 8r/920 8 (EIA232)
107
108 IBM 8-Port Asynchronous PCI Adapter (EIA232)
109 IBM 128-Port Asynchronous PCI Adapter (EIA232 & EIA422)
110*/
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400111
112static struct pci_device_id dgap_pci_tbl[] = {
Mark Hounschell2f60b332014-03-04 16:03:12 -0500113 { DIGI_VID, PCI_DEV_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
114 { DIGI_VID, PCI_DEV_CX_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
115 { DIGI_VID, PCI_DEV_CX_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
116 { DIGI_VID, PCI_DEV_EPCJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
117 { DIGI_VID, PCI_DEV_920_2_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
118 { DIGI_VID, PCI_DEV_920_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
119 { DIGI_VID, PCI_DEV_920_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
120 { DIGI_VID, PCI_DEV_XR_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
121 { DIGI_VID, PCI_DEV_XRJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
122 { DIGI_VID, PCI_DEV_XR_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
123 { DIGI_VID, PCI_DEV_XR_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
124 { DIGI_VID, PCI_DEV_XR_SAIP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
125 { DIGI_VID, PCI_DEV_XR_BULL_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
126 { DIGI_VID, PCI_DEV_920_8_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
127 { DIGI_VID, PCI_DEV_XEM_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400128 {0,} /* 0 terminated list. */
129};
130MODULE_DEVICE_TABLE(pci, dgap_pci_tbl);
131
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400132/*
133 * A generic list of Product names, PCI Vendor ID, and PCI Device ID.
134 */
135struct board_id {
136 uint config_type;
Mark Hounschell2023d182014-04-14 16:42:43 -0400137 u8 *name;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400138 uint maxports;
139 uint dpatype;
140};
141
Mark Hounschellfea06832014-04-25 16:49:29 -0400142static struct board_id dgap_ids[] = {
Mark Hounschell2f60b332014-03-04 16:03:12 -0500143 { PPCM, PCI_DEV_XEM_NAME, 64, (T_PCXM|T_PCLITE|T_PCIBUS) },
144 { PCX, PCI_DEV_CX_NAME, 128, (T_CX|T_PCIBUS) },
145 { PCX, PCI_DEV_CX_IBM_NAME, 128, (T_CX|T_PCIBUS) },
146 { PEPC, PCI_DEV_EPCJ_NAME, 224, (T_EPC|T_PCIBUS) },
147 { APORT2_920P, PCI_DEV_920_2_NAME, 2, (T_PCXR|T_PCLITE|T_PCIBUS) },
148 { APORT4_920P, PCI_DEV_920_4_NAME, 4, (T_PCXR|T_PCLITE|T_PCIBUS) },
149 { APORT8_920P, PCI_DEV_920_8_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
150 { PAPORT8, PCI_DEV_XR_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
151 { PAPORT8, PCI_DEV_XRJ_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
152 { PAPORT8, PCI_DEV_XR_422_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
153 { PAPORT8, PCI_DEV_XR_IBM_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
154 { PAPORT8, PCI_DEV_XR_SAIP_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
155 { PAPORT8, PCI_DEV_XR_BULL_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
156 { APORT8_920P, PCI_DEV_920_8_HP_NAME, 8, (T_PCXR|T_PCLITE|T_PCIBUS) },
157 { PPCM, PCI_DEV_XEM_HP_NAME, 64, (T_PCXM|T_PCLITE|T_PCIBUS) },
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400158 {0,} /* 0 terminated list. */
159};
160
Mark Hounschellb28ec882014-02-20 08:48:48 -0500161struct firmware_info {
Mark Hounschell174efc12014-05-23 12:54:04 -0400162 u8 *conf_name; /* dgap.conf */
Mark Hounschell2023d182014-04-14 16:42:43 -0400163 u8 *bios_name; /* BIOS filename */
164 u8 *fep_name; /* FEP filename */
165 u8 *con_name; /* Concentrator filename FIXME*/
Mark Hounschell174efc12014-05-23 12:54:04 -0400166 int num; /* sequence number */
Mark Hounschellb28ec882014-02-20 08:48:48 -0500167};
168
169/*
170 * Firmware - BIOS, FEP, and CONC filenames
171 */
172static struct firmware_info fw_info[] = {
Mark Hounschell8f5879c2014-04-24 10:41:44 -0400173 { "dgap/dgap.conf", "dgap/sxbios.bin", "dgap/sxfep.bin", NULL, 0 },
174 { "dgap/dgap.conf", "dgap/cxpbios.bin", "dgap/cxpfep.bin", NULL, 1 },
175 { "dgap/dgap.conf", "dgap/cxpbios.bin", "dgap/cxpfep.bin", NULL, 2 },
176 { "dgap/dgap.conf", "dgap/pcibios.bin", "dgap/pcifep.bin", NULL, 3 },
177 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 4 },
178 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 5 },
179 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 6 },
180 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 7 },
181 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 8 },
182 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 9 },
183 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 10 },
184 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 11 },
185 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 12 },
186 { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", NULL, 13 },
187 { "dgap/dgap.conf", "dgap/sxbios.bin", "dgap/sxfep.bin", NULL, 14 },
188 {NULL,}
Mark Hounschellb28ec882014-02-20 08:48:48 -0500189};
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400190
Mark Hounschella6792a32014-02-19 13:11:59 -0500191/*
192 * Default transparent print information.
193 */
194static struct digi_t dgap_digi_init = {
195 .digi_flags = DIGI_COOK, /* Flags */
196 .digi_maxcps = 100, /* Max CPS */
197 .digi_maxchar = 50, /* Max chars in print queue */
198 .digi_bufsize = 100, /* Printer buffer size */
199 .digi_onlen = 4, /* size of printer on string */
200 .digi_offlen = 4, /* size of printer off string */
201 .digi_onstr = "\033[5i", /* ANSI printer on string ] */
202 .digi_offstr = "\033[4i", /* ANSI printer off string ] */
203 .digi_term = "ansi" /* default terminal type */
204};
205
Mark Hounschella6792a32014-02-19 13:11:59 -0500206/*
207 * Define a local default termios struct. All ports will be created
208 * with this termios initially.
209 *
210 * This defines a raw port at 9600 baud, 8 data bits, no parity,
211 * 1 stop bit.
212 */
213
Mark Hounschellfea06832014-04-25 16:49:29 -0400214static struct ktermios dgap_default_termios = {
Mark Hounschella6792a32014-02-19 13:11:59 -0500215 .c_iflag = (DEFAULT_IFLAGS), /* iflags */
216 .c_oflag = (DEFAULT_OFLAGS), /* oflags */
217 .c_cflag = (DEFAULT_CFLAGS), /* cflags */
218 .c_lflag = (DEFAULT_LFLAGS), /* lflags */
219 .c_cc = INIT_C_CC,
Mark Hounschell7d6069d72014-02-28 12:42:10 -0500220 .c_line = 0,
Mark Hounschella6792a32014-02-19 13:11:59 -0500221};
222
Mark Hounschell69edaa22014-02-19 13:12:02 -0500223/*
224 * Our needed internal static variables from dgap_parse.c
225 */
226static struct cnode dgap_head;
227#define MAXCWORD 200
228static char dgap_cword[MAXCWORD];
229
230struct toklist {
Mark Hounschell174efc12014-05-23 12:54:04 -0400231 int token;
232 char *string;
Mark Hounschell69edaa22014-02-19 13:12:02 -0500233};
234
Daeseok Youn77a44922014-08-09 14:38:14 +0900235static struct toklist dgap_brdtype[] = {
Mark Hounschell2f60b332014-03-04 16:03:12 -0500236 { PCX, "Digi_AccelePort_C/X_PCI" },
237 { PEPC, "Digi_AccelePort_EPC/X_PCI" },
238 { PPCM, "Digi_AccelePort_Xem_PCI" },
239 { APORT2_920P, "Digi_AccelePort_2r_920_PCI" },
240 { APORT4_920P, "Digi_AccelePort_4r_920_PCI" },
241 { APORT8_920P, "Digi_AccelePort_8r_920_PCI" },
242 { PAPORT4, "Digi_AccelePort_4r_PCI(EIA-232/RS-422)" },
243 { PAPORT8, "Digi_AccelePort_8r_PCI(EIA-232/RS-422)" },
Daeseok Youn77a44922014-08-09 14:38:14 +0900244 { 0, NULL }
245};
246
247static struct toklist dgap_tlist[] = {
248 { BEGIN, "config_begin" },
249 { END, "config_end" },
250 { BOARD, "board" },
Mark Hounschell2f60b332014-03-04 16:03:12 -0500251 { IO, "io" },
252 { PCIINFO, "pciinfo" },
253 { LINE, "line" },
254 { CONC, "conc" },
255 { CONC, "concentrator" },
256 { CX, "cx" },
257 { CX, "ccon" },
258 { EPC, "epccon" },
259 { EPC, "epc" },
260 { MOD, "module" },
261 { ID, "id" },
262 { STARTO, "start" },
263 { SPEED, "speed" },
264 { CABLE, "cable" },
265 { CONNECT, "connect" },
266 { METHOD, "method" },
267 { STATUS, "status" },
268 { CUSTOM, "Custom" },
269 { BASIC, "Basic" },
270 { MEM, "mem" },
271 { MEM, "memory" },
272 { PORTS, "ports" },
273 { MODEM, "modem" },
274 { NPORTS, "nports" },
275 { TTYN, "ttyname" },
276 { CU, "cuname" },
277 { PRINT, "prname" },
278 { CMAJOR, "major" },
279 { ALTPIN, "altpin" },
280 { USEINTR, "useintr" },
281 { TTSIZ, "ttysize" },
282 { CHSIZ, "chsize" },
283 { BSSIZ, "boardsize" },
284 { UNTSIZ, "schedsize" },
285 { F2SIZ, "f2200size" },
286 { VPSIZ, "vpixsize" },
287 { 0, NULL }
Mark Hounschell69edaa22014-02-19 13:12:02 -0500288};
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400289
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400290
291/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900292 * dgap_sindex: much like index(), but it looks for a match of any character in
Sudip Mukherjee56f40e52015-05-09 17:59:42 +0530293 * the group, and returns that position.
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400294 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900295static char *dgap_sindex(char *string, char *group)
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400296{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900297 char *ptr;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400298
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900299 if (!string || !group)
300 return NULL;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400301
Sudip Mukherjee56f40e52015-05-09 17:59:42 +0530302 for (; *string; string++) {
303 for (ptr = group; *ptr; ptr++) {
304 if (*ptr == *string)
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900305 return string;
306 }
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900307 }
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400308
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900309 return NULL;
310}
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400311
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900312/*
313 * get a word from the input stream, also keep track of current line number.
314 * words are separated by whitespace.
315 */
316static char *dgap_getword(char **in)
317{
318 char *ret_ptr = *in;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400319
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900320 char *ptr = dgap_sindex(*in, " \t\n");
321
322 /* If no word found, return null */
323 if (!ptr)
324 return NULL;
325
326 /* Mark new location for our buffer */
327 *ptr = '\0';
328 *in = ptr + 1;
329
330 /* Eat any extra spaces/tabs/newlines that might be present */
331 while (*in && **in && ((**in == ' ') ||
332 (**in == '\t') ||
333 (**in == '\n'))) {
334 **in = '\0';
335 *in = *in + 1;
336 }
337
338 return ret_ptr;
339}
340
341
342/*
343 * Get a token from the input file; return 0 if end of file is reached
344 */
345static int dgap_gettok(char **in)
346{
347 char *w;
348 struct toklist *t;
349
350 if (strstr(dgap_cword, "board")) {
351 w = dgap_getword(in);
352 snprintf(dgap_cword, MAXCWORD, "%s", w);
353 for (t = dgap_brdtype; t->token != 0; t++) {
354 if (!strcmp(w, t->string))
355 return t->token;
356 }
357 } else {
358 while ((w = dgap_getword(in))) {
359 snprintf(dgap_cword, MAXCWORD, "%s", w);
360 for (t = dgap_tlist; t->token != 0; t++) {
361 if (!strcmp(w, t->string))
362 return t->token;
363 }
364 }
365 }
Mark Hounschell002de0b2014-03-06 15:25:19 -0500366
367 return 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400368}
369
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400370/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900371 * dgap_checknode: see if all the necessary info has been supplied for a node
372 * before creating the next node.
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400373 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900374static int dgap_checknode(struct cnode *p)
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400375{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900376 switch (p->type) {
377 case LNODE:
378 if (p->u.line.v_speed == 0) {
379 pr_err("line speed not specified");
380 return 1;
381 }
382 return 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400383
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900384 case CNODE:
385 if (p->u.conc.v_speed == 0) {
386 pr_err("concentrator line speed not specified");
387 return 1;
388 }
389 if (p->u.conc.v_nport == 0) {
390 pr_err("number of ports on concentrator not specified");
391 return 1;
392 }
393 if (p->u.conc.v_id == 0) {
394 pr_err("concentrator id letter not specified");
395 return 1;
396 }
397 return 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400398
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900399 case MNODE:
400 if (p->u.module.v_nport == 0) {
401 pr_err("number of ports on EBI module not specified");
402 return 1;
403 }
404 if (p->u.module.v_id == 0) {
405 pr_err("EBI module id letter not specified");
406 return 1;
407 }
408 return 0;
Alexey Khoroshilov0669e5f2014-03-09 01:01:34 +0400409 }
Daeseok Youn3c3befe2014-06-13 18:22:40 +0900410 return 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400411}
412
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400413/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900414 * Given a board pointer, returns whether we should use interrupts or not.
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400415 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900416static uint dgap_config_get_useintr(struct board_t *bd)
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400417{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900418 struct cnode *p;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400419
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900420 if (!bd)
421 return 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400422
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900423 for (p = bd->bd_config; p; p = p->next) {
424 if (p->type == INTRNODE) {
425 /*
426 * check for pcxr types.
427 */
428 return p->u.useintr;
429 }
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400430 }
431
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900432 /* If not found, then don't turn on interrupts. */
433 return 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400434}
435
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400436/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900437 * Given a board pointer, returns whether we turn on altpin or not.
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400438 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900439static uint dgap_config_get_altpin(struct board_t *bd)
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400440{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900441 struct cnode *p;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400442
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900443 if (!bd)
444 return 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400445
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900446 for (p = bd->bd_config; p; p = p->next) {
447 if (p->type == ANODE) {
448 /*
449 * check for pcxr types.
450 */
451 return p->u.altpin;
452 }
453 }
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400454
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900455 /* If not found, then don't turn on interrupts. */
456 return 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400457}
458
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400459/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900460 * Given a specific type of board, if found, detached link and
461 * returns the first occurrence in the list.
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400462 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900463static struct cnode *dgap_find_config(int type, int bus, int slot)
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400464{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900465 struct cnode *p, *prev, *prev2, *found;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400466
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900467 p = &dgap_head;
Mark Hounschell9b073ac2014-03-03 13:45:42 -0500468
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900469 while (p->next) {
470 prev = p;
471 p = p->next;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400472
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900473 if (p->type != BNODE)
474 continue;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400475
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900476 if (p->u.board.type != type)
477 continue;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400478
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900479 if (p->u.board.v_pcibus &&
480 p->u.board.pcibus != bus)
481 continue;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400482
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900483 if (p->u.board.v_pcislot &&
484 p->u.board.pcislot != slot)
485 continue;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400486
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900487 found = p;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400488 /*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900489 * Keep walking thru the list till we
490 * find the next board.
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400491 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900492 while (p->next) {
493 prev2 = p;
494 p = p->next;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400495
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900496 if (p->type != BNODE)
497 continue;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400498
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900499 /*
500 * Mark the end of our 1 board
501 * chain of configs.
502 */
503 prev2->next = NULL;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -0400504
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900505 /*
506 * Link the "next" board to the
507 * previous board, effectively
508 * "unlinking" our board from
509 * the main config.
510 */
511 prev->next = p;
Mark Hounschellc0c31b92014-03-12 12:50:56 -0400512
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900513 return found;
Mark Hounschellb28ec882014-02-20 08:48:48 -0500514 }
Mark Hounschell23aa2ad2014-04-23 10:33:45 -0400515 /*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900516 * It must be the last board in the list.
Mark Hounschell23aa2ad2014-04-23 10:33:45 -0400517 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900518 prev->next = NULL;
519 return found;
Mark Hounschellb28ec882014-02-20 08:48:48 -0500520 }
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900521 return NULL;
522}
523
524/*
525 * Given a board pointer, walks the config link, counting up
526 * all ports user specified should be on the board.
527 * (This does NOT mean they are all actually present right now tho)
528 */
529static uint dgap_config_get_num_prts(struct board_t *bd)
530{
531 int count = 0;
532 struct cnode *p;
533
534 if (!bd)
535 return 0;
536
537 for (p = bd->bd_config; p; p = p->next) {
538
539 switch (p->type) {
540 case BNODE:
541 /*
542 * check for pcxr types.
543 */
544 if (p->u.board.type > EPCFE)
545 count += p->u.board.nport;
546 break;
547 case CNODE:
548 count += p->u.conc.nport;
549 break;
550 case MNODE:
551 count += p->u.module.nport;
552 break;
553 }
554 }
555 return count;
556}
557
558static char *dgap_create_config_string(struct board_t *bd, char *string)
559{
560 char *ptr = string;
561 struct cnode *p;
562 struct cnode *q;
563 int speed;
564
565 if (!bd) {
566 *ptr = 0xff;
567 return string;
568 }
569
570 for (p = bd->bd_config; p; p = p->next) {
571
572 switch (p->type) {
573 case LNODE:
574 *ptr = '\0';
575 ptr++;
576 *ptr = p->u.line.speed;
577 ptr++;
578 break;
579 case CNODE:
580 /*
581 * Because the EPC/con concentrators can have EM modules
582 * hanging off of them, we have to walk ahead in the
583 * list and keep adding the number of ports on each EM
584 * to the config. UGH!
585 */
586 speed = p->u.conc.speed;
587 q = p->next;
588 if (q && (q->type == MNODE)) {
589 *ptr = (p->u.conc.nport + 0x80);
590 ptr++;
591 p = q;
592 while (q->next && (q->next->type) == MNODE) {
593 *ptr = (q->u.module.nport + 0x80);
594 ptr++;
595 p = q;
596 q = q->next;
597 }
598 *ptr = q->u.module.nport;
599 ptr++;
600 } else {
601 *ptr = p->u.conc.nport;
602 ptr++;
603 }
604
605 *ptr = speed;
606 ptr++;
607 break;
608 }
609 }
610
611 *ptr = 0xff;
612 return string;
613}
614
615/*
616 * Parse a configuration file read into memory as a string.
617 */
618static int dgap_parsefile(char **in)
619{
620 struct cnode *p, *brd, *line, *conc;
621 int rc;
622 char *s;
623 int linecnt = 0;
624
625 p = &dgap_head;
626 brd = line = conc = NULL;
627
628 /* perhaps we are adding to an existing list? */
629 while (p->next)
630 p = p->next;
631
632 /* file must start with a BEGIN */
633 while ((rc = dgap_gettok(in)) != BEGIN) {
634 if (rc == 0) {
635 pr_err("unexpected EOF");
636 return -1;
637 }
638 }
639
640 for (; ;) {
641 int board_type = 0;
642 int conc_type = 0;
643 int module_type = 0;
644
645 rc = dgap_gettok(in);
646 if (rc == 0) {
647 pr_err("unexpected EOF");
648 return -1;
649 }
650
651 switch (rc) {
652 case BEGIN: /* should only be 1 begin */
653 pr_err("unexpected config_begin\n");
654 return -1;
655
656 case END:
657 return 0;
658
659 case BOARD: /* board info */
660 if (dgap_checknode(p))
661 return -1;
662
663 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
664 if (!p->next)
665 return -1;
666
667 p = p->next;
668
669 p->type = BNODE;
670 p->u.board.status = kstrdup("No", GFP_KERNEL);
671 line = conc = NULL;
672 brd = p;
673 linecnt = -1;
674
675 board_type = dgap_gettok(in);
676 if (board_type == 0) {
677 pr_err("board !!type not specified");
678 return -1;
679 }
680
681 p->u.board.type = board_type;
682
683 break;
684
685 case IO: /* i/o port */
686 if (p->type != BNODE) {
687 pr_err("IO port only valid for boards");
688 return -1;
689 }
690 s = dgap_getword(in);
691 if (!s) {
692 pr_err("unexpected end of file");
693 return -1;
694 }
695 p->u.board.portstr = kstrdup(s, GFP_KERNEL);
696 if (kstrtol(s, 0, &p->u.board.port)) {
697 pr_err("bad number for IO port");
698 return -1;
699 }
700 p->u.board.v_port = 1;
701 break;
702
703 case MEM: /* memory address */
704 if (p->type != BNODE) {
705 pr_err("memory address only valid for boards");
706 return -1;
707 }
708 s = dgap_getword(in);
709 if (!s) {
710 pr_err("unexpected end of file");
711 return -1;
712 }
713 p->u.board.addrstr = kstrdup(s, GFP_KERNEL);
714 if (kstrtoul(s, 0, &p->u.board.addr)) {
715 pr_err("bad number for memory address");
716 return -1;
717 }
718 p->u.board.v_addr = 1;
719 break;
720
721 case PCIINFO: /* pci information */
722 if (p->type != BNODE) {
723 pr_err("memory address only valid for boards");
724 return -1;
725 }
726 s = dgap_getword(in);
727 if (!s) {
728 pr_err("unexpected end of file");
729 return -1;
730 }
731 p->u.board.pcibusstr = kstrdup(s, GFP_KERNEL);
732 if (kstrtoul(s, 0, &p->u.board.pcibus)) {
733 pr_err("bad number for pci bus");
734 return -1;
735 }
736 p->u.board.v_pcibus = 1;
737 s = dgap_getword(in);
738 if (!s) {
739 pr_err("unexpected end of file");
740 return -1;
741 }
742 p->u.board.pcislotstr = kstrdup(s, GFP_KERNEL);
743 if (kstrtoul(s, 0, &p->u.board.pcislot)) {
744 pr_err("bad number for pci slot");
745 return -1;
746 }
747 p->u.board.v_pcislot = 1;
748 break;
749
750 case METHOD:
751 if (p->type != BNODE) {
752 pr_err("install method only valid for boards");
753 return -1;
754 }
755 s = dgap_getword(in);
756 if (!s) {
757 pr_err("unexpected end of file");
758 return -1;
759 }
760 p->u.board.method = kstrdup(s, GFP_KERNEL);
761 p->u.board.v_method = 1;
762 break;
763
764 case STATUS:
765 if (p->type != BNODE) {
766 pr_err("config status only valid for boards");
767 return -1;
768 }
769 s = dgap_getword(in);
770 if (!s) {
771 pr_err("unexpected end of file");
772 return -1;
773 }
774 p->u.board.status = kstrdup(s, GFP_KERNEL);
775 break;
776
777 case NPORTS: /* number of ports */
778 if (p->type == BNODE) {
779 s = dgap_getword(in);
780 if (!s) {
781 pr_err("unexpected end of file");
782 return -1;
783 }
784 if (kstrtol(s, 0, &p->u.board.nport)) {
785 pr_err("bad number for number of ports");
786 return -1;
787 }
788 p->u.board.v_nport = 1;
789 } else if (p->type == CNODE) {
790 s = dgap_getword(in);
791 if (!s) {
792 pr_err("unexpected end of file");
793 return -1;
794 }
795 if (kstrtol(s, 0, &p->u.conc.nport)) {
796 pr_err("bad number for number of ports");
797 return -1;
798 }
799 p->u.conc.v_nport = 1;
800 } else if (p->type == MNODE) {
801 s = dgap_getword(in);
802 if (!s) {
803 pr_err("unexpected end of file");
804 return -1;
805 }
806 if (kstrtol(s, 0, &p->u.module.nport)) {
807 pr_err("bad number for number of ports");
808 return -1;
809 }
810 p->u.module.v_nport = 1;
811 } else {
812 pr_err("nports only valid for concentrators or modules");
813 return -1;
814 }
815 break;
816
817 case ID: /* letter ID used in tty name */
818 s = dgap_getword(in);
819 if (!s) {
820 pr_err("unexpected end of file");
821 return -1;
822 }
823
824 p->u.board.status = kstrdup(s, GFP_KERNEL);
825
826 if (p->type == CNODE) {
827 p->u.conc.id = kstrdup(s, GFP_KERNEL);
828 p->u.conc.v_id = 1;
829 } else if (p->type == MNODE) {
830 p->u.module.id = kstrdup(s, GFP_KERNEL);
831 p->u.module.v_id = 1;
832 } else {
833 pr_err("id only valid for concentrators or modules");
834 return -1;
835 }
836 break;
837
838 case STARTO: /* start offset of ID */
839 if (p->type == BNODE) {
840 s = dgap_getword(in);
841 if (!s) {
842 pr_err("unexpected end of file");
843 return -1;
844 }
845 if (kstrtol(s, 0, &p->u.board.start)) {
846 pr_err("bad number for start of tty count");
847 return -1;
848 }
849 p->u.board.v_start = 1;
850 } else if (p->type == CNODE) {
851 s = dgap_getword(in);
852 if (!s) {
853 pr_err("unexpected end of file");
854 return -1;
855 }
856 if (kstrtol(s, 0, &p->u.conc.start)) {
857 pr_err("bad number for start of tty count");
858 return -1;
859 }
860 p->u.conc.v_start = 1;
861 } else if (p->type == MNODE) {
862 s = dgap_getword(in);
863 if (!s) {
864 pr_err("unexpected end of file");
865 return -1;
866 }
867 if (kstrtol(s, 0, &p->u.module.start)) {
868 pr_err("bad number for start of tty count");
869 return -1;
870 }
871 p->u.module.v_start = 1;
872 } else {
873 pr_err("start only valid for concentrators or modules");
874 return -1;
875 }
876 break;
877
878 case TTYN: /* tty name prefix */
879 if (dgap_checknode(p))
880 return -1;
881
882 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
883 if (!p->next)
884 return -1;
885
886 p = p->next;
887 p->type = TNODE;
888
889 s = dgap_getword(in);
890 if (!s) {
891 pr_err("unexpeced end of file");
892 return -1;
893 }
894 p->u.ttyname = kstrdup(s, GFP_KERNEL);
895 if (!p->u.ttyname)
896 return -1;
897
898 break;
899
900 case CU: /* cu name prefix */
901 if (dgap_checknode(p))
902 return -1;
903
904 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
905 if (!p->next)
906 return -1;
907
908 p = p->next;
909 p->type = CUNODE;
910
911 s = dgap_getword(in);
912 if (!s) {
913 pr_err("unexpeced end of file");
914 return -1;
915 }
916 p->u.cuname = kstrdup(s, GFP_KERNEL);
917 if (!p->u.cuname)
918 return -1;
919
920 break;
921
922 case LINE: /* line information */
923 if (dgap_checknode(p))
924 return -1;
925 if (!brd) {
926 pr_err("must specify board before line info");
927 return -1;
928 }
929 switch (brd->u.board.type) {
930 case PPCM:
931 pr_err("line not valid for PC/em");
932 return -1;
933 }
934
935 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
936 if (!p->next)
937 return -1;
938
939 p = p->next;
940 p->type = LNODE;
941 conc = NULL;
942 line = p;
943 linecnt++;
944 break;
945
946 case CONC: /* concentrator information */
947 if (dgap_checknode(p))
948 return -1;
949 if (!line) {
950 pr_err("must specify line info before concentrator");
951 return -1;
952 }
953
954 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
955 if (!p->next)
956 return -1;
957
958 p = p->next;
959 p->type = CNODE;
960 conc = p;
961
962 if (linecnt)
963 brd->u.board.conc2++;
964 else
965 brd->u.board.conc1++;
966
967 conc_type = dgap_gettok(in);
Daeseok Younce5b6152015-01-23 20:44:28 +0900968 if (conc_type == 0 || (conc_type != CX &&
969 conc_type != EPC)) {
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +0900970 pr_err("failed to set a type of concentratros");
971 return -1;
972 }
973
974 p->u.conc.type = conc_type;
975
976 break;
977
978 case MOD: /* EBI module */
979 if (dgap_checknode(p))
980 return -1;
981 if (!brd) {
982 pr_err("must specify board info before EBI modules");
983 return -1;
984 }
985 switch (brd->u.board.type) {
986 case PPCM:
987 linecnt = 0;
988 break;
989 default:
990 if (!conc) {
991 pr_err("must specify concentrator info before EBI module");
992 return -1;
993 }
994 }
995
996 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
997 if (!p->next)
998 return -1;
999
1000 p = p->next;
1001 p->type = MNODE;
1002
1003 if (linecnt)
1004 brd->u.board.module2++;
1005 else
1006 brd->u.board.module1++;
1007
1008 module_type = dgap_gettok(in);
Daeseok Younce5b6152015-01-23 20:44:28 +09001009 if (module_type == 0 || (module_type != PORTS &&
1010 module_type != MODEM)) {
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001011 pr_err("failed to set a type of module");
1012 return -1;
1013 }
1014
1015 p->u.module.type = module_type;
1016
1017 break;
1018
1019 case CABLE:
1020 if (p->type == LNODE) {
1021 s = dgap_getword(in);
1022 if (!s) {
1023 pr_err("unexpected end of file");
1024 return -1;
1025 }
1026 p->u.line.cable = kstrdup(s, GFP_KERNEL);
1027 p->u.line.v_cable = 1;
1028 }
1029 break;
1030
1031 case SPEED: /* sync line speed indication */
1032 if (p->type == LNODE) {
1033 s = dgap_getword(in);
1034 if (!s) {
1035 pr_err("unexpected end of file");
1036 return -1;
1037 }
1038 if (kstrtol(s, 0, &p->u.line.speed)) {
1039 pr_err("bad number for line speed");
1040 return -1;
1041 }
1042 p->u.line.v_speed = 1;
1043 } else if (p->type == CNODE) {
1044 s = dgap_getword(in);
1045 if (!s) {
1046 pr_err("unexpected end of file");
1047 return -1;
1048 }
1049 if (kstrtol(s, 0, &p->u.conc.speed)) {
1050 pr_err("bad number for line speed");
1051 return -1;
1052 }
1053 p->u.conc.v_speed = 1;
1054 } else {
1055 pr_err("speed valid only for lines or concentrators.");
1056 return -1;
1057 }
1058 break;
1059
1060 case CONNECT:
1061 if (p->type == CNODE) {
1062 s = dgap_getword(in);
1063 if (!s) {
1064 pr_err("unexpected end of file");
1065 return -1;
1066 }
1067 p->u.conc.connect = kstrdup(s, GFP_KERNEL);
1068 p->u.conc.v_connect = 1;
1069 }
1070 break;
1071 case PRINT: /* transparent print name prefix */
1072 if (dgap_checknode(p))
1073 return -1;
1074
1075 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1076 if (!p->next)
1077 return -1;
1078
1079 p = p->next;
1080 p->type = PNODE;
1081
1082 s = dgap_getword(in);
1083 if (!s) {
1084 pr_err("unexpeced end of file");
1085 return -1;
1086 }
1087 p->u.printname = kstrdup(s, GFP_KERNEL);
1088 if (!p->u.printname)
1089 return -1;
1090
1091 break;
1092
1093 case CMAJOR: /* major number */
1094 if (dgap_checknode(p))
1095 return -1;
1096
1097 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1098 if (!p->next)
1099 return -1;
1100
1101 p = p->next;
1102 p->type = JNODE;
1103
1104 s = dgap_getword(in);
1105 if (!s) {
1106 pr_err("unexpected end of file");
1107 return -1;
1108 }
1109 if (kstrtol(s, 0, &p->u.majornumber)) {
1110 pr_err("bad number for major number");
1111 return -1;
1112 }
1113 break;
1114
1115 case ALTPIN: /* altpin setting */
1116 if (dgap_checknode(p))
1117 return -1;
1118
1119 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1120 if (!p->next)
1121 return -1;
1122
1123 p = p->next;
1124 p->type = ANODE;
1125
1126 s = dgap_getword(in);
1127 if (!s) {
1128 pr_err("unexpected end of file");
1129 return -1;
1130 }
1131 if (kstrtol(s, 0, &p->u.altpin)) {
1132 pr_err("bad number for altpin");
1133 return -1;
1134 }
1135 break;
1136
1137 case USEINTR: /* enable interrupt setting */
1138 if (dgap_checknode(p))
1139 return -1;
1140
1141 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1142 if (!p->next)
1143 return -1;
1144
1145 p = p->next;
1146 p->type = INTRNODE;
1147 s = dgap_getword(in);
1148 if (!s) {
1149 pr_err("unexpected end of file");
1150 return -1;
1151 }
1152 if (kstrtol(s, 0, &p->u.useintr)) {
1153 pr_err("bad number for useintr");
1154 return -1;
1155 }
1156 break;
1157
1158 case TTSIZ: /* size of tty structure */
1159 if (dgap_checknode(p))
1160 return -1;
1161
1162 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1163 if (!p->next)
1164 return -1;
1165
1166 p = p->next;
1167 p->type = TSNODE;
1168
1169 s = dgap_getword(in);
1170 if (!s) {
1171 pr_err("unexpected end of file");
1172 return -1;
1173 }
1174 if (kstrtol(s, 0, &p->u.ttysize)) {
1175 pr_err("bad number for ttysize");
1176 return -1;
1177 }
1178 break;
1179
1180 case CHSIZ: /* channel structure size */
1181 if (dgap_checknode(p))
1182 return -1;
1183
1184 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1185 if (!p->next)
1186 return -1;
1187
1188 p = p->next;
1189 p->type = CSNODE;
1190
1191 s = dgap_getword(in);
1192 if (!s) {
1193 pr_err("unexpected end of file");
1194 return -1;
1195 }
1196 if (kstrtol(s, 0, &p->u.chsize)) {
1197 pr_err("bad number for chsize");
1198 return -1;
1199 }
1200 break;
1201
1202 case BSSIZ: /* board structure size */
1203 if (dgap_checknode(p))
1204 return -1;
1205
1206 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1207 if (!p->next)
1208 return -1;
1209
1210 p = p->next;
1211 p->type = BSNODE;
1212
1213 s = dgap_getword(in);
1214 if (!s) {
1215 pr_err("unexpected end of file");
1216 return -1;
1217 }
1218 if (kstrtol(s, 0, &p->u.bssize)) {
1219 pr_err("bad number for bssize");
1220 return -1;
1221 }
1222 break;
1223
1224 case UNTSIZ: /* sched structure size */
1225 if (dgap_checknode(p))
1226 return -1;
1227
1228 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1229 if (!p->next)
1230 return -1;
1231
1232 p = p->next;
1233 p->type = USNODE;
1234
1235 s = dgap_getword(in);
1236 if (!s) {
1237 pr_err("unexpected end of file");
1238 return -1;
1239 }
1240 if (kstrtol(s, 0, &p->u.unsize)) {
1241 pr_err("bad number for schedsize");
1242 return -1;
1243 }
1244 break;
1245
1246 case F2SIZ: /* f2200 structure size */
1247 if (dgap_checknode(p))
1248 return -1;
1249
1250 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1251 if (!p->next)
1252 return -1;
1253
1254 p = p->next;
1255 p->type = FSNODE;
1256
1257 s = dgap_getword(in);
1258 if (!s) {
1259 pr_err("unexpected end of file");
1260 return -1;
1261 }
1262 if (kstrtol(s, 0, &p->u.f2size)) {
1263 pr_err("bad number for f2200size");
1264 return -1;
1265 }
1266 break;
1267
1268 case VPSIZ: /* vpix structure size */
1269 if (dgap_checknode(p))
1270 return -1;
1271
1272 p->next = kzalloc(sizeof(struct cnode), GFP_KERNEL);
1273 if (!p->next)
1274 return -1;
1275
1276 p = p->next;
1277 p->type = VSNODE;
1278
1279 s = dgap_getword(in);
1280 if (!s) {
1281 pr_err("unexpected end of file");
1282 return -1;
1283 }
1284 if (kstrtol(s, 0, &p->u.vpixsize)) {
1285 pr_err("bad number for vpixsize");
1286 return -1;
1287 }
1288 break;
1289 }
1290 }
1291}
1292
1293static void dgap_cleanup_nodes(void)
1294{
1295 struct cnode *p;
1296
1297 p = &dgap_head;
1298
1299 while (p) {
1300 struct cnode *tmp = p->next;
1301
1302 if (p->type == NULLNODE) {
1303 p = tmp;
1304 continue;
1305 }
1306
1307 switch (p->type) {
1308 case BNODE:
1309 kfree(p->u.board.portstr);
1310 kfree(p->u.board.addrstr);
1311 kfree(p->u.board.pcibusstr);
1312 kfree(p->u.board.pcislotstr);
1313 kfree(p->u.board.method);
1314 break;
1315 case CNODE:
1316 kfree(p->u.conc.id);
1317 kfree(p->u.conc.connect);
1318 break;
1319 case MNODE:
1320 kfree(p->u.module.id);
1321 break;
1322 case TNODE:
1323 kfree(p->u.ttyname);
1324 break;
1325 case CUNODE:
1326 kfree(p->u.cuname);
1327 break;
1328 case LNODE:
1329 kfree(p->u.line.cable);
1330 break;
1331 case PNODE:
1332 kfree(p->u.printname);
1333 break;
1334 }
1335
1336 kfree(p->u.board.status);
1337 kfree(p);
1338 p = tmp;
1339 }
1340}
1341
1342/*
1343 * Retrives the current custom baud rate from FEP memory,
1344 * and returns it back to the user.
1345 * Returns 0 on error.
1346 */
1347static uint dgap_get_custom_baud(struct channel_t *ch)
1348{
1349 u8 __iomem *vaddr;
1350 ulong offset;
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001351
1352 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
1353 return 0;
1354
1355 if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC)
1356 return 0;
1357
1358 if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS))
1359 return 0;
1360
1361 vaddr = ch->ch_bd->re_map_membase;
1362
1363 if (!vaddr)
1364 return 0;
Mark Hounschellb28ec882014-02-20 08:48:48 -05001365
Mark Hounschellb28ec882014-02-20 08:48:48 -05001366 /*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001367 * Go get from fep mem, what the fep
1368 * believes the custom baud rate is.
Mark Hounschellb28ec882014-02-20 08:48:48 -05001369 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001370 offset = (ioread16(vaddr + ECS_SEG) << 4) + (ch->ch_portnum * 0x28)
1371 + LINE_SPEED;
Mark Hounschellb28ec882014-02-20 08:48:48 -05001372
Haneen Mohammed6019ee42015-03-08 00:02:34 +03001373 return readw(vaddr + offset);
Mark Hounschellb28ec882014-02-20 08:48:48 -05001374}
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001375
1376/*
1377 * Remap PCI memory.
1378 */
Daeseok Youn263bd1c2014-10-08 20:13:21 +09001379static int dgap_remap(struct board_t *brd)
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001380{
1381 if (!brd || brd->magic != DGAP_BOARD_MAGIC)
Mark Hounschell6d488a02014-05-28 16:18:03 -04001382 return -EIO;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001383
Mark Hounschell31960c12014-02-28 12:42:08 -05001384 if (!request_mem_region(brd->membase, 0x200000, "dgap"))
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001385 return -ENOMEM;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001386
Mark Hounschell2f60b332014-03-04 16:03:12 -05001387 if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000,
Daeseok Younaa9895d2014-12-26 10:34:32 +09001388 "dgap"))
1389 goto err_req_mem;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001390
1391 brd->re_map_membase = ioremap(brd->membase, 0x200000);
Daeseok Younaa9895d2014-12-26 10:34:32 +09001392 if (!brd->re_map_membase)
1393 goto err_remap_mem;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001394
1395 brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000);
Daeseok Younaa9895d2014-12-26 10:34:32 +09001396 if (!brd->re_map_port)
1397 goto err_remap_port;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001398
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001399 return 0;
Daeseok Younaa9895d2014-12-26 10:34:32 +09001400
1401err_remap_port:
1402 iounmap(brd->re_map_membase);
1403err_remap_mem:
1404 release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
1405err_req_mem:
1406 release_mem_region(brd->membase, 0x200000);
1407
1408 return -ENOMEM;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001409}
1410
Daeseok Youn263bd1c2014-10-08 20:13:21 +09001411static void dgap_unmap(struct board_t *brd)
Daeseok Youn91177d52014-06-13 18:23:15 +09001412{
Daeseok Youn9f2b7442014-10-08 20:12:48 +09001413 iounmap(brd->re_map_port);
1414 iounmap(brd->re_map_membase);
1415 release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
1416 release_mem_region(brd->membase, 0x200000);
Daeseok Youn91177d52014-06-13 18:23:15 +09001417}
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001418
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001419/*
1420 * dgap_parity_scan()
1421 *
1422 * Convert the FEP5 way of reporting parity errors and breaks into
1423 * the Linux line discipline way.
1424 */
1425static void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf,
1426 unsigned char *fbuf, int *len)
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001427{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001428 int l = *len;
1429 int count = 0;
1430 unsigned char *in, *cout, *fout;
1431 unsigned char c;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001432
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001433 in = cbuf;
1434 cout = cbuf;
1435 fout = fbuf;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001436
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001437 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
1438 return;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001439
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001440 while (l--) {
1441 c = *in++;
1442 switch (ch->pscan_state) {
1443 default:
1444 /* reset to sanity and fall through */
1445 ch->pscan_state = 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001446
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001447 case 0:
1448 /* No FF seen yet */
1449 if (c == (unsigned char) '\377')
1450 /* delete this character from stream */
1451 ch->pscan_state = 1;
1452 else {
1453 *cout++ = c;
1454 *fout++ = TTY_NORMAL;
1455 count += 1;
1456 }
1457 break;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001458
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001459 case 1:
1460 /* first FF seen */
1461 if (c == (unsigned char) '\377') {
1462 /* doubled ff, transform to single ff */
1463 *cout++ = c;
1464 *fout++ = TTY_NORMAL;
1465 count += 1;
1466 ch->pscan_state = 0;
1467 } else {
1468 /* save value examination in next state */
1469 ch->pscan_savechar = c;
1470 ch->pscan_state = 2;
1471 }
1472 break;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001473
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001474 case 2:
1475 /* third character of ff sequence */
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001476
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001477 *cout++ = c;
1478
1479 if (ch->pscan_savechar == 0x0) {
1480
1481 if (c == 0x0) {
1482 ch->ch_err_break++;
1483 *fout++ = TTY_BREAK;
1484 } else {
1485 ch->ch_err_parity++;
1486 *fout++ = TTY_PARITY;
1487 }
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001488 }
1489
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001490 count += 1;
1491 ch->pscan_state = 0;
Scott_Kilau@digi.comc84b8b52013-08-21 21:48:31 -04001492 }
1493 }
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001494 *len = count;
Mark Hounschella6792a32014-02-19 13:11:59 -05001495}
1496
Mark Hounschella6792a32014-02-19 13:11:59 -05001497/*=======================================================================
1498 *
1499 * dgap_input - Process received data.
1500 *
1501 * ch - Pointer to channel structure.
1502 *
1503 *=======================================================================*/
1504
Mark Hounschellfe0ef8e2014-02-19 13:12:13 -05001505static void dgap_input(struct channel_t *ch)
Mark Hounschella6792a32014-02-19 13:11:59 -05001506{
1507 struct board_t *bd;
Mark Hounschell405b26d2014-04-23 16:25:27 -04001508 struct bs_t __iomem *bs;
Mark Hounschella6792a32014-02-19 13:11:59 -05001509 struct tty_struct *tp;
1510 struct tty_ldisc *ld;
Mark Hounschell174efc12014-05-23 12:54:04 -04001511 uint rmask;
1512 uint head;
1513 uint tail;
1514 int data_len;
1515 ulong lock_flags;
1516 ulong lock_flags2;
Mark Hounschella6792a32014-02-19 13:11:59 -05001517 int flip_len;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04001518 int len;
1519 int n;
Mark Hounschell2023d182014-04-14 16:42:43 -04001520 u8 *buf;
1521 u8 tmpchar;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04001522 int s;
Mark Hounschella6792a32014-02-19 13:11:59 -05001523
1524 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
1525 return;
1526
1527 tp = ch->ch_tun.un_tty;
1528
1529 bs = ch->ch_bs;
Mark Hounschell305ec872014-02-28 12:42:13 -05001530 if (!bs)
Mark Hounschella6792a32014-02-19 13:11:59 -05001531 return;
Mark Hounschella6792a32014-02-19 13:11:59 -05001532
1533 bd = ch->ch_bd;
Mark Hounschellb115b022014-02-28 12:42:15 -05001534 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschella6792a32014-02-19 13:11:59 -05001535 return;
1536
Mark Hounschellc43846a2014-03-19 11:10:51 -04001537 spin_lock_irqsave(&bd->bd_lock, lock_flags);
1538 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05001539
1540 /*
1541 * Figure the number of characters in the buffer.
1542 * Exit immediately if none.
1543 */
1544
1545 rmask = ch->ch_rsize - 1;
1546
1547 head = readw(&(bs->rx_head));
1548 head &= rmask;
1549 tail = readw(&(bs->rx_tail));
1550 tail &= rmask;
1551
1552 data_len = (head - tail) & rmask;
1553
1554 if (data_len == 0) {
1555 writeb(1, &(bs->idata));
Mark Hounschellc43846a2014-03-19 11:10:51 -04001556 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
1557 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05001558 return;
1559 }
1560
1561 /*
1562 * If the device is not open, or CREAD is off, flush
1563 * input data and return immediately.
1564 */
Mark Hounschell7d6069d72014-02-28 12:42:10 -05001565 if ((bd->state != BOARD_READY) || !tp ||
1566 (tp->magic != TTY_MAGIC) ||
1567 !(ch->ch_tun.un_flags & UN_ISOPEN) ||
1568 !(tp->termios.c_cflag & CREAD) ||
Mark Hounschella6792a32014-02-19 13:11:59 -05001569 (ch->ch_tun.un_flags & UN_CLOSING)) {
1570
Mark Hounschella6792a32014-02-19 13:11:59 -05001571 writew(head, &(bs->rx_tail));
1572 writeb(1, &(bs->idata));
Mark Hounschellc43846a2014-03-19 11:10:51 -04001573 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
1574 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05001575 return;
1576 }
1577
1578 /*
1579 * If we are throttled, simply don't read any data.
1580 */
1581 if (ch->ch_flags & CH_RXBLOCK) {
1582 writeb(1, &(bs->idata));
Mark Hounschellc43846a2014-03-19 11:10:51 -04001583 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
1584 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05001585 return;
1586 }
1587
1588 /*
1589 * Ignore oruns.
1590 */
1591 tmpchar = readb(&(bs->orun));
1592 if (tmpchar) {
1593 ch->ch_err_overrun++;
1594 writeb(0, &(bs->orun));
1595 }
1596
Mark Hounschella6792a32014-02-19 13:11:59 -05001597 /* Decide how much data we can send into the tty layer */
1598 flip_len = TTY_FLIPBUF_SIZE;
1599
1600 /* Chop down the length, if needed */
1601 len = min(data_len, flip_len);
1602 len = min(len, (N_TTY_BUF_SIZE - 1));
1603
1604 ld = tty_ldisc_ref(tp);
1605
1606#ifdef TTY_DONT_FLIP
1607 /*
1608 * If the DONT_FLIP flag is on, don't flush our buffer, and act
1609 * like the ld doesn't have any space to put the data right now.
1610 */
1611 if (test_bit(TTY_DONT_FLIP, &tp->flags))
1612 len = 0;
1613#endif
1614
1615 /*
1616 * If we were unable to get a reference to the ld,
1617 * don't flush our buffer, and act like the ld doesn't
1618 * have any space to put the data right now.
1619 */
1620 if (!ld) {
1621 len = 0;
1622 } else {
1623 /*
1624 * If ld doesn't have a pointer to a receive_buf function,
1625 * flush the data, then act like the ld doesn't have any
1626 * space to put the data right now.
1627 */
1628 if (!ld->ops->receive_buf) {
1629 writew(head, &(bs->rx_tail));
1630 len = 0;
1631 }
1632 }
1633
1634 if (len <= 0) {
1635 writeb(1, &(bs->idata));
Mark Hounschellc43846a2014-03-19 11:10:51 -04001636 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
1637 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05001638 if (ld)
1639 tty_ldisc_deref(ld);
1640 return;
1641 }
1642
1643 buf = ch->ch_bd->flipbuf;
1644 n = len;
1645
1646 /*
1647 * n now contains the most amount of data we can copy,
1648 * bounded either by our buffer size or the amount
1649 * of data the card actually has pending...
1650 */
1651 while (n) {
1652
1653 s = ((head >= tail) ? head : ch->ch_rsize) - tail;
1654 s = min(s, n);
1655
1656 if (s <= 0)
1657 break;
1658
Mark Hounschell630b2ab2014-04-24 09:22:12 -04001659 memcpy_fromio(buf, ch->ch_raddr + tail, s);
Mark Hounschella6792a32014-02-19 13:11:59 -05001660
1661 tail += s;
1662 buf += s;
1663
1664 n -= s;
1665 /* Flip queue if needed */
1666 tail &= rmask;
1667 }
1668
1669 writew(tail, &(bs->rx_tail));
1670 writeb(1, &(bs->idata));
1671 ch->ch_rxcount += len;
1672
1673 /*
1674 * If we are completely raw, we don't need to go through a lot
1675 * of the tty layers that exist.
1676 * In this case, we take the shortest and fastest route we
1677 * can to relay the data to the user.
1678 *
1679 * On the other hand, if we are not raw, we need to go through
1680 * the tty layer, which has its API more well defined.
1681 */
1682 if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
Mark Hounschell6045b6a2014-03-06 13:02:45 -05001683 dgap_parity_scan(ch, ch->ch_bd->flipbuf,
1684 ch->ch_bd->flipflagbuf, &len);
Mark Hounschella6792a32014-02-19 13:11:59 -05001685
1686 len = tty_buffer_request_room(tp->port, len);
1687 tty_insert_flip_string_flags(tp->port, ch->ch_bd->flipbuf,
1688 ch->ch_bd->flipflagbuf, len);
Mark Hounschell305ec872014-02-28 12:42:13 -05001689 } else {
Mark Hounschella6792a32014-02-19 13:11:59 -05001690 len = tty_buffer_request_room(tp->port, len);
1691 tty_insert_flip_string(tp->port, ch->ch_bd->flipbuf, len);
1692 }
1693
Mark Hounschellc43846a2014-03-19 11:10:51 -04001694 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
1695 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05001696
1697 /* Tell the tty layer its okay to "eat" the data now */
1698 tty_flip_buffer_push(tp->port);
1699
1700 if (ld)
1701 tty_ldisc_deref(ld);
1702
Mark Hounschella6792a32014-02-19 13:11:59 -05001703}
1704
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001705static void dgap_write_wakeup(struct board_t *bd, struct channel_t *ch,
1706 struct un_t *un, u32 mask,
1707 unsigned long *irq_flags1,
1708 unsigned long *irq_flags2)
1709{
1710 if (!(un->un_flags & mask))
1711 return;
1712
1713 un->un_flags &= ~mask;
1714
1715 if (!(un->un_flags & UN_ISOPEN))
1716 return;
1717
1718 if ((un->un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1719 un->un_tty->ldisc->ops->write_wakeup) {
1720 spin_unlock_irqrestore(&ch->ch_lock, *irq_flags2);
1721 spin_unlock_irqrestore(&bd->bd_lock, *irq_flags1);
1722
1723 (un->un_tty->ldisc->ops->write_wakeup)(un->un_tty);
1724
1725 spin_lock_irqsave(&bd->bd_lock, *irq_flags1);
1726 spin_lock_irqsave(&ch->ch_lock, *irq_flags2);
1727 }
1728 wake_up_interruptible(&un->un_tty->write_wait);
1729 wake_up_interruptible(&un->un_flags_wait);
1730}
1731
Mark Hounschella6792a32014-02-19 13:11:59 -05001732/************************************************************************
1733 * Determines when CARRIER changes state and takes appropriate
1734 * action.
1735 ************************************************************************/
Mark Hounschellfe0ef8e2014-02-19 13:12:13 -05001736static void dgap_carrier(struct channel_t *ch)
Mark Hounschella6792a32014-02-19 13:11:59 -05001737{
1738 struct board_t *bd;
1739
Mark Hounschell7d6069d72014-02-28 12:42:10 -05001740 int virt_carrier = 0;
1741 int phys_carrier = 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05001742
Mark Hounschella6792a32014-02-19 13:11:59 -05001743 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
1744 return;
1745
1746 bd = ch->ch_bd;
1747
1748 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
1749 return;
1750
1751 /* Make sure altpin is always set correctly */
1752 if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
1753 ch->ch_dsr = DM_CD;
1754 ch->ch_cd = DM_DSR;
Mark Hounschell305ec872014-02-28 12:42:13 -05001755 } else {
Mark Hounschella6792a32014-02-19 13:11:59 -05001756 ch->ch_dsr = DM_DSR;
1757 ch->ch_cd = DM_CD;
1758 }
1759
Mark Hounschell31960c12014-02-28 12:42:08 -05001760 if (ch->ch_mistat & D_CD(ch))
Mark Hounschella6792a32014-02-19 13:11:59 -05001761 phys_carrier = 1;
Mark Hounschella6792a32014-02-19 13:11:59 -05001762
Mark Hounschell305ec872014-02-28 12:42:13 -05001763 if (ch->ch_digi.digi_flags & DIGI_FORCEDCD)
Mark Hounschella6792a32014-02-19 13:11:59 -05001764 virt_carrier = 1;
Mark Hounschella6792a32014-02-19 13:11:59 -05001765
Mark Hounschell305ec872014-02-28 12:42:13 -05001766 if (ch->ch_c_cflag & CLOCAL)
Mark Hounschella6792a32014-02-19 13:11:59 -05001767 virt_carrier = 1;
Mark Hounschella6792a32014-02-19 13:11:59 -05001768
Mark Hounschella6792a32014-02-19 13:11:59 -05001769 /*
1770 * Test for a VIRTUAL carrier transition to HIGH.
1771 */
1772 if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
1773
1774 /*
1775 * When carrier rises, wake any threads waiting
1776 * for carrier in the open routine.
1777 */
1778
Mark Hounschella6792a32014-02-19 13:11:59 -05001779 if (waitqueue_active(&(ch->ch_flags_wait)))
1780 wake_up_interruptible(&ch->ch_flags_wait);
1781 }
1782
1783 /*
1784 * Test for a PHYSICAL carrier transition to HIGH.
1785 */
1786 if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
1787
1788 /*
1789 * When carrier rises, wake any threads waiting
1790 * for carrier in the open routine.
1791 */
1792
Mark Hounschella6792a32014-02-19 13:11:59 -05001793 if (waitqueue_active(&(ch->ch_flags_wait)))
1794 wake_up_interruptible(&ch->ch_flags_wait);
1795 }
1796
1797 /*
1798 * Test for a PHYSICAL transition to low, so long as we aren't
1799 * currently ignoring physical transitions (which is what "virtual
1800 * carrier" indicates).
1801 *
1802 * The transition of the virtual carrier to low really doesn't
1803 * matter... it really only means "ignore carrier state", not
1804 * "make pretend that carrier is there".
1805 */
Mark Hounschell305ec872014-02-28 12:42:13 -05001806 if ((virt_carrier == 0) &&
1807 ((ch->ch_flags & CH_CD) != 0) &&
1808 (phys_carrier == 0)) {
Mark Hounschella6792a32014-02-19 13:11:59 -05001809
1810 /*
1811 * When carrier drops:
1812 *
1813 * Drop carrier on all open units.
1814 *
1815 * Flush queues, waking up any task waiting in the
1816 * line discipline.
1817 *
1818 * Send a hangup to the control terminal.
1819 *
1820 * Enable all select calls.
1821 */
1822 if (waitqueue_active(&(ch->ch_flags_wait)))
1823 wake_up_interruptible(&ch->ch_flags_wait);
1824
Mark Hounschell31960c12014-02-28 12:42:08 -05001825 if (ch->ch_tun.un_open_count > 0)
Mark Hounschella6792a32014-02-19 13:11:59 -05001826 tty_hangup(ch->ch_tun.un_tty);
Mark Hounschella6792a32014-02-19 13:11:59 -05001827
Mark Hounschell31960c12014-02-28 12:42:08 -05001828 if (ch->ch_pun.un_open_count > 0)
Mark Hounschella6792a32014-02-19 13:11:59 -05001829 tty_hangup(ch->ch_pun.un_tty);
Mark Hounschella6792a32014-02-19 13:11:59 -05001830 }
1831
1832 /*
1833 * Make sure that our cached values reflect the current reality.
1834 */
1835 if (virt_carrier == 1)
1836 ch->ch_flags |= CH_FCAR;
1837 else
1838 ch->ch_flags &= ~CH_FCAR;
1839
1840 if (phys_carrier == 1)
1841 ch->ch_flags |= CH_CD;
1842 else
1843 ch->ch_flags &= ~CH_CD;
1844}
1845
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001846/*=======================================================================
Mark Hounschella6792a32014-02-19 13:11:59 -05001847 *
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001848 * dgap_event - FEP to host event processing routine.
Mark Hounschella6792a32014-02-19 13:11:59 -05001849 *
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001850 * bd - Board of current event.
Mark Hounschella6792a32014-02-19 13:11:59 -05001851 *
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001852 *=======================================================================*/
1853static int dgap_event(struct board_t *bd)
Mark Hounschella6792a32014-02-19 13:11:59 -05001854{
Mark Hounschella6792a32014-02-19 13:11:59 -05001855 struct channel_t *ch;
Mark Hounschell174efc12014-05-23 12:54:04 -04001856 ulong lock_flags;
1857 ulong lock_flags2;
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001858 struct bs_t __iomem *bs;
1859 u8 __iomem *event;
1860 u8 __iomem *vaddr;
1861 struct ev_t __iomem *eaddr;
1862 uint head;
1863 uint tail;
1864 int port;
1865 int reason;
1866 int modem;
1867 int b1;
Mark Hounschella6792a32014-02-19 13:11:59 -05001868
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001869 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschell6d488a02014-05-28 16:18:03 -04001870 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05001871
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001872 spin_lock_irqsave(&bd->bd_lock, lock_flags);
1873
1874 vaddr = bd->re_map_membase;
1875
1876 if (!vaddr) {
1877 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschell6d488a02014-05-28 16:18:03 -04001878 return -EIO;
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001879 }
1880
1881 eaddr = (struct ev_t __iomem *) (vaddr + EVBUF);
1882
1883 /* Get our head and tail */
1884 head = readw(&(eaddr->ev_head));
1885 tail = readw(&(eaddr->ev_tail));
Mark Hounschella6792a32014-02-19 13:11:59 -05001886
1887 /*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001888 * Forget it if pointers out of range.
Mark Hounschella6792a32014-02-19 13:11:59 -05001889 */
Mark Hounschella6792a32014-02-19 13:11:59 -05001890
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001891 if (head >= EVMAX - EVSTART || tail >= EVMAX - EVSTART ||
1892 (head | tail) & 03) {
1893 /* Let go of board lock */
1894 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschell6d488a02014-05-28 16:18:03 -04001895 return -EIO;
Mark Hounschell7d6069d72014-02-28 12:42:10 -05001896 }
Mark Hounschella6792a32014-02-19 13:11:59 -05001897
Mark Hounschella6792a32014-02-19 13:11:59 -05001898 /*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001899 * Loop to process all the events in the buffer.
Mark Hounschella6792a32014-02-19 13:11:59 -05001900 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001901 while (tail != head) {
Mark Hounschella6792a32014-02-19 13:11:59 -05001902
1903 /*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001904 * Get interrupt information.
Mark Hounschella6792a32014-02-19 13:11:59 -05001905 */
Mark Hounschella6792a32014-02-19 13:11:59 -05001906
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001907 event = bd->re_map_membase + tail + EVSTART;
Mark Hounschella6792a32014-02-19 13:11:59 -05001908
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001909 port = ioread8(event);
1910 reason = ioread8(event + 1);
1911 modem = ioread8(event + 2);
1912 b1 = ioread8(event + 3);
Mark Hounschella6792a32014-02-19 13:11:59 -05001913
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09001914 /*
1915 * Make sure the interrupt is valid.
1916 */
1917 if (port >= bd->nasync)
1918 goto next;
1919
1920 if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA)))
1921 goto next;
1922
1923 ch = bd->channels[port];
1924
1925 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
1926 goto next;
1927
1928 /*
1929 * If we have made it here, the event was valid.
1930 * Lock down the channel.
1931 */
1932 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
1933
1934 bs = ch->ch_bs;
1935
1936 if (!bs) {
1937 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
1938 goto next;
1939 }
1940
1941 /*
1942 * Process received data.
1943 */
1944 if (reason & IFDATA) {
1945
1946 /*
1947 * ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT!
1948 * input could send some data to ld, which in turn
1949 * could do a callback to one of our other functions.
1950 */
1951 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
1952 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
1953
1954 dgap_input(ch);
1955
1956 spin_lock_irqsave(&bd->bd_lock, lock_flags);
1957 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
1958
1959 if (ch->ch_flags & CH_RACTIVE)
1960 ch->ch_flags |= CH_RENABLE;
1961 else
1962 writeb(1, &(bs->idata));
1963
1964 if (ch->ch_flags & CH_RWAIT) {
1965 ch->ch_flags &= ~CH_RWAIT;
1966
1967 wake_up_interruptible
1968 (&ch->ch_tun.un_flags_wait);
1969 }
1970 }
1971
1972 /*
1973 * Process Modem change signals.
1974 */
1975 if (reason & IFMODEM) {
1976 ch->ch_mistat = modem;
1977 dgap_carrier(ch);
1978 }
1979
1980 /*
1981 * Process break.
1982 */
1983 if (reason & IFBREAK) {
1984
1985 if (ch->ch_tun.un_tty) {
1986 /* A break has been indicated */
1987 ch->ch_err_break++;
1988 tty_buffer_request_room
1989 (ch->ch_tun.un_tty->port, 1);
1990 tty_insert_flip_char(ch->ch_tun.un_tty->port,
1991 0, TTY_BREAK);
1992 tty_flip_buffer_push(ch->ch_tun.un_tty->port);
1993 }
1994 }
1995
1996 /*
1997 * Process Transmit low.
1998 */
1999 if (reason & IFTLW) {
2000 dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_LOW,
2001 &lock_flags, &lock_flags2);
2002 dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_LOW,
2003 &lock_flags, &lock_flags2);
2004 if (ch->ch_flags & CH_WLOW) {
2005 ch->ch_flags &= ~CH_WLOW;
2006 wake_up_interruptible(&ch->ch_flags_wait);
2007 }
2008 }
2009
2010 /*
2011 * Process Transmit empty.
2012 */
2013 if (reason & IFTEM) {
2014 dgap_write_wakeup(bd, ch, &ch->ch_tun, UN_EMPTY,
2015 &lock_flags, &lock_flags2);
2016 dgap_write_wakeup(bd, ch, &ch->ch_pun, UN_EMPTY,
2017 &lock_flags, &lock_flags2);
2018 if (ch->ch_flags & CH_WEMPTY) {
2019 ch->ch_flags &= ~CH_WEMPTY;
2020 wake_up_interruptible(&ch->ch_flags_wait);
2021 }
2022 }
2023
2024 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
2025
2026next:
2027 tail = (tail + 4) & (EVMAX - EVSTART - 4);
Mark Hounschella6792a32014-02-19 13:11:59 -05002028 }
2029
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09002030 writew(tail, &(eaddr->ev_tail));
2031 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
2032
2033 return 0;
2034}
2035
2036/*
2037 * Our board poller function.
2038 */
2039static void dgap_poll_tasklet(unsigned long data)
2040{
2041 struct board_t *bd = (struct board_t *) data;
2042 ulong lock_flags;
2043 char __iomem *vaddr;
2044 u16 head, tail;
2045
2046 if (!bd || (bd->magic != DGAP_BOARD_MAGIC))
2047 return;
2048
2049 if (bd->inhibit_poller)
2050 return;
2051
2052 spin_lock_irqsave(&bd->bd_lock, lock_flags);
2053
2054 vaddr = bd->re_map_membase;
2055
2056 /*
2057 * If board is ready, parse deeper to see if there is anything to do.
2058 */
2059 if (bd->state == BOARD_READY) {
2060
2061 struct ev_t __iomem *eaddr;
2062
2063 if (!bd->re_map_membase) {
2064 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
2065 return;
2066 }
2067 if (!bd->re_map_port) {
2068 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
2069 return;
2070 }
2071
2072 if (!bd->nasync)
2073 goto out;
2074
2075 eaddr = (struct ev_t __iomem *) (vaddr + EVBUF);
2076
2077 /* Get our head and tail */
2078 head = readw(&(eaddr->ev_head));
2079 tail = readw(&(eaddr->ev_tail));
2080
2081 /*
2082 * If there is an event pending. Go service it.
2083 */
2084 if (head != tail) {
2085 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
2086 dgap_event(bd);
2087 spin_lock_irqsave(&bd->bd_lock, lock_flags);
2088 }
2089
2090out:
2091 /*
2092 * If board is doing interrupts, ACK the interrupt.
2093 */
2094 if (bd && bd->intr_running)
2095 readb(bd->re_map_port + 2);
2096
2097 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
2098 return;
2099 }
2100
2101 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
2102}
2103
2104/*
2105 * dgap_found_board()
2106 *
2107 * A board has been found, init it.
2108 */
2109static struct board_t *dgap_found_board(struct pci_dev *pdev, int id,
2110 int boardnum)
2111{
2112 struct board_t *brd;
2113 unsigned int pci_irq;
2114 int i;
2115 int ret;
2116
2117 /* get the board structure and prep it */
2118 brd = kzalloc(sizeof(struct board_t), GFP_KERNEL);
2119 if (!brd)
2120 return ERR_PTR(-ENOMEM);
2121
2122 /* store the info for the board we've found */
2123 brd->magic = DGAP_BOARD_MAGIC;
2124 brd->boardnum = boardnum;
2125 brd->vendor = dgap_pci_tbl[id].vendor;
2126 brd->device = dgap_pci_tbl[id].device;
2127 brd->pdev = pdev;
2128 brd->pci_bus = pdev->bus->number;
2129 brd->pci_slot = PCI_SLOT(pdev->devfn);
2130 brd->name = dgap_ids[id].name;
2131 brd->maxports = dgap_ids[id].maxports;
2132 brd->type = dgap_ids[id].config_type;
2133 brd->dpatype = dgap_ids[id].dpatype;
2134 brd->dpastatus = BD_NOFEP;
2135 init_waitqueue_head(&brd->state_wait);
2136
2137 spin_lock_init(&brd->bd_lock);
2138
2139 brd->inhibit_poller = FALSE;
2140 brd->wait_for_bios = 0;
2141 brd->wait_for_fep = 0;
2142
2143 for (i = 0; i < MAXPORTS; i++)
2144 brd->channels[i] = NULL;
2145
2146 /* store which card & revision we have */
2147 pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor);
2148 pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice);
2149 pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
2150
2151 pci_irq = pdev->irq;
2152 brd->irq = pci_irq;
2153
2154 /* get the PCI Base Address Registers */
2155
2156 /* Xr Jupiter and EPC use BAR 2 */
2157 if (brd->device == PCI_DEV_XRJ_DID || brd->device == PCI_DEV_EPCJ_DID) {
2158 brd->membase = pci_resource_start(pdev, 2);
2159 brd->membase_end = pci_resource_end(pdev, 2);
2160 }
2161 /* Everyone else uses BAR 0 */
2162 else {
2163 brd->membase = pci_resource_start(pdev, 0);
2164 brd->membase_end = pci_resource_end(pdev, 0);
2165 }
2166
2167 if (!brd->membase) {
2168 ret = -ENODEV;
2169 goto free_brd;
2170 }
2171
2172 if (brd->membase & 1)
2173 brd->membase &= ~3;
2174 else
2175 brd->membase &= ~15;
2176
2177 /*
2178 * On the PCI boards, there is no IO space allocated
2179 * The I/O registers will be in the first 3 bytes of the
2180 * upper 2MB of the 4MB memory space. The board memory
2181 * will be mapped into the low 2MB of the 4MB memory space
2182 */
2183 brd->port = brd->membase + PCI_IO_OFFSET;
Fabio Estevam4c1d2dc2015-03-03 09:55:43 -03002184 brd->port_end = brd->port + PCI_IO_SIZE_DGAP;
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09002185
2186 /*
2187 * Special initialization for non-PLX boards
2188 */
2189 if (brd->device != PCI_DEV_XRJ_DID && brd->device != PCI_DEV_EPCJ_DID) {
2190 unsigned short cmd;
2191
2192 pci_write_config_byte(pdev, 0x40, 0);
2193 pci_write_config_byte(pdev, 0x46, 0);
2194
2195 /* Limit burst length to 2 doubleword transactions */
2196 pci_write_config_byte(pdev, 0x42, 1);
2197
2198 /*
2199 * Enable IO and mem if not already done.
2200 * This was needed for support on Itanium.
2201 */
2202 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
2203 cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
2204 pci_write_config_word(pdev, PCI_COMMAND, cmd);
2205 }
2206
2207 /* init our poll helper tasklet */
2208 tasklet_init(&brd->helper_tasklet, dgap_poll_tasklet,
2209 (unsigned long) brd);
2210
2211 ret = dgap_remap(brd);
2212 if (ret)
2213 goto free_brd;
2214
2215 pr_info("dgap: board %d: %s (rev %d), irq %ld\n",
2216 boardnum, brd->name, brd->rev, brd->irq);
2217
2218 return brd;
2219
2220free_brd:
2221 kfree(brd);
2222
2223 return ERR_PTR(ret);
2224}
2225
2226/*
2227 * dgap_intr()
2228 *
2229 * Driver interrupt handler.
2230 */
2231static irqreturn_t dgap_intr(int irq, void *voidbrd)
2232{
2233 struct board_t *brd = voidbrd;
2234
2235 if (!brd)
2236 return IRQ_NONE;
2237
2238 /*
2239 * Check to make sure its for us.
2240 */
2241 if (brd->magic != DGAP_BOARD_MAGIC)
2242 return IRQ_NONE;
2243
2244 brd->intr_count++;
2245
2246 /*
2247 * Schedule tasklet to run at a better time.
2248 */
2249 tasklet_schedule(&brd->helper_tasklet);
2250 return IRQ_HANDLED;
2251}
2252
2253/*****************************************************************************
2254*
2255* Function:
2256*
2257* dgap_poll_handler
2258*
2259* Author:
2260*
2261* Scott H Kilau
2262*
2263* Parameters:
2264*
2265* dummy -- ignored
2266*
2267* Return Values:
2268*
2269* none
2270*
2271* Description:
2272*
2273* As each timer expires, it determines (a) whether the "transmit"
2274* waiter needs to be woken up, and (b) whether the poller needs to
2275* be rescheduled.
2276*
2277******************************************************************************/
2278
2279static void dgap_poll_handler(ulong dummy)
2280{
2281 unsigned int i;
2282 struct board_t *brd;
2283 unsigned long lock_flags;
2284 ulong new_time;
2285
2286 dgap_poll_counter++;
2287
2288 /*
2289 * Do not start the board state machine until
2290 * driver tells us its up and running, and has
2291 * everything it needs.
2292 */
2293 if (dgap_driver_state != DRIVER_READY)
2294 goto schedule_poller;
2295
2296 /*
2297 * If we have just 1 board, or the system is not SMP,
2298 * then use the typical old style poller.
2299 * Otherwise, use our new tasklet based poller, which should
2300 * speed things up for multiple boards.
2301 */
2302 if ((dgap_numboards == 1) || (num_online_cpus() <= 1)) {
2303 for (i = 0; i < dgap_numboards; i++) {
2304
2305 brd = dgap_board[i];
2306
2307 if (brd->state == BOARD_FAILED)
2308 continue;
2309 if (!brd->intr_running)
2310 /* Call the real board poller directly */
2311 dgap_poll_tasklet((unsigned long) brd);
2312 }
2313 } else {
2314 /*
2315 * Go thru each board, kicking off a
2316 * tasklet for each if needed
2317 */
2318 for (i = 0; i < dgap_numboards; i++) {
2319 brd = dgap_board[i];
2320
2321 /*
2322 * Attempt to grab the board lock.
2323 *
2324 * If we can't get it, no big deal, the next poll
2325 * will get it. Basically, I just really don't want
2326 * to spin in here, because I want to kick off my
2327 * tasklets as fast as I can, and then get out the
2328 * poller.
2329 */
2330 if (!spin_trylock(&brd->bd_lock))
2331 continue;
2332
2333 /*
2334 * If board is in a failed state, don't bother
2335 * scheduling a tasklet
2336 */
2337 if (brd->state == BOARD_FAILED) {
2338 spin_unlock(&brd->bd_lock);
2339 continue;
2340 }
2341
2342 /* Schedule a poll helper task */
2343 if (!brd->intr_running)
2344 tasklet_schedule(&brd->helper_tasklet);
2345
2346 /*
2347 * Can't do DGAP_UNLOCK here, as we don't have
2348 * lock_flags because we did a trylock above.
2349 */
2350 spin_unlock(&brd->bd_lock);
2351 }
2352 }
2353
2354schedule_poller:
2355
2356 /*
2357 * Schedule ourself back at the nominal wakeup interval.
2358 */
2359 spin_lock_irqsave(&dgap_poll_lock, lock_flags);
2360 dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick);
2361
2362 new_time = dgap_poll_time - jiffies;
2363
2364 if ((ulong) new_time >= 2 * dgap_poll_tick) {
2365 dgap_poll_time =
2366 jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
2367 }
2368
2369 dgap_poll_timer.function = dgap_poll_handler;
2370 dgap_poll_timer.data = 0;
2371 dgap_poll_timer.expires = dgap_poll_time;
2372 spin_unlock_irqrestore(&dgap_poll_lock, lock_flags);
2373
2374 if (!dgap_poll_stop)
2375 add_timer(&dgap_poll_timer);
2376}
2377
2378/*=======================================================================
2379 *
2380 * dgap_cmdb - Sends a 2 byte command to the FEP.
2381 *
2382 * ch - Pointer to channel structure.
2383 * cmd - Command to be sent.
2384 * byte1 - Integer containing first byte to be sent.
2385 * byte2 - Integer containing second byte to be sent.
2386 * ncmds - Wait until ncmds or fewer cmds are left
2387 * in the cmd buffer before returning.
2388 *
2389 *=======================================================================*/
2390static void dgap_cmdb(struct channel_t *ch, u8 cmd, u8 byte1,
2391 u8 byte2, uint ncmds)
2392{
2393 char __iomem *vaddr;
2394 struct __iomem cm_t *cm_addr;
2395 uint count;
2396 uint n;
2397 u16 head;
2398 u16 tail;
2399
2400 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
2401 return;
2402
2403 /*
2404 * Check if board is still alive.
2405 */
2406 if (ch->ch_bd->state == BOARD_FAILED)
2407 return;
2408
2409 /*
2410 * Make sure the pointers are in range before
2411 * writing to the FEP memory.
2412 */
2413 vaddr = ch->ch_bd->re_map_membase;
2414
2415 if (!vaddr)
2416 return;
2417
2418 cm_addr = (struct cm_t __iomem *) (vaddr + CMDBUF);
2419 head = readw(&(cm_addr->cm_head));
2420
2421 /*
2422 * Forget it if pointers out of range.
2423 */
2424 if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
2425 ch->ch_bd->state = BOARD_FAILED;
2426 return;
2427 }
2428
2429 /*
2430 * Put the data in the circular command buffer.
2431 */
2432 writeb(cmd, (vaddr + head + CMDSTART + 0));
2433 writeb((u8) ch->ch_portnum, (vaddr + head + CMDSTART + 1));
2434 writeb(byte1, (vaddr + head + CMDSTART + 2));
2435 writeb(byte2, (vaddr + head + CMDSTART + 3));
2436
2437 head = (head + 4) & (CMDMAX - CMDSTART - 4);
2438
2439 writew(head, &(cm_addr->cm_head));
2440
2441 /*
2442 * Wait if necessary before updating the head
2443 * pointer to limit the number of outstanding
2444 * commands to the FEP. If the time spent waiting
2445 * is outlandish, declare the FEP dead.
2446 */
2447 for (count = dgap_count ;;) {
2448
2449 head = readw(&(cm_addr->cm_head));
2450 tail = readw(&(cm_addr->cm_tail));
2451
2452 n = (head - tail) & (CMDMAX - CMDSTART - 4);
2453
2454 if (n <= ncmds * sizeof(struct cm_t))
2455 break;
2456
2457 if (--count == 0) {
2458 ch->ch_bd->state = BOARD_FAILED;
2459 return;
2460 }
2461 udelay(10);
2462 }
2463}
2464
2465/*=======================================================================
2466 *
2467 * dgap_cmdw - Sends a 1 word command to the FEP.
2468 *
2469 * ch - Pointer to channel structure.
2470 * cmd - Command to be sent.
2471 * word - Integer containing word to be sent.
2472 * ncmds - Wait until ncmds or fewer cmds are left
2473 * in the cmd buffer before returning.
2474 *
2475 *=======================================================================*/
2476static void dgap_cmdw(struct channel_t *ch, u8 cmd, u16 word, uint ncmds)
2477{
2478 char __iomem *vaddr;
2479 struct __iomem cm_t *cm_addr;
2480 uint count;
2481 uint n;
2482 u16 head;
2483 u16 tail;
2484
2485 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
2486 return;
2487
2488 /*
2489 * Check if board is still alive.
2490 */
2491 if (ch->ch_bd->state == BOARD_FAILED)
2492 return;
2493
2494 /*
2495 * Make sure the pointers are in range before
2496 * writing to the FEP memory.
2497 */
2498 vaddr = ch->ch_bd->re_map_membase;
2499 if (!vaddr)
2500 return;
2501
2502 cm_addr = (struct cm_t __iomem *) (vaddr + CMDBUF);
2503 head = readw(&(cm_addr->cm_head));
2504
2505 /*
2506 * Forget it if pointers out of range.
2507 */
2508 if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
2509 ch->ch_bd->state = BOARD_FAILED;
2510 return;
2511 }
2512
2513 /*
2514 * Put the data in the circular command buffer.
2515 */
2516 writeb(cmd, (vaddr + head + CMDSTART + 0));
2517 writeb((u8) ch->ch_portnum, (vaddr + head + CMDSTART + 1));
2518 writew((u16) word, (vaddr + head + CMDSTART + 2));
2519
2520 head = (head + 4) & (CMDMAX - CMDSTART - 4);
2521
2522 writew(head, &(cm_addr->cm_head));
2523
2524 /*
2525 * Wait if necessary before updating the head
2526 * pointer to limit the number of outstanding
2527 * commands to the FEP. If the time spent waiting
2528 * is outlandish, declare the FEP dead.
2529 */
2530 for (count = dgap_count ;;) {
2531
2532 head = readw(&(cm_addr->cm_head));
2533 tail = readw(&(cm_addr->cm_tail));
2534
2535 n = (head - tail) & (CMDMAX - CMDSTART - 4);
2536
2537 if (n <= ncmds * sizeof(struct cm_t))
2538 break;
2539
2540 if (--count == 0) {
2541 ch->ch_bd->state = BOARD_FAILED;
2542 return;
2543 }
2544 udelay(10);
2545 }
2546}
2547
2548/*=======================================================================
2549 *
2550 * dgap_cmdw_ext - Sends a extended word command to the FEP.
2551 *
2552 * ch - Pointer to channel structure.
2553 * cmd - Command to be sent.
2554 * word - Integer containing word to be sent.
2555 * ncmds - Wait until ncmds or fewer cmds are left
2556 * in the cmd buffer before returning.
2557 *
2558 *=======================================================================*/
2559static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds)
2560{
2561 char __iomem *vaddr;
2562 struct __iomem cm_t *cm_addr;
2563 uint count;
2564 uint n;
2565 u16 head;
2566 u16 tail;
2567
2568 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
2569 return;
2570
2571 /*
2572 * Check if board is still alive.
2573 */
2574 if (ch->ch_bd->state == BOARD_FAILED)
2575 return;
2576
2577 /*
2578 * Make sure the pointers are in range before
2579 * writing to the FEP memory.
2580 */
2581 vaddr = ch->ch_bd->re_map_membase;
2582 if (!vaddr)
2583 return;
2584
2585 cm_addr = (struct cm_t __iomem *) (vaddr + CMDBUF);
2586 head = readw(&(cm_addr->cm_head));
2587
2588 /*
2589 * Forget it if pointers out of range.
2590 */
2591 if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
2592 ch->ch_bd->state = BOARD_FAILED;
2593 return;
2594 }
2595
2596 /*
2597 * Put the data in the circular command buffer.
2598 */
2599
2600 /* Write an FF to tell the FEP that we want an extended command */
2601 writeb((u8) 0xff, (vaddr + head + CMDSTART + 0));
2602
2603 writeb((u8) ch->ch_portnum, (vaddr + head + CMDSTART + 1));
2604 writew((u16) cmd, (vaddr + head + CMDSTART + 2));
2605
2606 /*
2607 * If the second part of the command won't fit,
2608 * put it at the beginning of the circular buffer.
2609 */
2610 if (((head + 4) >= ((CMDMAX - CMDSTART)) || (head & 03)))
2611 writew((u16) word, (vaddr + CMDSTART));
2612 else
2613 writew((u16) word, (vaddr + head + CMDSTART + 4));
2614
2615 head = (head + 8) & (CMDMAX - CMDSTART - 4);
2616
2617 writew(head, &(cm_addr->cm_head));
2618
2619 /*
2620 * Wait if necessary before updating the head
2621 * pointer to limit the number of outstanding
2622 * commands to the FEP. If the time spent waiting
2623 * is outlandish, declare the FEP dead.
2624 */
2625 for (count = dgap_count ;;) {
2626
2627 head = readw(&(cm_addr->cm_head));
2628 tail = readw(&(cm_addr->cm_tail));
2629
2630 n = (head - tail) & (CMDMAX - CMDSTART - 4);
2631
2632 if (n <= ncmds * sizeof(struct cm_t))
2633 break;
2634
2635 if (--count == 0) {
2636 ch->ch_bd->state = BOARD_FAILED;
2637 return;
2638 }
2639 udelay(10);
2640 }
2641}
2642
2643/*=======================================================================
2644 *
2645 * dgap_wmove - Write data to FEP buffer.
2646 *
2647 * ch - Pointer to channel structure.
Colin Cronin469caab2015-05-15 13:02:40 -07002648 * buf - Pointer to characters to be moved.
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09002649 * cnt - Number of characters to move.
2650 *
2651 *=======================================================================*/
2652static void dgap_wmove(struct channel_t *ch, char *buf, uint cnt)
2653{
2654 int n;
2655 char __iomem *taddr;
2656 struct bs_t __iomem *bs;
2657 u16 head;
2658
2659 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
2660 return;
2661
2662 /*
2663 * Check parameters.
2664 */
2665 bs = ch->ch_bs;
2666 head = readw(&(bs->tx_head));
2667
2668 /*
2669 * If pointers are out of range, just return.
2670 */
2671 if ((cnt > ch->ch_tsize) ||
2672 (unsigned)(head - ch->ch_tstart) >= ch->ch_tsize)
2673 return;
2674
2675 /*
2676 * If the write wraps over the top of the circular buffer,
2677 * move the portion up to the wrap point, and reset the
2678 * pointers to the bottom.
2679 */
2680 n = ch->ch_tstart + ch->ch_tsize - head;
2681
2682 if (cnt >= n) {
2683 cnt -= n;
2684 taddr = ch->ch_taddr + head;
2685 memcpy_toio(taddr, buf, n);
2686 head = ch->ch_tstart;
2687 buf += n;
2688 }
2689
2690 /*
2691 * Move rest of data.
2692 */
2693 taddr = ch->ch_taddr + head;
2694 n = cnt;
2695 memcpy_toio(taddr, buf, n);
2696 head += cnt;
2697
2698 writew(head, &(bs->tx_head));
2699}
2700
2701/*
2702 * Calls the firmware to reset this channel.
2703 */
2704static void dgap_firmware_reset_port(struct channel_t *ch)
2705{
2706 dgap_cmdb(ch, CHRESET, 0, 0, 0);
2707
2708 /*
2709 * Now that the channel is reset, we need to make sure
2710 * all the current settings get reapplied to the port
2711 * in the firmware.
2712 *
2713 * So we will set the driver's cache of firmware
2714 * settings all to 0, and then call param.
2715 */
2716 ch->ch_fepiflag = 0;
2717 ch->ch_fepcflag = 0;
2718 ch->ch_fepoflag = 0;
2719 ch->ch_fepstartc = 0;
2720 ch->ch_fepstopc = 0;
2721 ch->ch_fepastartc = 0;
2722 ch->ch_fepastopc = 0;
2723 ch->ch_mostat = 0;
2724 ch->ch_hflow = 0;
2725}
2726
2727/*=======================================================================
2728 *
2729 * dgap_param - Set Digi parameters.
2730 *
2731 * struct tty_struct * - TTY for port.
2732 *
2733 *=======================================================================*/
2734static int dgap_param(struct channel_t *ch, struct board_t *bd, u32 un_type)
2735{
2736 u16 head;
2737 u16 cflag;
2738 u16 iflag;
2739 u8 mval;
2740 u8 hflow;
2741
2742 /*
2743 * If baud rate is zero, flush queues, and set mval to drop DTR.
2744 */
2745 if ((ch->ch_c_cflag & (CBAUD)) == 0) {
2746
2747 /* flush rx */
2748 head = readw(&(ch->ch_bs->rx_head));
2749 writew(head, &(ch->ch_bs->rx_tail));
2750
2751 /* flush tx */
2752 head = readw(&(ch->ch_bs->tx_head));
2753 writew(head, &(ch->ch_bs->tx_tail));
2754
2755 ch->ch_flags |= (CH_BAUD0);
2756
2757 /* Drop RTS and DTR */
2758 ch->ch_mval &= ~(D_RTS(ch)|D_DTR(ch));
2759 mval = D_DTR(ch) | D_RTS(ch);
2760 ch->ch_baud_info = 0;
2761
2762 } else if (ch->ch_custom_speed && (bd->bd_flags & BD_FEP5PLUS)) {
2763 /*
2764 * Tell the fep to do the command
2765 */
2766
2767 dgap_cmdw_ext(ch, 0xff01, ch->ch_custom_speed, 0);
2768
2769 /*
2770 * Now go get from fep mem, what the fep
2771 * believes the custom baud rate is.
2772 */
2773 ch->ch_custom_speed = dgap_get_custom_baud(ch);
2774 ch->ch_baud_info = ch->ch_custom_speed;
2775
2776 /* Handle transition from B0 */
2777 if (ch->ch_flags & CH_BAUD0) {
2778 ch->ch_flags &= ~(CH_BAUD0);
2779 ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
2780 }
2781 mval = D_DTR(ch) | D_RTS(ch);
2782
2783 } else {
2784 /*
2785 * Set baud rate, character size, and parity.
2786 */
2787
2788
2789 int iindex = 0;
2790 int jindex = 0;
2791 int baud = 0;
2792
2793 ulong bauds[4][16] = {
2794 { /* slowbaud */
2795 0, 50, 75, 110,
2796 134, 150, 200, 300,
2797 600, 1200, 1800, 2400,
2798 4800, 9600, 19200, 38400 },
2799 { /* slowbaud & CBAUDEX */
2800 0, 57600, 115200, 230400,
2801 460800, 150, 200, 921600,
2802 600, 1200, 1800, 2400,
2803 4800, 9600, 19200, 38400 },
2804 { /* fastbaud */
2805 0, 57600, 76800, 115200,
2806 14400, 57600, 230400, 76800,
2807 115200, 230400, 28800, 460800,
2808 921600, 9600, 19200, 38400 },
2809 { /* fastbaud & CBAUDEX */
2810 0, 57600, 115200, 230400,
2811 460800, 150, 200, 921600,
2812 600, 1200, 1800, 2400,
2813 4800, 9600, 19200, 38400 }
2814 };
2815
2816 /*
2817 * Only use the TXPrint baud rate if the
2818 * terminal unit is NOT open
2819 */
2820 if (!(ch->ch_tun.un_flags & UN_ISOPEN) &&
2821 un_type == DGAP_PRINT)
2822 baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
2823 else
2824 baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
2825
2826 if (ch->ch_c_cflag & CBAUDEX)
2827 iindex = 1;
2828
2829 if (ch->ch_digi.digi_flags & DIGI_FAST)
2830 iindex += 2;
2831
2832 jindex = baud;
2833
2834 if ((iindex >= 0) && (iindex < 4) &&
2835 (jindex >= 0) && (jindex < 16))
2836 baud = bauds[iindex][jindex];
2837 else
2838 baud = 0;
2839
2840 if (baud == 0)
2841 baud = 9600;
2842
2843 ch->ch_baud_info = baud;
2844
2845 /*
2846 * CBAUD has bit position 0x1000 set these days to
2847 * indicate Linux baud rate remap.
2848 * We use a different bit assignment for high speed.
2849 * Clear this bit out while grabbing the parts of
2850 * "cflag" we want.
2851 */
2852 cflag = ch->ch_c_cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB |
2853 CSTOPB | CSIZE);
2854
2855 /*
2856 * HUPCL bit is used by FEP to indicate fast baud
2857 * table is to be used.
2858 */
2859 if ((ch->ch_digi.digi_flags & DIGI_FAST) ||
2860 (ch->ch_c_cflag & CBAUDEX))
2861 cflag |= HUPCL;
2862
2863 if ((ch->ch_c_cflag & CBAUDEX) &&
2864 !(ch->ch_digi.digi_flags & DIGI_FAST)) {
2865 /*
2866 * The below code is trying to guarantee that only
2867 * baud rates 115200, 230400, 460800, 921600 are
2868 * remapped. We use exclusive or because the various
2869 * baud rates share common bit positions and therefore
2870 * can't be tested for easily.
2871 */
2872 tcflag_t tcflag = (ch->ch_c_cflag & CBAUD) | CBAUDEX;
2873 int baudpart = 0;
2874
2875 /*
2876 * Map high speed requests to index
2877 * into FEP's baud table
2878 */
2879 switch (tcflag) {
2880 case B57600:
2881 baudpart = 1;
2882 break;
2883#ifdef B76800
2884 case B76800:
2885 baudpart = 2;
2886 break;
2887#endif
2888 case B115200:
2889 baudpart = 3;
2890 break;
2891 case B230400:
2892 baudpart = 9;
2893 break;
2894 case B460800:
2895 baudpart = 11;
2896 break;
2897#ifdef B921600
2898 case B921600:
2899 baudpart = 12;
2900 break;
2901#endif
2902 default:
2903 baudpart = 0;
2904 }
2905
2906 if (baudpart)
2907 cflag = (cflag & ~(CBAUD | CBAUDEX)) | baudpart;
2908 }
2909
2910 cflag &= 0xffff;
2911
2912 if (cflag != ch->ch_fepcflag) {
2913 ch->ch_fepcflag = (u16) (cflag & 0xffff);
2914
2915 /*
2916 * Okay to have channel and board
2917 * locks held calling this
2918 */
2919 dgap_cmdw(ch, SCFLAG, (u16) cflag, 0);
2920 }
2921
2922 /* Handle transition from B0 */
2923 if (ch->ch_flags & CH_BAUD0) {
2924 ch->ch_flags &= ~(CH_BAUD0);
2925 ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
2926 }
2927 mval = D_DTR(ch) | D_RTS(ch);
2928 }
2929
2930 /*
2931 * Get input flags.
2932 */
2933 iflag = ch->ch_c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
2934 INPCK | ISTRIP | IXON | IXANY | IXOFF);
2935
2936 if ((ch->ch_startc == _POSIX_VDISABLE) ||
2937 (ch->ch_stopc == _POSIX_VDISABLE)) {
2938 iflag &= ~(IXON | IXOFF);
2939 ch->ch_c_iflag &= ~(IXON | IXOFF);
2940 }
2941
2942 /*
2943 * Only the IBM Xr card can switch between
2944 * 232 and 422 modes on the fly
2945 */
2946 if (bd->device == PCI_DEV_XR_IBM_DID) {
2947 if (ch->ch_digi.digi_flags & DIGI_422)
2948 dgap_cmdb(ch, SCOMMODE, MODE_422, 0, 0);
2949 else
2950 dgap_cmdb(ch, SCOMMODE, MODE_232, 0, 0);
2951 }
2952
2953 if (ch->ch_digi.digi_flags & DIGI_ALTPIN)
2954 iflag |= IALTPIN;
2955
2956 if (iflag != ch->ch_fepiflag) {
2957 ch->ch_fepiflag = iflag;
2958
2959 /* Okay to have channel and board locks held calling this */
2960 dgap_cmdw(ch, SIFLAG, (u16) ch->ch_fepiflag, 0);
2961 }
2962
2963 /*
2964 * Select hardware handshaking.
2965 */
2966 hflow = 0;
2967
2968 if (ch->ch_c_cflag & CRTSCTS)
2969 hflow |= (D_RTS(ch) | D_CTS(ch));
2970 if (ch->ch_digi.digi_flags & RTSPACE)
2971 hflow |= D_RTS(ch);
2972 if (ch->ch_digi.digi_flags & DTRPACE)
2973 hflow |= D_DTR(ch);
2974 if (ch->ch_digi.digi_flags & CTSPACE)
2975 hflow |= D_CTS(ch);
2976 if (ch->ch_digi.digi_flags & DSRPACE)
2977 hflow |= D_DSR(ch);
2978 if (ch->ch_digi.digi_flags & DCDPACE)
2979 hflow |= D_CD(ch);
2980
2981 if (hflow != ch->ch_hflow) {
2982 ch->ch_hflow = hflow;
2983
2984 /* Okay to have channel and board locks held calling this */
2985 dgap_cmdb(ch, SHFLOW, (u8) hflow, 0xff, 0);
2986 }
2987
2988 /*
2989 * Set RTS and/or DTR Toggle if needed,
2990 * but only if product is FEP5+ based.
2991 */
2992 if (bd->bd_flags & BD_FEP5PLUS) {
2993 u16 hflow2 = 0;
2994
2995 if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE)
2996 hflow2 |= (D_RTS(ch));
2997 if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE)
2998 hflow2 |= (D_DTR(ch));
2999
3000 dgap_cmdw_ext(ch, 0xff03, hflow2, 0);
3001 }
3002
3003 /*
3004 * Set modem control lines.
3005 */
3006
3007 mval ^= ch->ch_mforce & (mval ^ ch->ch_mval);
3008
3009 if (ch->ch_mostat ^ mval) {
3010 ch->ch_mostat = mval;
3011
3012 /* Okay to have channel and board locks held calling this */
3013 dgap_cmdb(ch, SMODEM, (u8) mval, D_RTS(ch)|D_DTR(ch), 0);
3014 }
3015
3016 /*
3017 * Read modem signals, and then call carrier function.
3018 */
3019 ch->ch_mistat = readb(&(ch->ch_bs->m_stat));
Mark Hounschella6792a32014-02-19 13:11:59 -05003020 dgap_carrier(ch);
Mark Hounschella6792a32014-02-19 13:11:59 -05003021
3022 /*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09003023 * Set the start and stop characters.
Mark Hounschella6792a32014-02-19 13:11:59 -05003024 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09003025 if (ch->ch_startc != ch->ch_fepstartc ||
3026 ch->ch_stopc != ch->ch_fepstopc) {
3027 ch->ch_fepstartc = ch->ch_startc;
3028 ch->ch_fepstopc = ch->ch_stopc;
Mark Hounschella6792a32014-02-19 13:11:59 -05003029
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09003030 /* Okay to have channel and board locks held calling this */
3031 dgap_cmdb(ch, SFLOWC, ch->ch_fepstartc, ch->ch_fepstopc, 0);
3032 }
Mark Hounschella6792a32014-02-19 13:11:59 -05003033
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09003034 /*
3035 * Set the Auxiliary start and stop characters.
3036 */
3037 if (ch->ch_astartc != ch->ch_fepastartc ||
3038 ch->ch_astopc != ch->ch_fepastopc) {
3039 ch->ch_fepastartc = ch->ch_astartc;
3040 ch->ch_fepastopc = ch->ch_astopc;
Mark Hounschella6792a32014-02-19 13:11:59 -05003041
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09003042 /* Okay to have channel and board locks held calling this */
3043 dgap_cmdb(ch, SAFLOWC, ch->ch_fepastartc, ch->ch_fepastopc, 0);
3044 }
Mark Hounschella6792a32014-02-19 13:11:59 -05003045
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09003046 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003047}
3048
Mark Hounschella6792a32014-02-19 13:11:59 -05003049/*
3050 * dgap_block_til_ready()
3051 *
3052 * Wait for DCD, if needed.
3053 */
Mark Hounschell6045b6a2014-03-06 13:02:45 -05003054static int dgap_block_til_ready(struct tty_struct *tty, struct file *file,
3055 struct channel_t *ch)
Mark Hounschella6792a32014-02-19 13:11:59 -05003056{
3057 int retval = 0;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003058 struct un_t *un;
Mark Hounschell174efc12014-05-23 12:54:04 -04003059 ulong lock_flags;
3060 uint old_flags;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003061 int sleep_on_un_flags;
Mark Hounschella6792a32014-02-19 13:11:59 -05003062
Mark Hounschell305ec872014-02-28 12:42:13 -05003063 if (!tty || tty->magic != TTY_MAGIC || !file || !ch ||
3064 ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschell6d488a02014-05-28 16:18:03 -04003065 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003066
3067 un = tty->driver_data;
Mark Hounschell305ec872014-02-28 12:42:13 -05003068 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschell6d488a02014-05-28 16:18:03 -04003069 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003070
Mark Hounschellc43846a2014-03-19 11:10:51 -04003071 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003072
3073 ch->ch_wopen++;
3074
3075 /* Loop forever */
3076 while (1) {
3077
3078 sleep_on_un_flags = 0;
3079
3080 /*
Mark Hounschell6045b6a2014-03-06 13:02:45 -05003081 * If board has failed somehow during our sleep,
3082 * bail with error.
Mark Hounschella6792a32014-02-19 13:11:59 -05003083 */
3084 if (ch->ch_bd->state == BOARD_FAILED) {
Mark Hounschell6d488a02014-05-28 16:18:03 -04003085 retval = -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003086 break;
3087 }
3088
3089 /* If tty was hung up, break out of loop and set error. */
3090 if (tty_hung_up_p(file)) {
3091 retval = -EAGAIN;
3092 break;
3093 }
3094
3095 /*
3096 * If either unit is in the middle of the fragile part of close,
3097 * we just cannot touch the channel safely.
3098 * Go back to sleep, knowing that when the channel can be
3099 * touched safely, the close routine will signal the
3100 * ch_wait_flags to wake us back up.
3101 */
Mark Hounschell6045b6a2014-03-06 13:02:45 -05003102 if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) &
3103 UN_CLOSING)) {
Mark Hounschella6792a32014-02-19 13:11:59 -05003104
3105 /*
3106 * Our conditions to leave cleanly and happily:
3107 * 1) NONBLOCKING on the tty is set.
3108 * 2) CLOCAL is set.
3109 * 3) DCD (fake or real) is active.
3110 */
3111
Mark Hounschell305ec872014-02-28 12:42:13 -05003112 if (file->f_flags & O_NONBLOCK)
Mark Hounschella6792a32014-02-19 13:11:59 -05003113 break;
Mark Hounschella6792a32014-02-19 13:11:59 -05003114
Mark Hounschell305ec872014-02-28 12:42:13 -05003115 if (tty->flags & (1 << TTY_IO_ERROR))
Mark Hounschella6792a32014-02-19 13:11:59 -05003116 break;
Mark Hounschella6792a32014-02-19 13:11:59 -05003117
Mark Hounschell31960c12014-02-28 12:42:08 -05003118 if (ch->ch_flags & CH_CD)
Mark Hounschella6792a32014-02-19 13:11:59 -05003119 break;
Mark Hounschella6792a32014-02-19 13:11:59 -05003120
Mark Hounschell31960c12014-02-28 12:42:08 -05003121 if (ch->ch_flags & CH_FCAR)
Mark Hounschella6792a32014-02-19 13:11:59 -05003122 break;
Mark Hounschell305ec872014-02-28 12:42:13 -05003123 } else {
Mark Hounschella6792a32014-02-19 13:11:59 -05003124 sleep_on_un_flags = 1;
3125 }
3126
3127 /*
3128 * If there is a signal pending, the user probably
3129 * interrupted (ctrl-c) us.
3130 * Leave loop with error set.
3131 */
3132 if (signal_pending(current)) {
Mark Hounschella6792a32014-02-19 13:11:59 -05003133 retval = -ERESTARTSYS;
3134 break;
3135 }
3136
Mark Hounschella6792a32014-02-19 13:11:59 -05003137 /*
3138 * Store the flags before we let go of channel lock
3139 */
3140 if (sleep_on_un_flags)
3141 old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags;
3142 else
3143 old_flags = ch->ch_flags;
3144
3145 /*
3146 * Let go of channel lock before calling schedule.
3147 * Our poller will get any FEP events and wake us up when DCD
3148 * eventually goes active.
3149 */
3150
Mark Hounschellc43846a2014-03-19 11:10:51 -04003151 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003152
Mark Hounschella6792a32014-02-19 13:11:59 -05003153 /*
Mark Hounschell6045b6a2014-03-06 13:02:45 -05003154 * Wait for something in the flags to change
3155 * from the current value.
Mark Hounschella6792a32014-02-19 13:11:59 -05003156 */
3157 if (sleep_on_un_flags) {
3158 retval = wait_event_interruptible(un->un_flags_wait,
Mark Hounschell6045b6a2014-03-06 13:02:45 -05003159 (old_flags != (ch->ch_tun.un_flags |
3160 ch->ch_pun.un_flags)));
Mark Hounschell305ec872014-02-28 12:42:13 -05003161 } else {
Mark Hounschella6792a32014-02-19 13:11:59 -05003162 retval = wait_event_interruptible(ch->ch_flags_wait,
3163 (old_flags != ch->ch_flags));
3164 }
3165
Mark Hounschella6792a32014-02-19 13:11:59 -05003166 /*
3167 * We got woken up for some reason.
3168 * Before looping around, grab our channel lock.
3169 */
Mark Hounschellc43846a2014-03-19 11:10:51 -04003170 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003171 }
3172
3173 ch->ch_wopen--;
3174
Mark Hounschellc43846a2014-03-19 11:10:51 -04003175 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003176
Daeseok Youndfa30ac2014-07-15 18:47:11 +09003177 return retval;
Mark Hounschella6792a32014-02-19 13:11:59 -05003178}
3179
Mark Hounschella6792a32014-02-19 13:11:59 -05003180/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09003181 * dgap_tty_flush_buffer()
3182 *
3183 * Flush Tx buffer (make in == out)
3184 */
3185static void dgap_tty_flush_buffer(struct tty_struct *tty)
3186{
3187 struct board_t *bd;
3188 struct channel_t *ch;
3189 struct un_t *un;
3190 ulong lock_flags;
3191 ulong lock_flags2;
3192 u16 head;
3193
3194 if (!tty || tty->magic != TTY_MAGIC)
3195 return;
3196
3197 un = tty->driver_data;
3198 if (!un || un->magic != DGAP_UNIT_MAGIC)
3199 return;
3200
3201 ch = un->un_ch;
3202 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
3203 return;
3204
3205 bd = ch->ch_bd;
3206 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
3207 return;
3208
3209 spin_lock_irqsave(&bd->bd_lock, lock_flags);
3210 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
3211
3212 ch->ch_flags &= ~CH_STOP;
3213 head = readw(&(ch->ch_bs->tx_head));
3214 dgap_cmdw(ch, FLUSHTX, (u16) head, 0);
3215 dgap_cmdw(ch, RESUMETX, 0, 0);
3216 if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
3217 ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
3218 wake_up_interruptible(&ch->ch_tun.un_flags_wait);
3219 }
3220 if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
3221 ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
3222 wake_up_interruptible(&ch->ch_pun.un_flags_wait);
3223 }
3224
3225 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
3226 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
3227 if (waitqueue_active(&tty->write_wait))
3228 wake_up_interruptible(&tty->write_wait);
3229 tty_wakeup(tty);
3230}
3231
3232/*
Mark Hounschella6792a32014-02-19 13:11:59 -05003233 * dgap_tty_hangup()
3234 *
3235 * Hangup the port. Like a close, but don't wait for output to drain.
3236 */
3237static void dgap_tty_hangup(struct tty_struct *tty)
3238{
Mark Hounschell174efc12014-05-23 12:54:04 -04003239 struct board_t *bd;
Mark Hounschella6792a32014-02-19 13:11:59 -05003240 struct channel_t *ch;
Mark Hounschell174efc12014-05-23 12:54:04 -04003241 struct un_t *un;
Mark Hounschella6792a32014-02-19 13:11:59 -05003242
3243 if (!tty || tty->magic != TTY_MAGIC)
3244 return;
3245
3246 un = tty->driver_data;
3247 if (!un || un->magic != DGAP_UNIT_MAGIC)
3248 return;
3249
3250 ch = un->un_ch;
3251 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
3252 return;
3253
3254 bd = ch->ch_bd;
3255 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
3256 return;
3257
Mark Hounschella6792a32014-02-19 13:11:59 -05003258 /* flush the transmit queues */
3259 dgap_tty_flush_buffer(tty);
Mark Hounschella6792a32014-02-19 13:11:59 -05003260}
3261
Mark Hounschella6792a32014-02-19 13:11:59 -05003262/*
Mark Hounschella6792a32014-02-19 13:11:59 -05003263 * dgap_tty_chars_in_buffer()
3264 *
3265 * Return number of characters that have not been transmitted yet.
3266 *
3267 * This routine is used by the line discipline to determine if there
3268 * is data waiting to be transmitted/drained/flushed or not.
3269 */
3270static int dgap_tty_chars_in_buffer(struct tty_struct *tty)
3271{
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003272 struct board_t *bd;
3273 struct channel_t *ch;
3274 struct un_t *un;
Mark Hounschell405b26d2014-04-23 16:25:27 -04003275 struct bs_t __iomem *bs;
Mark Hounschell2023d182014-04-14 16:42:43 -04003276 u8 tbusy;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003277 uint chars;
Mark Hounschella6792a32014-02-19 13:11:59 -05003278 u16 thead, ttail, tmask, chead, ctail;
Mark Hounschell174efc12014-05-23 12:54:04 -04003279 ulong lock_flags = 0;
3280 ulong lock_flags2 = 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003281
Mark Hounschell9a133a92014-05-28 16:17:45 -04003282 if (!tty)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003283 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003284
3285 un = tty->driver_data;
3286 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003287 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003288
3289 ch = un->un_ch;
3290 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003291 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003292
3293 bd = ch->ch_bd;
3294 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003295 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003296
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003297 bs = ch->ch_bs;
Mark Hounschella6792a32014-02-19 13:11:59 -05003298 if (!bs)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003299 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003300
Mark Hounschellc43846a2014-03-19 11:10:51 -04003301 spin_lock_irqsave(&bd->bd_lock, lock_flags);
3302 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05003303
3304 tmask = (ch->ch_tsize - 1);
3305
3306 /* Get Transmit queue pointers */
3307 thead = readw(&(bs->tx_head)) & tmask;
3308 ttail = readw(&(bs->tx_tail)) & tmask;
3309
3310 /* Get tbusy flag */
3311 tbusy = readb(&(bs->tbusy));
3312
3313 /* Get Command queue pointers */
3314 chead = readw(&(ch->ch_cm->cm_head));
3315 ctail = readw(&(ch->ch_cm->cm_tail));
3316
Mark Hounschellc43846a2014-03-19 11:10:51 -04003317 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
3318 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003319
3320 /*
3321 * The only way we know for sure if there is no pending
3322 * data left to be transferred, is if:
3323 * 1) Transmit head and tail are equal (empty).
3324 * 2) Command queue head and tail are equal (empty).
3325 * 3) The "TBUSY" flag is 0. (Transmitter not busy).
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003326 */
Mark Hounschella6792a32014-02-19 13:11:59 -05003327
3328 if ((ttail == thead) && (tbusy == 0) && (chead == ctail)) {
3329 chars = 0;
Mark Hounschell305ec872014-02-28 12:42:13 -05003330 } else {
Mark Hounschella6792a32014-02-19 13:11:59 -05003331 if (thead >= ttail)
3332 chars = thead - ttail;
3333 else
3334 chars = thead - ttail + ch->ch_tsize;
3335 /*
3336 * Fudge factor here.
3337 * If chars is zero, we know that the command queue had
3338 * something in it or tbusy was set. Because we cannot
3339 * be sure if there is still some data to be transmitted,
3340 * lets lie, and tell ld we have 1 byte left.
3341 */
3342 if (chars == 0) {
3343 /*
3344 * If TBUSY is still set, and our tx buffers are empty,
3345 * force the firmware to send me another wakeup after
3346 * TBUSY has been cleared.
3347 */
3348 if (tbusy != 0) {
Mark Hounschellc43846a2014-03-19 11:10:51 -04003349 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003350 un->un_flags |= UN_EMPTY;
3351 writeb(1, &(bs->iempty));
Mark Hounschellc43846a2014-03-19 11:10:51 -04003352 spin_unlock_irqrestore(&ch->ch_lock,
3353 lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003354 }
3355 chars = 1;
3356 }
3357 }
3358
Mark Hounschellcf42c342014-02-28 12:42:09 -05003359 return chars;
Mark Hounschella6792a32014-02-19 13:11:59 -05003360}
3361
Mark Hounschella6792a32014-02-19 13:11:59 -05003362static int dgap_wait_for_drain(struct tty_struct *tty)
3363{
3364 struct channel_t *ch;
3365 struct un_t *un;
Mark Hounschell405b26d2014-04-23 16:25:27 -04003366 struct bs_t __iomem *bs;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003367 int ret = 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003368 uint count = 1;
Mark Hounschell174efc12014-05-23 12:54:04 -04003369 ulong lock_flags = 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003370
3371 if (!tty || tty->magic != TTY_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003372 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003373
3374 un = tty->driver_data;
3375 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003376 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003377
3378 ch = un->un_ch;
3379 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003380 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003381
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003382 bs = ch->ch_bs;
Mark Hounschella6792a32014-02-19 13:11:59 -05003383 if (!bs)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003384 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003385
Mark Hounschella6792a32014-02-19 13:11:59 -05003386 /* Loop until data is drained */
3387 while (count != 0) {
3388
3389 count = dgap_tty_chars_in_buffer(tty);
3390
3391 if (count == 0)
3392 break;
3393
3394 /* Set flag waiting for drain */
Mark Hounschellc43846a2014-03-19 11:10:51 -04003395 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003396 un->un_flags |= UN_EMPTY;
3397 writeb(1, &(bs->iempty));
Mark Hounschellc43846a2014-03-19 11:10:51 -04003398 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003399
3400 /* Go to sleep till we get woken up */
Mark Hounschell6045b6a2014-03-06 13:02:45 -05003401 ret = wait_event_interruptible(un->un_flags_wait,
3402 ((un->un_flags & UN_EMPTY) == 0));
Mark Hounschella6792a32014-02-19 13:11:59 -05003403 /* If ret is non-zero, user ctrl-c'ed us */
Mark Hounschell305ec872014-02-28 12:42:13 -05003404 if (ret)
Mark Hounschella6792a32014-02-19 13:11:59 -05003405 break;
Mark Hounschella6792a32014-02-19 13:11:59 -05003406 }
3407
Mark Hounschellc43846a2014-03-19 11:10:51 -04003408 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003409 un->un_flags &= ~(UN_EMPTY);
Mark Hounschellc43846a2014-03-19 11:10:51 -04003410 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003411
Mark Hounschellcf42c342014-02-28 12:42:09 -05003412 return ret;
Mark Hounschella6792a32014-02-19 13:11:59 -05003413}
3414
Mark Hounschella6792a32014-02-19 13:11:59 -05003415/*
3416 * dgap_maxcps_room
3417 *
3418 * Reduces bytes_available to the max number of characters
3419 * that can be sent currently given the maxcps value, and
3420 * returns the new bytes_available. This only affects printer
3421 * output.
3422 */
Daeseok Younbdf4d4f2014-07-10 12:26:04 +09003423static int dgap_maxcps_room(struct channel_t *ch, struct un_t *un,
3424 int bytes_available)
Mark Hounschella6792a32014-02-19 13:11:59 -05003425{
Mark Hounschella6792a32014-02-19 13:11:59 -05003426 /*
3427 * If its not the Transparent print device, return
3428 * the full data amount.
3429 */
3430 if (un->un_type != DGAP_PRINT)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003431 return bytes_available;
Mark Hounschella6792a32014-02-19 13:11:59 -05003432
Mark Hounschellb115b022014-02-28 12:42:15 -05003433 if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0) {
Mark Hounschella6792a32014-02-19 13:11:59 -05003434 int cps_limit = 0;
3435 unsigned long current_time = jiffies;
3436 unsigned long buffer_time = current_time +
Mark Hounschell6045b6a2014-03-06 13:02:45 -05003437 (HZ * ch->ch_digi.digi_bufsize) /
3438 ch->ch_digi.digi_maxcps;
Mark Hounschella6792a32014-02-19 13:11:59 -05003439
3440 if (ch->ch_cpstime < current_time) {
3441 /* buffer is empty */
Mark Hounschell8a2c9c42014-03-05 15:54:50 -05003442 ch->ch_cpstime = current_time; /* reset ch_cpstime */
Mark Hounschella6792a32014-02-19 13:11:59 -05003443 cps_limit = ch->ch_digi.digi_bufsize;
Mark Hounschell305ec872014-02-28 12:42:13 -05003444 } else if (ch->ch_cpstime < buffer_time) {
Mark Hounschella6792a32014-02-19 13:11:59 -05003445 /* still room in the buffer */
Mark Hounschell6045b6a2014-03-06 13:02:45 -05003446 cps_limit = ((buffer_time - ch->ch_cpstime) *
3447 ch->ch_digi.digi_maxcps) / HZ;
Mark Hounschell305ec872014-02-28 12:42:13 -05003448 } else {
Mark Hounschella6792a32014-02-19 13:11:59 -05003449 /* no room in the buffer */
3450 cps_limit = 0;
3451 }
3452
3453 bytes_available = min(cps_limit, bytes_available);
3454 }
3455
Mark Hounschellcf42c342014-02-28 12:42:09 -05003456 return bytes_available;
Mark Hounschella6792a32014-02-19 13:11:59 -05003457}
3458
Mark Hounschella6792a32014-02-19 13:11:59 -05003459static inline void dgap_set_firmware_event(struct un_t *un, unsigned int event)
3460{
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003461 struct channel_t *ch;
3462 struct bs_t __iomem *bs;
Mark Hounschella6792a32014-02-19 13:11:59 -05003463
3464 if (!un || un->magic != DGAP_UNIT_MAGIC)
3465 return;
3466 ch = un->un_ch;
3467 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
3468 return;
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003469 bs = ch->ch_bs;
Mark Hounschella6792a32014-02-19 13:11:59 -05003470 if (!bs)
3471 return;
3472
3473 if ((event & UN_LOW) != 0) {
3474 if ((un->un_flags & UN_LOW) == 0) {
3475 un->un_flags |= UN_LOW;
3476 writeb(1, &(bs->ilow));
3477 }
3478 }
3479 if ((event & UN_LOW) != 0) {
3480 if ((un->un_flags & UN_EMPTY) == 0) {
3481 un->un_flags |= UN_EMPTY;
3482 writeb(1, &(bs->iempty));
3483 }
3484 }
3485}
3486
Mark Hounschella6792a32014-02-19 13:11:59 -05003487/*
3488 * dgap_tty_write_room()
3489 *
3490 * Return space available in Tx buffer
3491 */
3492static int dgap_tty_write_room(struct tty_struct *tty)
3493{
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003494 struct channel_t *ch;
3495 struct un_t *un;
Mark Hounschell405b26d2014-04-23 16:25:27 -04003496 struct bs_t __iomem *bs;
Mark Hounschella6792a32014-02-19 13:11:59 -05003497 u16 head, tail, tmask;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003498 int ret;
Mark Hounschell174efc12014-05-23 12:54:04 -04003499 ulong lock_flags = 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003500
Mark Hounschell61260222014-03-06 13:03:33 -05003501 if (!tty)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003502 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003503
3504 un = tty->driver_data;
3505 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003506 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003507
3508 ch = un->un_ch;
3509 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003510 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003511
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003512 bs = ch->ch_bs;
Mark Hounschella6792a32014-02-19 13:11:59 -05003513 if (!bs)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003514 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003515
Mark Hounschellc43846a2014-03-19 11:10:51 -04003516 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003517
3518 tmask = ch->ch_tsize - 1;
3519 head = readw(&(bs->tx_head)) & tmask;
3520 tail = readw(&(bs->tx_tail)) & tmask;
3521
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003522 ret = tail - head - 1;
3523 if (ret < 0)
3524 ret += ch->ch_tsize;
Mark Hounschella6792a32014-02-19 13:11:59 -05003525
3526 /* Limit printer to maxcps */
Daeseok Younbdf4d4f2014-07-10 12:26:04 +09003527 ret = dgap_maxcps_room(ch, un, ret);
Mark Hounschella6792a32014-02-19 13:11:59 -05003528
3529 /*
3530 * If we are printer device, leave space for
3531 * possibly both the on and off strings.
3532 */
3533 if (un->un_type == DGAP_PRINT) {
3534 if (!(ch->ch_flags & CH_PRON))
3535 ret -= ch->ch_digi.digi_onlen;
3536 ret -= ch->ch_digi.digi_offlen;
Mark Hounschell305ec872014-02-28 12:42:13 -05003537 } else {
Mark Hounschella6792a32014-02-19 13:11:59 -05003538 if (ch->ch_flags & CH_PRON)
3539 ret -= ch->ch_digi.digi_offlen;
3540 }
3541
3542 if (ret < 0)
3543 ret = 0;
3544
3545 /*
3546 * Schedule FEP to wake us up if needed.
3547 *
3548 * TODO: This might be overkill...
3549 * Do we really need to schedule callbacks from the FEP
3550 * in every case? Can we get smarter based on ret?
3551 */
3552 dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
Mark Hounschellc43846a2014-03-19 11:10:51 -04003553 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003554
Mark Hounschellcf42c342014-02-28 12:42:09 -05003555 return ret;
Mark Hounschella6792a32014-02-19 13:11:59 -05003556}
3557
Mark Hounschella6792a32014-02-19 13:11:59 -05003558/*
Mark Hounschella6792a32014-02-19 13:11:59 -05003559 * dgap_tty_write()
3560 *
3561 * Take data from the user or kernel and send it out to the FEP.
3562 * In here exists all the Transparent Print magic as well.
3563 */
Mark Hounschell8a2c9c42014-03-05 15:54:50 -05003564static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf,
3565 int count)
Mark Hounschella6792a32014-02-19 13:11:59 -05003566{
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003567 struct channel_t *ch;
3568 struct un_t *un;
Mark Hounschell405b26d2014-04-23 16:25:27 -04003569 struct bs_t __iomem *bs;
Mark Hounschell630b2ab2014-04-24 09:22:12 -04003570 char __iomem *vaddr;
Mark Hounschella6792a32014-02-19 13:11:59 -05003571 u16 head, tail, tmask, remain;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003572 int bufcount, n;
Mark Hounschella6792a32014-02-19 13:11:59 -05003573 ulong lock_flags;
Mark Hounschella6792a32014-02-19 13:11:59 -05003574
Mark Hounschell61260222014-03-06 13:03:33 -05003575 if (!tty)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003576 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003577
3578 un = tty->driver_data;
3579 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003580 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003581
3582 ch = un->un_ch;
3583 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003584 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003585
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003586 bs = ch->ch_bs;
Mark Hounschella6792a32014-02-19 13:11:59 -05003587 if (!bs)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003588 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003589
3590 if (!count)
Mark Hounschellcf42c342014-02-28 12:42:09 -05003591 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003592
Mark Hounschellc43846a2014-03-19 11:10:51 -04003593 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003594
3595 /* Get our space available for the channel from the board */
3596 tmask = ch->ch_tsize - 1;
3597 head = readw(&(bs->tx_head)) & tmask;
3598 tail = readw(&(bs->tx_tail)) & tmask;
3599
Mark Hounschelld1c3c6f2014-02-28 15:48:44 -05003600 bufcount = tail - head - 1;
3601 if (bufcount < 0)
Mark Hounschella6792a32014-02-19 13:11:59 -05003602 bufcount += ch->ch_tsize;
3603
Mark Hounschella6792a32014-02-19 13:11:59 -05003604 /*
3605 * Limit printer output to maxcps overall, with bursts allowed
3606 * up to bufsize characters.
3607 */
Daeseok Younbdf4d4f2014-07-10 12:26:04 +09003608 bufcount = dgap_maxcps_room(ch, un, bufcount);
Mark Hounschella6792a32014-02-19 13:11:59 -05003609
3610 /*
3611 * Take minimum of what the user wants to send, and the
3612 * space available in the FEP buffer.
3613 */
3614 count = min(count, bufcount);
3615
3616 /*
3617 * Bail if no space left.
3618 */
3619 if (count <= 0) {
3620 dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
Mark Hounschellc43846a2014-03-19 11:10:51 -04003621 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschellcf42c342014-02-28 12:42:09 -05003622 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003623 }
3624
3625 /*
3626 * Output the printer ON string, if we are in terminal mode, but
3627 * need to be in printer mode.
3628 */
3629 if ((un->un_type == DGAP_PRINT) && !(ch->ch_flags & CH_PRON)) {
3630 dgap_wmove(ch, ch->ch_digi.digi_onstr,
3631 (int) ch->ch_digi.digi_onlen);
3632 head = readw(&(bs->tx_head)) & tmask;
3633 ch->ch_flags |= CH_PRON;
3634 }
3635
3636 /*
3637 * On the other hand, output the printer OFF string, if we are
3638 * currently in printer mode, but need to output to the terminal.
3639 */
3640 if ((un->un_type != DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
3641 dgap_wmove(ch, ch->ch_digi.digi_offstr,
3642 (int) ch->ch_digi.digi_offlen);
3643 head = readw(&(bs->tx_head)) & tmask;
3644 ch->ch_flags &= ~CH_PRON;
3645 }
3646
Mark Hounschella6792a32014-02-19 13:11:59 -05003647 n = count;
3648
3649 /*
3650 * If the write wraps over the top of the circular buffer,
3651 * move the portion up to the wrap point, and reset the
3652 * pointers to the bottom.
3653 */
3654 remain = ch->ch_tstart + ch->ch_tsize - head;
3655
3656 if (n >= remain) {
3657 n -= remain;
3658 vaddr = ch->ch_taddr + head;
3659
Mark Hounschell2023d182014-04-14 16:42:43 -04003660 memcpy_toio(vaddr, (u8 *) buf, remain);
Mark Hounschella6792a32014-02-19 13:11:59 -05003661
3662 head = ch->ch_tstart;
3663 buf += remain;
3664 }
3665
3666 if (n > 0) {
3667
3668 /*
3669 * Move rest of data.
3670 */
3671 vaddr = ch->ch_taddr + head;
3672 remain = n;
3673
Mark Hounschell2023d182014-04-14 16:42:43 -04003674 memcpy_toio(vaddr, (u8 *) buf, remain);
Mark Hounschella6792a32014-02-19 13:11:59 -05003675 head += remain;
3676
3677 }
3678
3679 if (count) {
3680 ch->ch_txcount += count;
3681 head &= tmask;
3682 writew(head, &(bs->tx_head));
3683 }
3684
Mark Hounschella6792a32014-02-19 13:11:59 -05003685 dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
3686
3687 /*
3688 * If this is the print device, and the
3689 * printer is still on, we need to turn it
3690 * off before going idle. If the buffer is
3691 * non-empty, wait until it goes empty.
3692 * Otherwise turn it off right now.
3693 */
3694 if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
3695 tail = readw(&(bs->tx_tail)) & tmask;
3696
3697 if (tail != head) {
3698 un->un_flags |= UN_EMPTY;
3699 writeb(1, &(bs->iempty));
Mark Hounschell305ec872014-02-28 12:42:13 -05003700 } else {
Mark Hounschella6792a32014-02-19 13:11:59 -05003701 dgap_wmove(ch, ch->ch_digi.digi_offstr,
3702 (int) ch->ch_digi.digi_offlen);
3703 head = readw(&(bs->tx_head)) & tmask;
3704 ch->ch_flags &= ~CH_PRON;
3705 }
3706 }
3707
3708 /* Update printer buffer empty time. */
3709 if ((un->un_type == DGAP_PRINT) && (ch->ch_digi.digi_maxcps > 0)
3710 && (ch->ch_digi.digi_bufsize > 0)) {
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003711 ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps;
Mark Hounschella6792a32014-02-19 13:11:59 -05003712 }
3713
Mark Hounschellc43846a2014-03-19 11:10:51 -04003714 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003715
Mark Hounschellcf42c342014-02-28 12:42:09 -05003716 return count;
Mark Hounschella6792a32014-02-19 13:11:59 -05003717}
3718
Mark Hounschella6792a32014-02-19 13:11:59 -05003719/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09003720 * dgap_tty_put_char()
3721 *
3722 * Put a character into ch->ch_buf
3723 *
3724 * - used by the line discipline for OPOST processing
3725 */
3726static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c)
3727{
3728 /*
3729 * Simply call tty_write.
3730 */
3731 dgap_tty_write(tty, &c, 1);
3732 return 1;
3733}
3734
3735/*
Mark Hounschella6792a32014-02-19 13:11:59 -05003736 * Return modem signals to ld.
3737 */
3738static int dgap_tty_tiocmget(struct tty_struct *tty)
3739{
3740 struct channel_t *ch;
3741 struct un_t *un;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003742 int result;
3743 u8 mstat;
Mark Hounschella6792a32014-02-19 13:11:59 -05003744 ulong lock_flags;
3745
3746 if (!tty || tty->magic != TTY_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003747 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003748
3749 un = tty->driver_data;
3750 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003751 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003752
3753 ch = un->un_ch;
3754 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003755 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003756
Mark Hounschellc43846a2014-03-19 11:10:51 -04003757 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003758
3759 mstat = readb(&(ch->ch_bs->m_stat));
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003760 /* Append any outbound signals that might be pending... */
3761 mstat |= ch->ch_mostat;
Mark Hounschella6792a32014-02-19 13:11:59 -05003762
Mark Hounschellc43846a2014-03-19 11:10:51 -04003763 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003764
3765 result = 0;
3766
3767 if (mstat & D_DTR(ch))
3768 result |= TIOCM_DTR;
3769 if (mstat & D_RTS(ch))
3770 result |= TIOCM_RTS;
3771 if (mstat & D_CTS(ch))
3772 result |= TIOCM_CTS;
3773 if (mstat & D_DSR(ch))
3774 result |= TIOCM_DSR;
3775 if (mstat & D_RI(ch))
3776 result |= TIOCM_RI;
3777 if (mstat & D_CD(ch))
3778 result |= TIOCM_CD;
3779
Mark Hounschella6792a32014-02-19 13:11:59 -05003780 return result;
3781}
3782
Mark Hounschella6792a32014-02-19 13:11:59 -05003783/*
3784 * dgap_tty_tiocmset()
3785 *
3786 * Set modem signals, called by ld.
3787 */
Mark Hounschella6792a32014-02-19 13:11:59 -05003788static int dgap_tty_tiocmset(struct tty_struct *tty,
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003789 unsigned int set, unsigned int clear)
Mark Hounschella6792a32014-02-19 13:11:59 -05003790{
3791 struct board_t *bd;
3792 struct channel_t *ch;
3793 struct un_t *un;
Mark Hounschella6792a32014-02-19 13:11:59 -05003794 ulong lock_flags;
3795 ulong lock_flags2;
3796
3797 if (!tty || tty->magic != TTY_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003798 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003799
3800 un = tty->driver_data;
3801 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003802 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003803
3804 ch = un->un_ch;
3805 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003806 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003807
3808 bd = ch->ch_bd;
3809 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003810 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003811
Mark Hounschellc43846a2014-03-19 11:10:51 -04003812 spin_lock_irqsave(&bd->bd_lock, lock_flags);
3813 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05003814
3815 if (set & TIOCM_RTS) {
3816 ch->ch_mforce |= D_RTS(ch);
3817 ch->ch_mval |= D_RTS(ch);
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003818 }
Mark Hounschella6792a32014-02-19 13:11:59 -05003819
3820 if (set & TIOCM_DTR) {
3821 ch->ch_mforce |= D_DTR(ch);
3822 ch->ch_mval |= D_DTR(ch);
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003823 }
Mark Hounschella6792a32014-02-19 13:11:59 -05003824
3825 if (clear & TIOCM_RTS) {
3826 ch->ch_mforce |= D_RTS(ch);
3827 ch->ch_mval &= ~(D_RTS(ch));
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003828 }
Mark Hounschella6792a32014-02-19 13:11:59 -05003829
3830 if (clear & TIOCM_DTR) {
3831 ch->ch_mforce |= D_DTR(ch);
3832 ch->ch_mval &= ~(D_DTR(ch));
Mark Hounschell7d6069d72014-02-28 12:42:10 -05003833 }
Mark Hounschella6792a32014-02-19 13:11:59 -05003834
Daeseok Younab6cdcb2014-07-11 19:22:39 +09003835 dgap_param(ch, bd, un->un_type);
Mark Hounschella6792a32014-02-19 13:11:59 -05003836
Mark Hounschellc43846a2014-03-19 11:10:51 -04003837 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
3838 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003839
Mark Hounschellcf42c342014-02-28 12:42:09 -05003840 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003841}
3842
Mark Hounschella6792a32014-02-19 13:11:59 -05003843/*
3844 * dgap_tty_send_break()
3845 *
3846 * Send a Break, called by ld.
3847 */
3848static int dgap_tty_send_break(struct tty_struct *tty, int msec)
3849{
3850 struct board_t *bd;
3851 struct channel_t *ch;
3852 struct un_t *un;
Mark Hounschella6792a32014-02-19 13:11:59 -05003853 ulong lock_flags;
3854 ulong lock_flags2;
3855
3856 if (!tty || tty->magic != TTY_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003857 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003858
3859 un = tty->driver_data;
3860 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003861 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003862
3863 ch = un->un_ch;
3864 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003865 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003866
3867 bd = ch->ch_bd;
3868 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003869 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05003870
3871 switch (msec) {
3872 case -1:
3873 msec = 0xFFFF;
3874 break;
3875 case 0:
3876 msec = 1;
3877 break;
3878 default:
3879 msec /= 10;
3880 break;
3881 }
3882
Mark Hounschellc43846a2014-03-19 11:10:51 -04003883 spin_lock_irqsave(&bd->bd_lock, lock_flags);
3884 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05003885#if 0
3886 dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
3887#endif
3888 dgap_cmdw(ch, SBREAK, (u16) msec, 0);
3889
Mark Hounschellc43846a2014-03-19 11:10:51 -04003890 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
3891 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003892
Mark Hounschellcf42c342014-02-28 12:42:09 -05003893 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05003894}
3895
Mark Hounschella6792a32014-02-19 13:11:59 -05003896/*
3897 * dgap_tty_wait_until_sent()
3898 *
3899 * wait until data has been transmitted, called by ld.
3900 */
3901static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout)
3902{
Mark Hounschell31960c12014-02-28 12:42:08 -05003903 dgap_wait_for_drain(tty);
Mark Hounschella6792a32014-02-19 13:11:59 -05003904}
3905
Mark Hounschella6792a32014-02-19 13:11:59 -05003906/*
3907 * dgap_send_xchar()
3908 *
3909 * send a high priority character, called by ld.
3910 */
3911static void dgap_tty_send_xchar(struct tty_struct *tty, char c)
3912{
3913 struct board_t *bd;
3914 struct channel_t *ch;
3915 struct un_t *un;
3916 ulong lock_flags;
3917 ulong lock_flags2;
3918
3919 if (!tty || tty->magic != TTY_MAGIC)
3920 return;
3921
3922 un = tty->driver_data;
3923 if (!un || un->magic != DGAP_UNIT_MAGIC)
3924 return;
3925
3926 ch = un->un_ch;
3927 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
3928 return;
3929
3930 bd = ch->ch_bd;
3931 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
3932 return;
3933
Mark Hounschellc43846a2014-03-19 11:10:51 -04003934 spin_lock_irqsave(&bd->bd_lock, lock_flags);
3935 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05003936
3937 /*
3938 * This is technically what we should do.
3939 * However, the NIST tests specifically want
3940 * to see each XON or XOFF character that it
3941 * sends, so lets just send each character
3942 * by hand...
3943 */
3944#if 0
Mark Hounschell305ec872014-02-28 12:42:13 -05003945 if (c == STOP_CHAR(tty))
Mark Hounschella6792a32014-02-19 13:11:59 -05003946 dgap_cmdw(ch, RPAUSE, 0, 0);
Mark Hounschell305ec872014-02-28 12:42:13 -05003947 else if (c == START_CHAR(tty))
Mark Hounschella6792a32014-02-19 13:11:59 -05003948 dgap_cmdw(ch, RRESUME, 0, 0);
Mark Hounschell305ec872014-02-28 12:42:13 -05003949 else
Mark Hounschella6792a32014-02-19 13:11:59 -05003950 dgap_wmove(ch, &c, 1);
Mark Hounschella6792a32014-02-19 13:11:59 -05003951#else
3952 dgap_wmove(ch, &c, 1);
3953#endif
3954
Mark Hounschellc43846a2014-03-19 11:10:51 -04003955 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
3956 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003957}
3958
Mark Hounschella6792a32014-02-19 13:11:59 -05003959/*
3960 * Return modem signals to ld.
3961 */
3962static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value)
3963{
Mark Hounschell7dfa3832014-05-23 10:14:02 -04003964 int result;
3965 u8 mstat;
Mark Hounschella6792a32014-02-19 13:11:59 -05003966 ulong lock_flags;
Mark Hounschella6792a32014-02-19 13:11:59 -05003967
Mark Hounschellc43846a2014-03-19 11:10:51 -04003968 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003969
3970 mstat = readb(&(ch->ch_bs->m_stat));
3971 /* Append any outbound signals that might be pending... */
3972 mstat |= ch->ch_mostat;
3973
Mark Hounschellc43846a2014-03-19 11:10:51 -04003974 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05003975
3976 result = 0;
3977
3978 if (mstat & D_DTR(ch))
3979 result |= TIOCM_DTR;
3980 if (mstat & D_RTS(ch))
3981 result |= TIOCM_RTS;
3982 if (mstat & D_CTS(ch))
3983 result |= TIOCM_CTS;
3984 if (mstat & D_DSR(ch))
3985 result |= TIOCM_DSR;
3986 if (mstat & D_RI(ch))
3987 result |= TIOCM_RI;
3988 if (mstat & D_CD(ch))
3989 result |= TIOCM_CD;
3990
Aya Mahfouze20af8a2015-02-27 15:11:02 +02003991 return put_user(result, value);
Mark Hounschella6792a32014-02-19 13:11:59 -05003992}
3993
Mark Hounschella6792a32014-02-19 13:11:59 -05003994/*
3995 * dgap_set_modem_info()
3996 *
3997 * Set modem signals, called by ld.
3998 */
Piotr Witoslawski70c0ed92014-09-04 08:18:53 +02003999static int dgap_set_modem_info(struct channel_t *ch, struct board_t *bd,
4000 struct un_t *un, unsigned int command,
4001 unsigned int __user *value)
Mark Hounschella6792a32014-02-19 13:11:59 -05004002{
Mark Hounschell7dfa3832014-05-23 10:14:02 -04004003 int ret;
4004 unsigned int arg;
Mark Hounschella6792a32014-02-19 13:11:59 -05004005 ulong lock_flags;
4006 ulong lock_flags2;
4007
Mark Hounschella6792a32014-02-19 13:11:59 -05004008 ret = get_user(arg, value);
Mark Hounschell31960c12014-02-28 12:42:08 -05004009 if (ret)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004010 return ret;
Mark Hounschella6792a32014-02-19 13:11:59 -05004011
4012 switch (command) {
4013 case TIOCMBIS:
4014 if (arg & TIOCM_RTS) {
4015 ch->ch_mforce |= D_RTS(ch);
4016 ch->ch_mval |= D_RTS(ch);
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004017 }
Mark Hounschella6792a32014-02-19 13:11:59 -05004018
4019 if (arg & TIOCM_DTR) {
4020 ch->ch_mforce |= D_DTR(ch);
4021 ch->ch_mval |= D_DTR(ch);
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004022 }
Mark Hounschella6792a32014-02-19 13:11:59 -05004023
4024 break;
4025
4026 case TIOCMBIC:
4027 if (arg & TIOCM_RTS) {
4028 ch->ch_mforce |= D_RTS(ch);
4029 ch->ch_mval &= ~(D_RTS(ch));
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004030 }
Mark Hounschella6792a32014-02-19 13:11:59 -05004031
4032 if (arg & TIOCM_DTR) {
4033 ch->ch_mforce |= D_DTR(ch);
4034 ch->ch_mval &= ~(D_DTR(ch));
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004035 }
Mark Hounschella6792a32014-02-19 13:11:59 -05004036
4037 break;
4038
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004039 case TIOCMSET:
Mark Hounschella6792a32014-02-19 13:11:59 -05004040 ch->ch_mforce = D_DTR(ch)|D_RTS(ch);
4041
Mark Hounschell305ec872014-02-28 12:42:13 -05004042 if (arg & TIOCM_RTS)
Mark Hounschella6792a32014-02-19 13:11:59 -05004043 ch->ch_mval |= D_RTS(ch);
Mark Hounschell305ec872014-02-28 12:42:13 -05004044 else
Mark Hounschella6792a32014-02-19 13:11:59 -05004045 ch->ch_mval &= ~(D_RTS(ch));
Mark Hounschella6792a32014-02-19 13:11:59 -05004046
Mark Hounschell305ec872014-02-28 12:42:13 -05004047 if (arg & TIOCM_DTR)
Mark Hounschella6792a32014-02-19 13:11:59 -05004048 ch->ch_mval |= (D_DTR(ch));
Mark Hounschell305ec872014-02-28 12:42:13 -05004049 else
Mark Hounschella6792a32014-02-19 13:11:59 -05004050 ch->ch_mval &= ~(D_DTR(ch));
Mark Hounschella6792a32014-02-19 13:11:59 -05004051
4052 break;
4053
4054 default:
Mark Hounschellcf42c342014-02-28 12:42:09 -05004055 return -EINVAL;
Mark Hounschella6792a32014-02-19 13:11:59 -05004056 }
4057
Mark Hounschellc43846a2014-03-19 11:10:51 -04004058 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4059 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004060
Daeseok Younab6cdcb2014-07-11 19:22:39 +09004061 dgap_param(ch, bd, un->un_type);
Mark Hounschella6792a32014-02-19 13:11:59 -05004062
Mark Hounschellc43846a2014-03-19 11:10:51 -04004063 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4064 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004065
Mark Hounschellcf42c342014-02-28 12:42:09 -05004066 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004067}
4068
Mark Hounschella6792a32014-02-19 13:11:59 -05004069/*
4070 * dgap_tty_digigeta()
4071 *
4072 * Ioctl to get the information for ditty.
4073 *
4074 *
4075 *
4076 */
Piotr Witoslawski70c0ed92014-09-04 08:18:53 +02004077static int dgap_tty_digigeta(struct channel_t *ch,
4078 struct digi_t __user *retinfo)
Mark Hounschella6792a32014-02-19 13:11:59 -05004079{
Mark Hounschella6792a32014-02-19 13:11:59 -05004080 struct digi_t tmp;
4081 ulong lock_flags;
4082
4083 if (!retinfo)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004084 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004085
Mark Hounschella6792a32014-02-19 13:11:59 -05004086 memset(&tmp, 0, sizeof(tmp));
4087
Mark Hounschellc43846a2014-03-19 11:10:51 -04004088 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004089 memcpy(&tmp, &ch->ch_digi, sizeof(tmp));
Mark Hounschellc43846a2014-03-19 11:10:51 -04004090 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004091
4092 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
Mark Hounschellcf42c342014-02-28 12:42:09 -05004093 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004094
Mark Hounschellcf42c342014-02-28 12:42:09 -05004095 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004096}
4097
Mark Hounschella6792a32014-02-19 13:11:59 -05004098/*
4099 * dgap_tty_digiseta()
4100 *
4101 * Ioctl to set the information for ditty.
4102 *
4103 *
4104 *
4105 */
Daeseok Younffc11c12014-07-11 19:22:58 +09004106static int dgap_tty_digiseta(struct channel_t *ch, struct board_t *bd,
4107 struct un_t *un, struct digi_t __user *new_info)
Mark Hounschella6792a32014-02-19 13:11:59 -05004108{
Mark Hounschella6792a32014-02-19 13:11:59 -05004109 struct digi_t new_digi;
Mark Hounschell174efc12014-05-23 12:54:04 -04004110 ulong lock_flags = 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004111 unsigned long lock_flags2;
4112
Mark Hounschell31960c12014-02-28 12:42:08 -05004113 if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t)))
4114 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004115
Mark Hounschellc43846a2014-03-19 11:10:51 -04004116 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4117 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004118
4119 memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t));
4120
4121 if (ch->ch_digi.digi_maxcps < 1)
4122 ch->ch_digi.digi_maxcps = 1;
4123
4124 if (ch->ch_digi.digi_maxcps > 10000)
4125 ch->ch_digi.digi_maxcps = 10000;
4126
4127 if (ch->ch_digi.digi_bufsize < 10)
4128 ch->ch_digi.digi_bufsize = 10;
4129
4130 if (ch->ch_digi.digi_maxchar < 1)
4131 ch->ch_digi.digi_maxchar = 1;
4132
4133 if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
4134 ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
4135
4136 if (ch->ch_digi.digi_onlen > DIGI_PLEN)
4137 ch->ch_digi.digi_onlen = DIGI_PLEN;
4138
4139 if (ch->ch_digi.digi_offlen > DIGI_PLEN)
4140 ch->ch_digi.digi_offlen = DIGI_PLEN;
4141
Daeseok Younab6cdcb2014-07-11 19:22:39 +09004142 dgap_param(ch, bd, un->un_type);
Mark Hounschella6792a32014-02-19 13:11:59 -05004143
Mark Hounschellc43846a2014-03-19 11:10:51 -04004144 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4145 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004146
Mark Hounschellcf42c342014-02-28 12:42:09 -05004147 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004148}
4149
Mark Hounschella6792a32014-02-19 13:11:59 -05004150/*
4151 * dgap_tty_digigetedelay()
4152 *
4153 * Ioctl to get the current edelay setting.
4154 *
4155 *
4156 *
4157 */
4158static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo)
4159{
4160 struct channel_t *ch;
4161 struct un_t *un;
4162 int tmp;
4163 ulong lock_flags;
4164
4165 if (!retinfo)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004166 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004167
4168 if (!tty || tty->magic != TTY_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004169 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004170
4171 un = tty->driver_data;
4172 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004173 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004174
4175 ch = un->un_ch;
4176 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004177 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004178
4179 memset(&tmp, 0, sizeof(tmp));
4180
Mark Hounschellc43846a2014-03-19 11:10:51 -04004181 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004182 tmp = readw(&(ch->ch_bs->edelay));
Mark Hounschellc43846a2014-03-19 11:10:51 -04004183 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004184
4185 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
Mark Hounschellcf42c342014-02-28 12:42:09 -05004186 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004187
Mark Hounschellcf42c342014-02-28 12:42:09 -05004188 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004189}
4190
Mark Hounschella6792a32014-02-19 13:11:59 -05004191/*
4192 * dgap_tty_digisetedelay()
4193 *
4194 * Ioctl to set the EDELAY setting
4195 *
4196 */
Daeseok Younccbe7e52014-07-11 19:23:54 +09004197static int dgap_tty_digisetedelay(struct channel_t *ch, struct board_t *bd,
4198 struct un_t *un, int __user *new_info)
Mark Hounschella6792a32014-02-19 13:11:59 -05004199{
Mark Hounschella6792a32014-02-19 13:11:59 -05004200 int new_digi;
4201 ulong lock_flags;
4202 ulong lock_flags2;
4203
Mark Hounschell31960c12014-02-28 12:42:08 -05004204 if (copy_from_user(&new_digi, new_info, sizeof(int)))
4205 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004206
Mark Hounschellc43846a2014-03-19 11:10:51 -04004207 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4208 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004209
4210 writew((u16) new_digi, &(ch->ch_bs->edelay));
4211
Daeseok Younab6cdcb2014-07-11 19:22:39 +09004212 dgap_param(ch, bd, un->un_type);
Mark Hounschella6792a32014-02-19 13:11:59 -05004213
Mark Hounschellc43846a2014-03-19 11:10:51 -04004214 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4215 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004216
Mark Hounschellcf42c342014-02-28 12:42:09 -05004217 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004218}
4219
Mark Hounschella6792a32014-02-19 13:11:59 -05004220/*
4221 * dgap_tty_digigetcustombaud()
4222 *
4223 * Ioctl to get the current custom baud rate setting.
4224 */
Daeseok Youn501bcd42014-07-11 19:24:14 +09004225static int dgap_tty_digigetcustombaud(struct channel_t *ch, struct un_t *un,
4226 int __user *retinfo)
Mark Hounschella6792a32014-02-19 13:11:59 -05004227{
Mark Hounschella6792a32014-02-19 13:11:59 -05004228 int tmp;
4229 ulong lock_flags;
4230
4231 if (!retinfo)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004232 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004233
Mark Hounschella6792a32014-02-19 13:11:59 -05004234 memset(&tmp, 0, sizeof(tmp));
4235
Mark Hounschellc43846a2014-03-19 11:10:51 -04004236 spin_lock_irqsave(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004237 tmp = dgap_get_custom_baud(ch);
Mark Hounschellc43846a2014-03-19 11:10:51 -04004238 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004239
Mark Hounschella6792a32014-02-19 13:11:59 -05004240 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
Mark Hounschellcf42c342014-02-28 12:42:09 -05004241 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004242
Mark Hounschellcf42c342014-02-28 12:42:09 -05004243 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004244}
4245
Mark Hounschella6792a32014-02-19 13:11:59 -05004246/*
4247 * dgap_tty_digisetcustombaud()
4248 *
4249 * Ioctl to set the custom baud rate setting
4250 */
Daeseok Youndb6fc2d2014-07-11 19:24:34 +09004251static int dgap_tty_digisetcustombaud(struct channel_t *ch, struct board_t *bd,
4252 struct un_t *un, int __user *new_info)
Mark Hounschella6792a32014-02-19 13:11:59 -05004253{
Mark Hounschella6792a32014-02-19 13:11:59 -05004254 uint new_rate;
4255 ulong lock_flags;
4256 ulong lock_flags2;
4257
Mark Hounschell31960c12014-02-28 12:42:08 -05004258 if (copy_from_user(&new_rate, new_info, sizeof(unsigned int)))
Mark Hounschellcf42c342014-02-28 12:42:09 -05004259 return -EFAULT;
Mark Hounschella6792a32014-02-19 13:11:59 -05004260
4261 if (bd->bd_flags & BD_FEP5PLUS) {
4262
Mark Hounschellc43846a2014-03-19 11:10:51 -04004263 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4264 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004265
4266 ch->ch_custom_speed = new_rate;
4267
Daeseok Younab6cdcb2014-07-11 19:22:39 +09004268 dgap_param(ch, bd, un->un_type);
Mark Hounschella6792a32014-02-19 13:11:59 -05004269
Mark Hounschellc43846a2014-03-19 11:10:51 -04004270 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4271 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004272 }
4273
Mark Hounschellcf42c342014-02-28 12:42:09 -05004274 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004275}
4276
Mark Hounschella6792a32014-02-19 13:11:59 -05004277/*
4278 * dgap_set_termios()
4279 */
Mark Hounschell8a2c9c42014-03-05 15:54:50 -05004280static void dgap_tty_set_termios(struct tty_struct *tty,
4281 struct ktermios *old_termios)
Mark Hounschella6792a32014-02-19 13:11:59 -05004282{
4283 struct board_t *bd;
4284 struct channel_t *ch;
4285 struct un_t *un;
4286 unsigned long lock_flags;
4287 unsigned long lock_flags2;
4288
4289 if (!tty || tty->magic != TTY_MAGIC)
4290 return;
4291
4292 un = tty->driver_data;
4293 if (!un || un->magic != DGAP_UNIT_MAGIC)
4294 return;
4295
4296 ch = un->un_ch;
4297 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
4298 return;
4299
4300 bd = ch->ch_bd;
4301 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
4302 return;
4303
Mark Hounschellc43846a2014-03-19 11:10:51 -04004304 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4305 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004306
4307 ch->ch_c_cflag = tty->termios.c_cflag;
4308 ch->ch_c_iflag = tty->termios.c_iflag;
4309 ch->ch_c_oflag = tty->termios.c_oflag;
4310 ch->ch_c_lflag = tty->termios.c_lflag;
4311 ch->ch_startc = tty->termios.c_cc[VSTART];
4312 ch->ch_stopc = tty->termios.c_cc[VSTOP];
4313
4314 dgap_carrier(ch);
Daeseok Younab6cdcb2014-07-11 19:22:39 +09004315 dgap_param(ch, bd, un->un_type);
Mark Hounschella6792a32014-02-19 13:11:59 -05004316
Mark Hounschellc43846a2014-03-19 11:10:51 -04004317 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4318 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004319}
4320
Mark Hounschella6792a32014-02-19 13:11:59 -05004321static void dgap_tty_throttle(struct tty_struct *tty)
4322{
4323 struct board_t *bd;
4324 struct channel_t *ch;
4325 struct un_t *un;
Mark Hounschell174efc12014-05-23 12:54:04 -04004326 ulong lock_flags;
4327 ulong lock_flags2;
Mark Hounschella6792a32014-02-19 13:11:59 -05004328
4329 if (!tty || tty->magic != TTY_MAGIC)
4330 return;
4331
4332 un = tty->driver_data;
4333 if (!un || un->magic != DGAP_UNIT_MAGIC)
4334 return;
4335
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004336 ch = un->un_ch;
4337 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004338 return;
Mark Hounschella6792a32014-02-19 13:11:59 -05004339
4340 bd = ch->ch_bd;
4341 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
4342 return;
4343
Mark Hounschellc43846a2014-03-19 11:10:51 -04004344 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4345 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004346
4347 ch->ch_flags |= (CH_RXBLOCK);
4348#if 1
4349 dgap_cmdw(ch, RPAUSE, 0, 0);
4350#endif
4351
Mark Hounschellc43846a2014-03-19 11:10:51 -04004352 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4353 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004354
Mark Hounschella6792a32014-02-19 13:11:59 -05004355}
4356
Mark Hounschella6792a32014-02-19 13:11:59 -05004357static void dgap_tty_unthrottle(struct tty_struct *tty)
4358{
4359 struct board_t *bd;
4360 struct channel_t *ch;
4361 struct un_t *un;
Mark Hounschell174efc12014-05-23 12:54:04 -04004362 ulong lock_flags;
4363 ulong lock_flags2;
Mark Hounschella6792a32014-02-19 13:11:59 -05004364
4365 if (!tty || tty->magic != TTY_MAGIC)
4366 return;
4367
4368 un = tty->driver_data;
4369 if (!un || un->magic != DGAP_UNIT_MAGIC)
4370 return;
4371
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004372 ch = un->un_ch;
4373 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004374 return;
Mark Hounschella6792a32014-02-19 13:11:59 -05004375
4376 bd = ch->ch_bd;
4377 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
4378 return;
4379
Mark Hounschellc43846a2014-03-19 11:10:51 -04004380 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4381 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004382
4383 ch->ch_flags &= ~(CH_RXBLOCK);
4384
4385#if 1
4386 dgap_cmdw(ch, RRESUME, 0, 0);
4387#endif
4388
Mark Hounschellc43846a2014-03-19 11:10:51 -04004389 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4390 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004391}
4392
Daeseok Youn48d43be2014-11-06 19:27:59 +09004393static struct board_t *find_board_by_major(unsigned int major)
4394{
4395 unsigned int i;
4396
4397 for (i = 0; i < MAXBOARDS; i++) {
4398 struct board_t *brd = dgap_board[i];
Anjana Sasindrand268b502014-11-21 00:27:50 +05304399
Daeseok Youn48d43be2014-11-06 19:27:59 +09004400 if (!brd)
4401 return NULL;
4402 if (major == brd->serial_driver->major ||
4403 major == brd->print_driver->major)
4404 return brd;
4405 }
4406
4407 return NULL;
4408}
4409
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09004410/************************************************************************
4411 *
4412 * TTY Entry points and helper functions
4413 *
4414 ************************************************************************/
4415
4416/*
4417 * dgap_tty_open()
4418 *
4419 */
4420static int dgap_tty_open(struct tty_struct *tty, struct file *file)
4421{
4422 struct board_t *brd;
4423 struct channel_t *ch;
4424 struct un_t *un;
4425 struct bs_t __iomem *bs;
4426 uint major;
4427 uint minor;
4428 int rc;
4429 ulong lock_flags;
4430 ulong lock_flags2;
4431 u16 head;
4432
4433 major = MAJOR(tty_devnum(tty));
4434 minor = MINOR(tty_devnum(tty));
4435
Daeseok Youn48d43be2014-11-06 19:27:59 +09004436 brd = find_board_by_major(major);
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09004437 if (!brd)
4438 return -EIO;
4439
4440 /*
4441 * If board is not yet up to a state of READY, go to
4442 * sleep waiting for it to happen or they cancel the open.
4443 */
4444 rc = wait_event_interruptible(brd->state_wait,
4445 (brd->state & BOARD_READY));
4446
4447 if (rc)
4448 return rc;
4449
4450 spin_lock_irqsave(&brd->bd_lock, lock_flags);
4451
4452 /* The wait above should guarantee this cannot happen */
4453 if (brd->state != BOARD_READY) {
4454 spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
4455 return -EIO;
4456 }
4457
4458 /* If opened device is greater than our number of ports, bail. */
4459 if (MINOR(tty_devnum(tty)) > brd->nasync) {
4460 spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
4461 return -EIO;
4462 }
4463
4464 ch = brd->channels[minor];
4465 if (!ch) {
4466 spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
4467 return -EIO;
4468 }
4469
4470 /* Grab channel lock */
4471 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
4472
4473 /* Figure out our type */
Daeseok Youn4c5dbca2014-11-06 19:27:33 +09004474 if (major == brd->serial_driver->major) {
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09004475 un = &brd->channels[minor]->ch_tun;
4476 un->un_type = DGAP_SERIAL;
Daeseok Youn4c5dbca2014-11-06 19:27:33 +09004477 } else if (major == brd->print_driver->major) {
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09004478 un = &brd->channels[minor]->ch_pun;
4479 un->un_type = DGAP_PRINT;
4480 } else {
4481 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4482 spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
4483 return -EIO;
4484 }
4485
4486 /* Store our unit into driver_data, so we always have it available. */
4487 tty->driver_data = un;
4488
4489 /*
4490 * Error if channel info pointer is NULL.
4491 */
4492 bs = ch->ch_bs;
4493 if (!bs) {
4494 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4495 spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
4496 return -EIO;
4497 }
4498
4499 /*
4500 * Initialize tty's
4501 */
4502 if (!(un->un_flags & UN_ISOPEN)) {
4503 /* Store important variables. */
4504 un->un_tty = tty;
4505
4506 /* Maybe do something here to the TTY struct as well? */
4507 }
4508
4509 /*
4510 * Initialize if neither terminal or printer is open.
4511 */
4512 if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) {
4513
4514 ch->ch_mforce = 0;
4515 ch->ch_mval = 0;
4516
4517 /*
4518 * Flush input queue.
4519 */
4520 head = readw(&(bs->rx_head));
4521 writew(head, &(bs->rx_tail));
4522
4523 ch->ch_flags = 0;
4524 ch->pscan_state = 0;
4525 ch->pscan_savechar = 0;
4526
4527 ch->ch_c_cflag = tty->termios.c_cflag;
4528 ch->ch_c_iflag = tty->termios.c_iflag;
4529 ch->ch_c_oflag = tty->termios.c_oflag;
4530 ch->ch_c_lflag = tty->termios.c_lflag;
4531 ch->ch_startc = tty->termios.c_cc[VSTART];
4532 ch->ch_stopc = tty->termios.c_cc[VSTOP];
4533
4534 /* TODO: flush our TTY struct here? */
4535 }
4536
4537 dgap_carrier(ch);
4538 /*
4539 * Run param in case we changed anything
4540 */
4541 dgap_param(ch, brd, un->un_type);
4542
4543 /*
4544 * follow protocol for opening port
4545 */
4546
4547 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4548 spin_unlock_irqrestore(&brd->bd_lock, lock_flags);
4549
4550 rc = dgap_block_til_ready(tty, file, ch);
4551
4552 if (!un->un_tty)
4553 return -ENODEV;
4554
4555 /* No going back now, increment our unit and channel counters */
4556 spin_lock_irqsave(&ch->ch_lock, lock_flags);
4557 ch->ch_open_count++;
4558 un->un_open_count++;
4559 un->un_flags |= (UN_ISOPEN);
4560 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
4561
4562 return rc;
4563}
4564
4565/*
4566 * dgap_tty_close()
4567 *
4568 */
4569static void dgap_tty_close(struct tty_struct *tty, struct file *file)
4570{
4571 struct ktermios *ts;
4572 struct board_t *bd;
4573 struct channel_t *ch;
4574 struct un_t *un;
4575 ulong lock_flags;
4576
4577 if (!tty || tty->magic != TTY_MAGIC)
4578 return;
4579
4580 un = tty->driver_data;
4581 if (!un || un->magic != DGAP_UNIT_MAGIC)
4582 return;
4583
4584 ch = un->un_ch;
4585 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
4586 return;
4587
4588 bd = ch->ch_bd;
4589 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
4590 return;
4591
4592 ts = &tty->termios;
4593
4594 spin_lock_irqsave(&ch->ch_lock, lock_flags);
4595
4596 /*
4597 * Determine if this is the last close or not - and if we agree about
4598 * which type of close it is with the Line Discipline
4599 */
4600 if ((tty->count == 1) && (un->un_open_count != 1)) {
4601 /*
4602 * Uh, oh. tty->count is 1, which means that the tty
4603 * structure will be freed. un_open_count should always
4604 * be one in these conditions. If it's greater than
4605 * one, we've got real problems, since it means the
4606 * serial port won't be shutdown.
4607 */
4608 un->un_open_count = 1;
4609 }
4610
4611 if (--un->un_open_count < 0)
4612 un->un_open_count = 0;
4613
4614 ch->ch_open_count--;
4615
4616 if (ch->ch_open_count && un->un_open_count) {
4617 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
4618 return;
4619 }
4620
4621 /* OK, its the last close on the unit */
4622
4623 un->un_flags |= UN_CLOSING;
4624
4625 tty->closing = 1;
4626
4627 /*
4628 * Only officially close channel if count is 0 and
4629 * DIGI_PRINTER bit is not set.
4630 */
4631 if ((ch->ch_open_count == 0) &&
4632 !(ch->ch_digi.digi_flags & DIGI_PRINTER)) {
4633
4634 ch->ch_flags &= ~(CH_RXBLOCK);
4635
4636 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
4637
4638 /* wait for output to drain */
4639 /* This will also return if we take an interrupt */
4640
4641 dgap_wait_for_drain(tty);
4642
4643 dgap_tty_flush_buffer(tty);
4644 tty_ldisc_flush(tty);
4645
4646 spin_lock_irqsave(&ch->ch_lock, lock_flags);
4647
4648 tty->closing = 0;
4649
4650 /*
4651 * If we have HUPCL set, lower DTR and RTS
4652 */
4653 if (ch->ch_c_cflag & HUPCL) {
4654 ch->ch_mostat &= ~(D_RTS(ch)|D_DTR(ch));
4655 dgap_cmdb(ch, SMODEM, 0, D_DTR(ch)|D_RTS(ch), 0);
4656
4657 /*
4658 * Go to sleep to ensure RTS/DTR
4659 * have been dropped for modems to see it.
4660 */
4661 spin_unlock_irqrestore(&ch->ch_lock,
4662 lock_flags);
4663
4664 /* .25 second delay for dropping RTS/DTR */
4665 schedule_timeout_interruptible(msecs_to_jiffies(250));
4666
4667 spin_lock_irqsave(&ch->ch_lock, lock_flags);
4668 }
4669
4670 ch->pscan_state = 0;
4671 ch->pscan_savechar = 0;
4672 ch->ch_baud_info = 0;
4673
4674 }
4675
4676 /*
4677 * turn off print device when closing print device.
4678 */
4679 if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
4680 dgap_wmove(ch, ch->ch_digi.digi_offstr,
4681 (int) ch->ch_digi.digi_offlen);
4682 ch->ch_flags &= ~CH_PRON;
4683 }
4684
4685 un->un_tty = NULL;
4686 un->un_flags &= ~(UN_ISOPEN | UN_CLOSING);
4687 tty->driver_data = NULL;
4688
4689 wake_up_interruptible(&ch->ch_flags_wait);
4690 wake_up_interruptible(&un->un_flags_wait);
4691
4692 spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
4693}
4694
Mark Hounschella6792a32014-02-19 13:11:59 -05004695static void dgap_tty_start(struct tty_struct *tty)
4696{
4697 struct board_t *bd;
4698 struct channel_t *ch;
4699 struct un_t *un;
Mark Hounschell174efc12014-05-23 12:54:04 -04004700 ulong lock_flags;
4701 ulong lock_flags2;
Mark Hounschella6792a32014-02-19 13:11:59 -05004702
4703 if (!tty || tty->magic != TTY_MAGIC)
4704 return;
4705
4706 un = tty->driver_data;
4707 if (!un || un->magic != DGAP_UNIT_MAGIC)
4708 return;
4709
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004710 ch = un->un_ch;
4711 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004712 return;
Mark Hounschella6792a32014-02-19 13:11:59 -05004713
4714 bd = ch->ch_bd;
4715 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
4716 return;
4717
Mark Hounschellc43846a2014-03-19 11:10:51 -04004718 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4719 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004720
4721 dgap_cmdw(ch, RESUMETX, 0, 0);
4722
Mark Hounschellc43846a2014-03-19 11:10:51 -04004723 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4724 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004725}
4726
Mark Hounschella6792a32014-02-19 13:11:59 -05004727static void dgap_tty_stop(struct tty_struct *tty)
4728{
4729 struct board_t *bd;
4730 struct channel_t *ch;
4731 struct un_t *un;
Mark Hounschell174efc12014-05-23 12:54:04 -04004732 ulong lock_flags;
4733 ulong lock_flags2;
Mark Hounschella6792a32014-02-19 13:11:59 -05004734
4735 if (!tty || tty->magic != TTY_MAGIC)
4736 return;
4737
4738 un = tty->driver_data;
4739 if (!un || un->magic != DGAP_UNIT_MAGIC)
4740 return;
4741
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004742 ch = un->un_ch;
4743 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004744 return;
Mark Hounschella6792a32014-02-19 13:11:59 -05004745
4746 bd = ch->ch_bd;
4747 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
4748 return;
4749
Mark Hounschellc43846a2014-03-19 11:10:51 -04004750 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4751 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004752
4753 dgap_cmdw(ch, PAUSETX, 0, 0);
4754
Mark Hounschellc43846a2014-03-19 11:10:51 -04004755 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4756 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004757}
4758
Mark Hounschella6792a32014-02-19 13:11:59 -05004759/*
4760 * dgap_tty_flush_chars()
4761 *
4762 * Flush the cook buffer
4763 *
4764 * Note to self, and any other poor souls who venture here:
4765 *
4766 * flush in this case DOES NOT mean dispose of the data.
4767 * instead, it means "stop buffering and send it if you
4768 * haven't already." Just guess how I figured that out... SRW 2-Jun-98
4769 *
4770 * It is also always called in interrupt context - JAR 8-Sept-99
4771 */
4772static void dgap_tty_flush_chars(struct tty_struct *tty)
4773{
4774 struct board_t *bd;
4775 struct channel_t *ch;
4776 struct un_t *un;
Mark Hounschell174efc12014-05-23 12:54:04 -04004777 ulong lock_flags;
4778 ulong lock_flags2;
Mark Hounschella6792a32014-02-19 13:11:59 -05004779
4780 if (!tty || tty->magic != TTY_MAGIC)
4781 return;
4782
4783 un = tty->driver_data;
4784 if (!un || un->magic != DGAP_UNIT_MAGIC)
4785 return;
4786
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004787 ch = un->un_ch;
4788 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004789 return;
Mark Hounschella6792a32014-02-19 13:11:59 -05004790
4791 bd = ch->ch_bd;
4792 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
4793 return;
4794
Mark Hounschellc43846a2014-03-19 11:10:51 -04004795 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4796 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004797
4798 /* TODO: Do something here */
4799
Mark Hounschellc43846a2014-03-19 11:10:51 -04004800 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4801 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004802}
4803
Mark Hounschella6792a32014-02-19 13:11:59 -05004804/*****************************************************************************
4805 *
4806 * The IOCTL function and all of its helpers
4807 *
4808 *****************************************************************************/
4809
4810/*
4811 * dgap_tty_ioctl()
4812 *
4813 * The usual assortment of ioctl's
4814 */
4815static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
4816 unsigned long arg)
4817{
4818 struct board_t *bd;
4819 struct channel_t *ch;
4820 struct un_t *un;
4821 int rc;
Mark Hounschell174efc12014-05-23 12:54:04 -04004822 u16 head;
4823 ulong lock_flags = 0;
4824 ulong lock_flags2 = 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004825 void __user *uarg = (void __user *) arg;
4826
4827 if (!tty || tty->magic != TTY_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004828 return -ENODEV;
Mark Hounschella6792a32014-02-19 13:11:59 -05004829
4830 un = tty->driver_data;
4831 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004832 return -ENODEV;
Mark Hounschella6792a32014-02-19 13:11:59 -05004833
4834 ch = un->un_ch;
4835 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004836 return -ENODEV;
Mark Hounschella6792a32014-02-19 13:11:59 -05004837
4838 bd = ch->ch_bd;
4839 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004840 return -ENODEV;
Mark Hounschella6792a32014-02-19 13:11:59 -05004841
Mark Hounschellc43846a2014-03-19 11:10:51 -04004842 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4843 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004844
4845 if (un->un_open_count <= 0) {
Mark Hounschellc43846a2014-03-19 11:10:51 -04004846 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4847 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschellcf42c342014-02-28 12:42:09 -05004848 return -EIO;
Mark Hounschella6792a32014-02-19 13:11:59 -05004849 }
4850
4851 switch (cmd) {
4852
4853 /* Here are all the standard ioctl's that we MUST implement */
4854
4855 case TCSBRK:
4856 /*
4857 * TCSBRK is SVID version: non-zero arg --> no break
4858 * this behaviour is exploited by tcdrain().
4859 *
4860 * According to POSIX.1 spec (7.2.2.1.2) breaks should be
4861 * between 0.25 and 0.5 seconds so we'll ask for something
4862 * in the middle: 0.375 seconds.
4863 */
4864 rc = tty_check_change(tty);
Mark Hounschellc43846a2014-03-19 11:10:51 -04004865 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4866 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschell305ec872014-02-28 12:42:13 -05004867 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004868 return rc;
Mark Hounschella6792a32014-02-19 13:11:59 -05004869
4870 rc = dgap_wait_for_drain(tty);
4871
Mark Hounschell31960c12014-02-28 12:42:08 -05004872 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004873 return -EINTR;
Mark Hounschella6792a32014-02-19 13:11:59 -05004874
Mark Hounschellc43846a2014-03-19 11:10:51 -04004875 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4876 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004877
Mark Hounschell305ec872014-02-28 12:42:13 -05004878 if (((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP))
Mark Hounschella6792a32014-02-19 13:11:59 -05004879 dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
Mark Hounschella6792a32014-02-19 13:11:59 -05004880
Mark Hounschellc43846a2014-03-19 11:10:51 -04004881 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4882 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004883
Mark Hounschellcf42c342014-02-28 12:42:09 -05004884 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004885
Mark Hounschella6792a32014-02-19 13:11:59 -05004886 case TCSBRKP:
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004887 /* support for POSIX tcsendbreak()
Mark Hounschella6792a32014-02-19 13:11:59 -05004888
4889 * According to POSIX.1 spec (7.2.2.1.2) breaks should be
4890 * between 0.25 and 0.5 seconds so we'll ask for something
4891 * in the middle: 0.375 seconds.
4892 */
4893 rc = tty_check_change(tty);
Mark Hounschellc43846a2014-03-19 11:10:51 -04004894 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4895 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschell305ec872014-02-28 12:42:13 -05004896 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004897 return rc;
Mark Hounschella6792a32014-02-19 13:11:59 -05004898
4899 rc = dgap_wait_for_drain(tty);
Mark Hounschell31960c12014-02-28 12:42:08 -05004900 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004901 return -EINTR;
Mark Hounschella6792a32014-02-19 13:11:59 -05004902
Mark Hounschellc43846a2014-03-19 11:10:51 -04004903 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4904 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004905
4906 dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
4907
Mark Hounschellc43846a2014-03-19 11:10:51 -04004908 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4909 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004910
Mark Hounschellcf42c342014-02-28 12:42:09 -05004911 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004912
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004913 case TIOCSBRK:
Mark Hounschella6792a32014-02-19 13:11:59 -05004914 /*
4915 * FEP5 doesn't support turning on a break unconditionally.
4916 * The FEP5 device will stop sending a break automatically
4917 * after the specified time value that was sent when turning on
4918 * the break.
4919 */
4920 rc = tty_check_change(tty);
Mark Hounschellc43846a2014-03-19 11:10:51 -04004921 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4922 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschell305ec872014-02-28 12:42:13 -05004923 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004924 return rc;
Mark Hounschella6792a32014-02-19 13:11:59 -05004925
4926 rc = dgap_wait_for_drain(tty);
Mark Hounschell31960c12014-02-28 12:42:08 -05004927 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004928 return -EINTR;
Mark Hounschella6792a32014-02-19 13:11:59 -05004929
Mark Hounschellc43846a2014-03-19 11:10:51 -04004930 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4931 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschella6792a32014-02-19 13:11:59 -05004932
4933 dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
4934
Mark Hounschellc43846a2014-03-19 11:10:51 -04004935 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4936 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004937
Mark Hounschella6792a32014-02-19 13:11:59 -05004938 return 0;
4939
Mark Hounschell7d6069d72014-02-28 12:42:10 -05004940 case TIOCCBRK:
Mark Hounschella6792a32014-02-19 13:11:59 -05004941 /*
4942 * FEP5 doesn't support turning off a break unconditionally.
4943 * The FEP5 device will stop sending a break automatically
4944 * after the specified time value that was sent when turning on
4945 * the break.
4946 */
Mark Hounschellc43846a2014-03-19 11:10:51 -04004947 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4948 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004949 return 0;
4950
4951 case TIOCGSOFTCAR:
4952
Mark Hounschellc43846a2014-03-19 11:10:51 -04004953 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4954 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004955
Shraddha Barke6ba4df22015-07-27 23:30:52 +05304956 return put_user(C_CLOCAL(tty) ? 1 : 0,
Mark Hounschell8a2c9c42014-03-05 15:54:50 -05004957 (unsigned long __user *) arg);
Mark Hounschella6792a32014-02-19 13:11:59 -05004958
4959 case TIOCSSOFTCAR:
Mark Hounschellc43846a2014-03-19 11:10:51 -04004960 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4961 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004962
4963 rc = get_user(arg, (unsigned long __user *) arg);
4964 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05004965 return rc;
Mark Hounschella6792a32014-02-19 13:11:59 -05004966
Mark Hounschellc43846a2014-03-19 11:10:51 -04004967 spin_lock_irqsave(&bd->bd_lock, lock_flags);
4968 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschell8a2c9c42014-03-05 15:54:50 -05004969 tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) |
4970 (arg ? CLOCAL : 0));
Daeseok Younab6cdcb2014-07-11 19:22:39 +09004971 dgap_param(ch, bd, un->un_type);
Mark Hounschellc43846a2014-03-19 11:10:51 -04004972 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4973 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05004974
Mark Hounschellcf42c342014-02-28 12:42:09 -05004975 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05004976
4977 case TIOCMGET:
Mark Hounschellc43846a2014-03-19 11:10:51 -04004978 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4979 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschellcf42c342014-02-28 12:42:09 -05004980 return dgap_get_modem_info(ch, uarg);
Mark Hounschella6792a32014-02-19 13:11:59 -05004981
4982 case TIOCMBIS:
4983 case TIOCMBIC:
4984 case TIOCMSET:
Mark Hounschellc43846a2014-03-19 11:10:51 -04004985 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
4986 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Daeseok Youn4285c972014-07-11 19:23:34 +09004987 return dgap_set_modem_info(ch, bd, un, cmd, uarg);
Mark Hounschella6792a32014-02-19 13:11:59 -05004988
4989 /*
4990 * Here are any additional ioctl's that we want to implement
4991 */
4992
4993 case TCFLSH:
4994 /*
4995 * The linux tty driver doesn't have a flush
4996 * input routine for the driver, assuming all backed
4997 * up data is in the line disc. buffers. However,
4998 * we all know that's not the case. Here, we
4999 * act on the ioctl, but then lie and say we didn't
5000 * so the line discipline will process the flush
5001 * also.
5002 */
5003 rc = tty_check_change(tty);
5004 if (rc) {
Mark Hounschellc43846a2014-03-19 11:10:51 -04005005 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5006 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschellcf42c342014-02-28 12:42:09 -05005007 return rc;
Mark Hounschella6792a32014-02-19 13:11:59 -05005008 }
5009
5010 if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) {
5011 if (!(un->un_type == DGAP_PRINT)) {
5012 head = readw(&(ch->ch_bs->rx_head));
5013 writew(head, &(ch->ch_bs->rx_tail));
5014 writeb(0, &(ch->ch_bs->orun));
5015 }
5016 }
5017
Mark Hounschell70d97a62014-03-10 14:39:41 -04005018 if ((arg != TCOFLUSH) && (arg != TCIOFLUSH)) {
5019 /* pretend we didn't recognize this IOCTL */
Mark Hounschellc43846a2014-03-19 11:10:51 -04005020 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5021 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschell70d97a62014-03-10 14:39:41 -04005022
5023 return -ENOIOCTLCMD;
Mark Hounschella6792a32014-02-19 13:11:59 -05005024 }
5025
Mark Hounschell70d97a62014-03-10 14:39:41 -04005026 ch->ch_flags &= ~CH_STOP;
5027 head = readw(&(ch->ch_bs->tx_head));
5028 dgap_cmdw(ch, FLUSHTX, (u16) head, 0);
5029 dgap_cmdw(ch, RESUMETX, 0, 0);
5030 if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
5031 ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
5032 wake_up_interruptible(&ch->ch_tun.un_flags_wait);
5033 }
5034 if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
5035 ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
5036 wake_up_interruptible(&ch->ch_pun.un_flags_wait);
5037 }
5038 if (waitqueue_active(&tty->write_wait))
5039 wake_up_interruptible(&tty->write_wait);
5040
5041 /* Can't hold any locks when calling tty_wakeup! */
Mark Hounschellc43846a2014-03-19 11:10:51 -04005042 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5043 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschell70d97a62014-03-10 14:39:41 -04005044 tty_wakeup(tty);
Mark Hounschella6792a32014-02-19 13:11:59 -05005045
Mark Hounschell70d97a62014-03-10 14:39:41 -04005046 /* pretend we didn't recognize this IOCTL */
Mark Hounschellcf42c342014-02-28 12:42:09 -05005047 return -ENOIOCTLCMD;
Mark Hounschella6792a32014-02-19 13:11:59 -05005048
5049 case TCSETSF:
5050 case TCSETSW:
5051 /*
5052 * The linux tty driver doesn't have a flush
5053 * input routine for the driver, assuming all backed
5054 * up data is in the line disc. buffers. However,
5055 * we all know that's not the case. Here, we
5056 * act on the ioctl, but then lie and say we didn't
5057 * so the line discipline will process the flush
5058 * also.
5059 */
5060 if (cmd == TCSETSF) {
5061 /* flush rx */
5062 ch->ch_flags &= ~CH_STOP;
5063 head = readw(&(ch->ch_bs->rx_head));
5064 writew(head, &(ch->ch_bs->rx_tail));
5065 }
5066
5067 /* now wait for all the output to drain */
Mark Hounschellc43846a2014-03-19 11:10:51 -04005068 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5069 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05005070 rc = dgap_wait_for_drain(tty);
Mark Hounschell31960c12014-02-28 12:42:08 -05005071 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005072 return -EINTR;
Mark Hounschella6792a32014-02-19 13:11:59 -05005073
5074 /* pretend we didn't recognize this */
Mark Hounschellcf42c342014-02-28 12:42:09 -05005075 return -ENOIOCTLCMD;
Mark Hounschella6792a32014-02-19 13:11:59 -05005076
5077 case TCSETAW:
5078
Mark Hounschellc43846a2014-03-19 11:10:51 -04005079 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5080 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05005081 rc = dgap_wait_for_drain(tty);
Mark Hounschell31960c12014-02-28 12:42:08 -05005082 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005083 return -EINTR;
Mark Hounschella6792a32014-02-19 13:11:59 -05005084
5085 /* pretend we didn't recognize this */
Mark Hounschellcf42c342014-02-28 12:42:09 -05005086 return -ENOIOCTLCMD;
Mark Hounschella6792a32014-02-19 13:11:59 -05005087
5088 case TCXONC:
5089 /*
5090 * The Linux Line Discipline (LD) would do this for us if we
5091 * let it, but we have the special firmware options to do this
5092 * the "right way" regardless of hardware or software flow
5093 * control so we'll do it outselves instead of letting the LD
5094 * do it.
5095 */
5096 rc = tty_check_change(tty);
5097 if (rc) {
Mark Hounschellc43846a2014-03-19 11:10:51 -04005098 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5099 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschellcf42c342014-02-28 12:42:09 -05005100 return rc;
Mark Hounschella6792a32014-02-19 13:11:59 -05005101 }
5102
Mark Hounschella6792a32014-02-19 13:11:59 -05005103 switch (arg) {
5104
5105 case TCOON:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005106 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5107 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05005108 dgap_tty_start(tty);
Mark Hounschellcf42c342014-02-28 12:42:09 -05005109 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05005110 case TCOOFF:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005111 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5112 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05005113 dgap_tty_stop(tty);
Mark Hounschellcf42c342014-02-28 12:42:09 -05005114 return 0;
Mark Hounschella6792a32014-02-19 13:11:59 -05005115 case TCION:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005116 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5117 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05005118 /* Make the ld do it */
Mark Hounschellcf42c342014-02-28 12:42:09 -05005119 return -ENOIOCTLCMD;
Mark Hounschella6792a32014-02-19 13:11:59 -05005120 case TCIOFF:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005121 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5122 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05005123 /* Make the ld do it */
Mark Hounschellcf42c342014-02-28 12:42:09 -05005124 return -ENOIOCTLCMD;
Mark Hounschella6792a32014-02-19 13:11:59 -05005125 default:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005126 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5127 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschellcf42c342014-02-28 12:42:09 -05005128 return -EINVAL;
Mark Hounschella6792a32014-02-19 13:11:59 -05005129 }
5130
5131 case DIGI_GETA:
5132 /* get information for ditty */
Mark Hounschellc43846a2014-03-19 11:10:51 -04005133 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5134 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Daeseok Youn4285c972014-07-11 19:23:34 +09005135 return dgap_tty_digigeta(ch, uarg);
Mark Hounschella6792a32014-02-19 13:11:59 -05005136
5137 case DIGI_SETAW:
5138 case DIGI_SETAF:
5139
5140 /* set information for ditty */
5141 if (cmd == (DIGI_SETAW)) {
5142
Mark Hounschellc43846a2014-03-19 11:10:51 -04005143 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5144 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05005145 rc = dgap_wait_for_drain(tty);
Mark Hounschell31960c12014-02-28 12:42:08 -05005146 if (rc)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005147 return -EINTR;
Mark Hounschellc43846a2014-03-19 11:10:51 -04005148 spin_lock_irqsave(&bd->bd_lock, lock_flags);
5149 spin_lock_irqsave(&ch->ch_lock, lock_flags2);
Mark Hounschell305ec872014-02-28 12:42:13 -05005150 } else
Mark Hounschella6792a32014-02-19 13:11:59 -05005151 tty_ldisc_flush(tty);
Mark Hounschella6792a32014-02-19 13:11:59 -05005152 /* fall thru */
5153
5154 case DIGI_SETA:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005155 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5156 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Daeseok Younffc11c12014-07-11 19:22:58 +09005157 return dgap_tty_digiseta(ch, bd, un, uarg);
Mark Hounschella6792a32014-02-19 13:11:59 -05005158
5159 case DIGI_GEDELAY:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005160 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5161 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschellcf42c342014-02-28 12:42:09 -05005162 return dgap_tty_digigetedelay(tty, uarg);
Mark Hounschella6792a32014-02-19 13:11:59 -05005163
5164 case DIGI_SEDELAY:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005165 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5166 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Daeseok Younccbe7e52014-07-11 19:23:54 +09005167 return dgap_tty_digisetedelay(ch, bd, un, uarg);
Mark Hounschella6792a32014-02-19 13:11:59 -05005168
5169 case DIGI_GETCUSTOMBAUD:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005170 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5171 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Daeseok Youn501bcd42014-07-11 19:24:14 +09005172 return dgap_tty_digigetcustombaud(ch, un, uarg);
Mark Hounschella6792a32014-02-19 13:11:59 -05005173
5174 case DIGI_SETCUSTOMBAUD:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005175 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5176 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Daeseok Youndb6fc2d2014-07-11 19:24:34 +09005177 return dgap_tty_digisetcustombaud(ch, bd, un, uarg);
Mark Hounschella6792a32014-02-19 13:11:59 -05005178
5179 case DIGI_RESET_PORT:
5180 dgap_firmware_reset_port(ch);
Daeseok Younab6cdcb2014-07-11 19:22:39 +09005181 dgap_param(ch, bd, un->un_type);
Mark Hounschellc43846a2014-03-19 11:10:51 -04005182 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5183 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05005184 return 0;
5185
5186 default:
Mark Hounschellc43846a2014-03-19 11:10:51 -04005187 spin_unlock_irqrestore(&ch->ch_lock, lock_flags2);
5188 spin_unlock_irqrestore(&bd->bd_lock, lock_flags);
Mark Hounschella6792a32014-02-19 13:11:59 -05005189
Mark Hounschellcf42c342014-02-28 12:42:09 -05005190 return -ENOIOCTLCMD;
Mark Hounschella6792a32014-02-19 13:11:59 -05005191 }
5192}
Mark Hounschellb28ec882014-02-20 08:48:48 -05005193
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09005194static const struct tty_operations dgap_tty_ops = {
5195 .open = dgap_tty_open,
5196 .close = dgap_tty_close,
5197 .write = dgap_tty_write,
5198 .write_room = dgap_tty_write_room,
5199 .flush_buffer = dgap_tty_flush_buffer,
5200 .chars_in_buffer = dgap_tty_chars_in_buffer,
5201 .flush_chars = dgap_tty_flush_chars,
5202 .ioctl = dgap_tty_ioctl,
5203 .set_termios = dgap_tty_set_termios,
5204 .stop = dgap_tty_stop,
5205 .start = dgap_tty_start,
5206 .throttle = dgap_tty_throttle,
5207 .unthrottle = dgap_tty_unthrottle,
5208 .hangup = dgap_tty_hangup,
5209 .put_char = dgap_tty_put_char,
5210 .tiocmget = dgap_tty_tiocmget,
5211 .tiocmset = dgap_tty_tiocmset,
5212 .break_ctl = dgap_tty_send_break,
5213 .wait_until_sent = dgap_tty_wait_until_sent,
5214 .send_xchar = dgap_tty_send_xchar
5215};
5216
5217/************************************************************************
5218 *
5219 * TTY Initialization/Cleanup Functions
5220 *
5221 ************************************************************************/
5222
5223/*
5224 * dgap_tty_register()
5225 *
5226 * Init the tty subsystem for this board.
5227 */
5228static int dgap_tty_register(struct board_t *brd)
5229{
5230 int rc;
5231
Daeseok Youndc3cfcd2014-11-06 19:26:47 +09005232 brd->serial_driver = tty_alloc_driver(MAXPORTS,
5233 TTY_DRIVER_REAL_RAW |
5234 TTY_DRIVER_DYNAMIC_DEV |
5235 TTY_DRIVER_HARDWARE_BREAK);
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09005236 if (IS_ERR(brd->serial_driver))
5237 return PTR_ERR(brd->serial_driver);
5238
5239 snprintf(brd->serial_name, MAXTTYNAMELEN, "tty_dgap_%d_",
5240 brd->boardnum);
5241 brd->serial_driver->name = brd->serial_name;
5242 brd->serial_driver->name_base = 0;
5243 brd->serial_driver->major = 0;
5244 brd->serial_driver->minor_start = 0;
5245 brd->serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
5246 brd->serial_driver->subtype = SERIAL_TYPE_NORMAL;
5247 brd->serial_driver->init_termios = dgap_default_termios;
5248 brd->serial_driver->driver_name = DRVSTR;
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09005249
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09005250 /*
5251 * Entry points for driver. Called by the kernel from
5252 * tty_io.c and n_tty.c.
5253 */
5254 tty_set_operations(brd->serial_driver, &dgap_tty_ops);
5255
5256 /*
5257 * If we're doing transparent print, we have to do all of the above
5258 * again, separately so we don't get the LD confused about what major
5259 * we are when we get into the dgap_tty_open() routine.
5260 */
Daeseok Youndc3cfcd2014-11-06 19:26:47 +09005261 brd->print_driver = tty_alloc_driver(MAXPORTS,
5262 TTY_DRIVER_REAL_RAW |
5263 TTY_DRIVER_DYNAMIC_DEV |
5264 TTY_DRIVER_HARDWARE_BREAK);
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09005265 if (IS_ERR(brd->print_driver)) {
5266 rc = PTR_ERR(brd->print_driver);
5267 goto free_serial_drv;
5268 }
5269
5270 snprintf(brd->print_name, MAXTTYNAMELEN, "pr_dgap_%d_",
5271 brd->boardnum);
5272 brd->print_driver->name = brd->print_name;
5273 brd->print_driver->name_base = 0;
5274 brd->print_driver->major = 0;
5275 brd->print_driver->minor_start = 0;
5276 brd->print_driver->type = TTY_DRIVER_TYPE_SERIAL;
5277 brd->print_driver->subtype = SERIAL_TYPE_NORMAL;
5278 brd->print_driver->init_termios = dgap_default_termios;
5279 brd->print_driver->driver_name = DRVSTR;
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09005280
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09005281 /*
5282 * Entry points for driver. Called by the kernel from
5283 * tty_io.c and n_tty.c.
5284 */
5285 tty_set_operations(brd->print_driver, &dgap_tty_ops);
5286
5287 /* Register tty devices */
5288 rc = tty_register_driver(brd->serial_driver);
5289 if (rc < 0)
5290 goto free_print_drv;
5291
5292 /* Register Transparent Print devices */
5293 rc = tty_register_driver(brd->print_driver);
5294 if (rc < 0)
5295 goto unregister_serial_drv;
5296
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09005297 return 0;
5298
5299unregister_serial_drv:
5300 tty_unregister_driver(brd->serial_driver);
5301free_print_drv:
5302 put_tty_driver(brd->print_driver);
5303free_serial_drv:
5304 put_tty_driver(brd->serial_driver);
5305
5306 return rc;
5307}
5308
5309static void dgap_tty_unregister(struct board_t *brd)
5310{
5311 tty_unregister_driver(brd->print_driver);
5312 tty_unregister_driver(brd->serial_driver);
5313 put_tty_driver(brd->print_driver);
5314 put_tty_driver(brd->serial_driver);
5315}
5316
Daeseok Youn3f7fa942014-06-13 18:22:05 +09005317static int dgap_alloc_flipbuf(struct board_t *brd)
Mark Hounschellb053bb82014-02-19 13:12:00 -05005318{
Mark Hounschellb28ec882014-02-20 08:48:48 -05005319 /*
Mark Hounschellb28ec882014-02-20 08:48:48 -05005320 * allocate flip buffer for board.
Mark Hounschellb053bb82014-02-19 13:12:00 -05005321 */
Daeseok Youn8148f372014-06-03 17:01:31 +09005322 brd->flipbuf = kmalloc(MYFLIPLEN, GFP_KERNEL);
5323 if (!brd->flipbuf)
Mark Hounschellb28ec882014-02-20 08:48:48 -05005324 return -ENOMEM;
Mark Hounschellb053bb82014-02-19 13:12:00 -05005325
Daeseok Youn8148f372014-06-03 17:01:31 +09005326 brd->flipflagbuf = kmalloc(MYFLIPLEN, GFP_KERNEL);
5327 if (!brd->flipflagbuf) {
5328 kfree(brd->flipbuf);
Mark Hounschellb28ec882014-02-20 08:48:48 -05005329 return -ENOMEM;
Mark Hounschellb053bb82014-02-19 13:12:00 -05005330 }
5331
Mark Hounschellb28ec882014-02-20 08:48:48 -05005332 return 0;
Mark Hounschellb053bb82014-02-19 13:12:00 -05005333}
5334
Daeseok Youn91177d52014-06-13 18:23:15 +09005335static void dgap_free_flipbuf(struct board_t *brd)
5336{
5337 kfree(brd->flipbuf);
5338 kfree(brd->flipflagbuf);
5339}
5340
Mark Hounschell3eb14152014-03-04 09:33:46 -05005341static struct board_t *dgap_verify_board(struct device *p)
5342{
5343 struct board_t *bd;
5344
5345 if (!p)
5346 return NULL;
5347
5348 bd = dev_get_drvdata(p);
5349 if (!bd || bd->magic != DGAP_BOARD_MAGIC || bd->state != BOARD_READY)
5350 return NULL;
5351
5352 return bd;
5353}
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005354
Mark Hounschell84e88282014-03-10 15:46:54 -04005355static ssize_t dgap_ports_state_show(struct device *p,
5356 struct device_attribute *attr,
5357 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005358{
5359 struct board_t *bd;
5360 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305361 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005362
Mark Hounschell3eb14152014-03-04 09:33:46 -05005363 bd = dgap_verify_board(p);
5364 if (!bd)
5365 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005366
5367 for (i = 0; i < bd->nasync; i++) {
5368 count += snprintf(buf + count, PAGE_SIZE - count,
5369 "%d %s\n", bd->channels[i]->ch_portnum,
5370 bd->channels[i]->ch_open_count ? "Open" : "Closed");
5371 }
5372 return count;
5373}
5374static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL);
5375
Mark Hounschell84e88282014-03-10 15:46:54 -04005376static ssize_t dgap_ports_baud_show(struct device *p,
5377 struct device_attribute *attr,
5378 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005379{
5380 struct board_t *bd;
5381 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305382 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005383
Mark Hounschell3eb14152014-03-04 09:33:46 -05005384 bd = dgap_verify_board(p);
5385 if (!bd)
5386 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005387
5388 for (i = 0; i < bd->nasync; i++) {
Mark Hounschell84e88282014-03-10 15:46:54 -04005389 count += snprintf(buf + count, PAGE_SIZE - count, "%d %d\n",
5390 bd->channels[i]->ch_portnum,
5391 bd->channels[i]->ch_baud_info);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005392 }
5393 return count;
5394}
5395static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL);
5396
Mark Hounschell84e88282014-03-10 15:46:54 -04005397static ssize_t dgap_ports_msignals_show(struct device *p,
5398 struct device_attribute *attr,
5399 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005400{
5401 struct board_t *bd;
5402 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305403 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005404
Mark Hounschell3eb14152014-03-04 09:33:46 -05005405 bd = dgap_verify_board(p);
5406 if (!bd)
5407 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005408
5409 for (i = 0; i < bd->nasync; i++) {
Mark Hounschell305ec872014-02-28 12:42:13 -05005410 if (bd->channels[i]->ch_open_count)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005411 count += snprintf(buf + count, PAGE_SIZE - count,
Mark Hounschell84e88282014-03-10 15:46:54 -04005412 "%d %s %s %s %s %s %s\n",
5413 bd->channels[i]->ch_portnum,
5414 (bd->channels[i]->ch_mostat &
5415 UART_MCR_RTS) ? "RTS" : "",
5416 (bd->channels[i]->ch_mistat &
5417 UART_MSR_CTS) ? "CTS" : "",
5418 (bd->channels[i]->ch_mostat &
5419 UART_MCR_DTR) ? "DTR" : "",
5420 (bd->channels[i]->ch_mistat &
5421 UART_MSR_DSR) ? "DSR" : "",
5422 (bd->channels[i]->ch_mistat &
5423 UART_MSR_DCD) ? "DCD" : "",
5424 (bd->channels[i]->ch_mistat &
5425 UART_MSR_RI) ? "RI" : "");
Mark Hounschell305ec872014-02-28 12:42:13 -05005426 else
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005427 count += snprintf(buf + count, PAGE_SIZE - count,
5428 "%d\n", bd->channels[i]->ch_portnum);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005429 }
5430 return count;
5431}
5432static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL);
5433
Mark Hounschell84e88282014-03-10 15:46:54 -04005434static ssize_t dgap_ports_iflag_show(struct device *p,
5435 struct device_attribute *attr,
5436 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005437{
5438 struct board_t *bd;
5439 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305440 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005441
Mark Hounschell3eb14152014-03-04 09:33:46 -05005442 bd = dgap_verify_board(p);
5443 if (!bd)
5444 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005445
Mark Hounschell305ec872014-02-28 12:42:13 -05005446 for (i = 0; i < bd->nasync; i++)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005447 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
Mark Hounschell84e88282014-03-10 15:46:54 -04005448 bd->channels[i]->ch_portnum,
5449 bd->channels[i]->ch_c_iflag);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005450 return count;
5451}
5452static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL);
5453
Mark Hounschell84e88282014-03-10 15:46:54 -04005454static ssize_t dgap_ports_cflag_show(struct device *p,
5455 struct device_attribute *attr,
5456 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005457{
5458 struct board_t *bd;
5459 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305460 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005461
Mark Hounschell3eb14152014-03-04 09:33:46 -05005462 bd = dgap_verify_board(p);
5463 if (!bd)
5464 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005465
Mark Hounschell305ec872014-02-28 12:42:13 -05005466 for (i = 0; i < bd->nasync; i++)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005467 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
Mark Hounschell84e88282014-03-10 15:46:54 -04005468 bd->channels[i]->ch_portnum,
5469 bd->channels[i]->ch_c_cflag);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005470 return count;
5471}
5472static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL);
5473
Mark Hounschell84e88282014-03-10 15:46:54 -04005474static ssize_t dgap_ports_oflag_show(struct device *p,
5475 struct device_attribute *attr,
5476 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005477{
5478 struct board_t *bd;
5479 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305480 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005481
Mark Hounschell3eb14152014-03-04 09:33:46 -05005482 bd = dgap_verify_board(p);
5483 if (!bd)
5484 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005485
Mark Hounschell305ec872014-02-28 12:42:13 -05005486 for (i = 0; i < bd->nasync; i++)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005487 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
Mark Hounschell84e88282014-03-10 15:46:54 -04005488 bd->channels[i]->ch_portnum,
5489 bd->channels[i]->ch_c_oflag);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005490 return count;
5491}
5492static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL);
5493
Mark Hounschell84e88282014-03-10 15:46:54 -04005494static ssize_t dgap_ports_lflag_show(struct device *p,
5495 struct device_attribute *attr,
5496 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005497{
5498 struct board_t *bd;
5499 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305500 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005501
Mark Hounschell3eb14152014-03-04 09:33:46 -05005502 bd = dgap_verify_board(p);
5503 if (!bd)
5504 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005505
Mark Hounschell305ec872014-02-28 12:42:13 -05005506 for (i = 0; i < bd->nasync; i++)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005507 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
Mark Hounschell84e88282014-03-10 15:46:54 -04005508 bd->channels[i]->ch_portnum,
5509 bd->channels[i]->ch_c_lflag);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005510 return count;
5511}
5512static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL);
5513
Mark Hounschell84e88282014-03-10 15:46:54 -04005514static ssize_t dgap_ports_digi_flag_show(struct device *p,
5515 struct device_attribute *attr,
5516 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005517{
5518 struct board_t *bd;
5519 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305520 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005521
Mark Hounschell3eb14152014-03-04 09:33:46 -05005522 bd = dgap_verify_board(p);
5523 if (!bd)
5524 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005525
Mark Hounschell305ec872014-02-28 12:42:13 -05005526 for (i = 0; i < bd->nasync; i++)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005527 count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
Mark Hounschell84e88282014-03-10 15:46:54 -04005528 bd->channels[i]->ch_portnum,
5529 bd->channels[i]->ch_digi.digi_flags);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005530 return count;
5531}
5532static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL);
5533
Mark Hounschell84e88282014-03-10 15:46:54 -04005534static ssize_t dgap_ports_rxcount_show(struct device *p,
5535 struct device_attribute *attr,
5536 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005537{
5538 struct board_t *bd;
5539 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305540 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005541
Mark Hounschell3eb14152014-03-04 09:33:46 -05005542 bd = dgap_verify_board(p);
5543 if (!bd)
5544 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005545
Mark Hounschell305ec872014-02-28 12:42:13 -05005546 for (i = 0; i < bd->nasync; i++)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005547 count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
Mark Hounschell84e88282014-03-10 15:46:54 -04005548 bd->channels[i]->ch_portnum,
5549 bd->channels[i]->ch_rxcount);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005550 return count;
5551}
5552static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL);
5553
Mark Hounschell84e88282014-03-10 15:46:54 -04005554static ssize_t dgap_ports_txcount_show(struct device *p,
5555 struct device_attribute *attr,
5556 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005557{
5558 struct board_t *bd;
5559 int count = 0;
Tapasweni Pathakac2f46c2014-10-26 20:38:32 +05305560 unsigned int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005561
Mark Hounschell3eb14152014-03-04 09:33:46 -05005562 bd = dgap_verify_board(p);
5563 if (!bd)
5564 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005565
Mark Hounschell305ec872014-02-28 12:42:13 -05005566 for (i = 0; i < bd->nasync; i++)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005567 count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
Mark Hounschell84e88282014-03-10 15:46:54 -04005568 bd->channels[i]->ch_portnum,
5569 bd->channels[i]->ch_txcount);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005570 return count;
5571}
5572static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL);
5573
Mark Hounschell84e88282014-03-10 15:46:54 -04005574static ssize_t dgap_tty_state_show(struct device *d,
5575 struct device_attribute *attr,
5576 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005577{
5578 struct board_t *bd;
5579 struct channel_t *ch;
5580 struct un_t *un;
5581
5582 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005583 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005584 un = dev_get_drvdata(d);
5585 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005586 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005587 ch = un->un_ch;
5588 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005589 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005590 bd = ch->ch_bd;
5591 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005592 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005593 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005594 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005595
Mark Hounschell84e88282014-03-10 15:46:54 -04005596 return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ?
5597 "Open" : "Closed");
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005598}
5599static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL);
5600
Mark Hounschell84e88282014-03-10 15:46:54 -04005601static ssize_t dgap_tty_baud_show(struct device *d,
5602 struct device_attribute *attr,
5603 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005604{
5605 struct board_t *bd;
5606 struct channel_t *ch;
5607 struct un_t *un;
5608
5609 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005610 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005611 un = dev_get_drvdata(d);
5612 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005613 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005614 ch = un->un_ch;
5615 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005616 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005617 bd = ch->ch_bd;
5618 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005619 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005620 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005621 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005622
5623 return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info);
5624}
5625static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL);
5626
Mark Hounschell84e88282014-03-10 15:46:54 -04005627static ssize_t dgap_tty_msignals_show(struct device *d,
5628 struct device_attribute *attr,
5629 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005630{
5631 struct board_t *bd;
5632 struct channel_t *ch;
5633 struct un_t *un;
5634
5635 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005636 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005637 un = dev_get_drvdata(d);
5638 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005639 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005640 ch = un->un_ch;
5641 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005642 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005643 bd = ch->ch_bd;
5644 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005645 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005646 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005647 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005648
5649 if (ch->ch_open_count) {
5650 return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
5651 (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
5652 (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
5653 (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
5654 (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
5655 (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
5656 (ch->ch_mistat & UART_MSR_RI) ? "RI" : "");
5657 }
5658 return 0;
5659}
5660static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL);
5661
Mark Hounschell84e88282014-03-10 15:46:54 -04005662static ssize_t dgap_tty_iflag_show(struct device *d,
5663 struct device_attribute *attr,
5664 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005665{
5666 struct board_t *bd;
5667 struct channel_t *ch;
5668 struct un_t *un;
5669
5670 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005671 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005672 un = dev_get_drvdata(d);
5673 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005674 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005675 ch = un->un_ch;
5676 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005677 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005678 bd = ch->ch_bd;
5679 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005680 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005681 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005682 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005683
5684 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
5685}
5686static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL);
5687
Mark Hounschell84e88282014-03-10 15:46:54 -04005688static ssize_t dgap_tty_cflag_show(struct device *d,
5689 struct device_attribute *attr,
5690 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005691{
5692 struct board_t *bd;
5693 struct channel_t *ch;
5694 struct un_t *un;
5695
5696 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005697 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005698 un = dev_get_drvdata(d);
5699 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005700 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005701 ch = un->un_ch;
5702 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005703 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005704 bd = ch->ch_bd;
5705 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005706 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005707 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005708 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005709
5710 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
5711}
5712static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL);
5713
Mark Hounschell84e88282014-03-10 15:46:54 -04005714static ssize_t dgap_tty_oflag_show(struct device *d,
5715 struct device_attribute *attr,
5716 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005717{
5718 struct board_t *bd;
5719 struct channel_t *ch;
5720 struct un_t *un;
5721
5722 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005723 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005724 un = dev_get_drvdata(d);
5725 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005726 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005727 ch = un->un_ch;
5728 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005729 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005730 bd = ch->ch_bd;
5731 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005732 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005733 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005734 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005735
5736 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
5737}
5738static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL);
5739
Mark Hounschell84e88282014-03-10 15:46:54 -04005740static ssize_t dgap_tty_lflag_show(struct device *d,
5741 struct device_attribute *attr,
5742 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005743{
5744 struct board_t *bd;
5745 struct channel_t *ch;
5746 struct un_t *un;
5747
5748 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005749 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005750 un = dev_get_drvdata(d);
5751 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005752 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005753 ch = un->un_ch;
5754 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005755 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005756 bd = ch->ch_bd;
5757 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005758 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005759 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005760 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005761
5762 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
5763}
5764static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL);
5765
Mark Hounschell84e88282014-03-10 15:46:54 -04005766static ssize_t dgap_tty_digi_flag_show(struct device *d,
5767 struct device_attribute *attr,
5768 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005769{
5770 struct board_t *bd;
5771 struct channel_t *ch;
5772 struct un_t *un;
5773
5774 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005775 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005776 un = dev_get_drvdata(d);
5777 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005778 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005779 ch = un->un_ch;
5780 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005781 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005782 bd = ch->ch_bd;
5783 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005784 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005785 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005786 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005787
5788 return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
5789}
5790static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL);
5791
Mark Hounschell84e88282014-03-10 15:46:54 -04005792static ssize_t dgap_tty_rxcount_show(struct device *d,
5793 struct device_attribute *attr,
5794 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005795{
5796 struct board_t *bd;
5797 struct channel_t *ch;
5798 struct un_t *un;
5799
5800 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005801 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005802 un = dev_get_drvdata(d);
5803 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005804 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005805 ch = un->un_ch;
5806 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005807 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005808 bd = ch->ch_bd;
5809 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005810 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005811 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005812 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005813
5814 return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
5815}
5816static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL);
5817
Mark Hounschell84e88282014-03-10 15:46:54 -04005818static ssize_t dgap_tty_txcount_show(struct device *d,
5819 struct device_attribute *attr,
5820 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005821{
5822 struct board_t *bd;
5823 struct channel_t *ch;
5824 struct un_t *un;
5825
5826 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005827 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005828 un = dev_get_drvdata(d);
5829 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005830 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005831 ch = un->un_ch;
5832 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005833 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005834 bd = ch->ch_bd;
5835 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005836 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005837 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005838 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005839
5840 return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
5841}
5842static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL);
5843
Mark Hounschell84e88282014-03-10 15:46:54 -04005844static ssize_t dgap_tty_name_show(struct device *d,
5845 struct device_attribute *attr,
5846 char *buf)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005847{
5848 struct board_t *bd;
5849 struct channel_t *ch;
5850 struct un_t *un;
Mark Hounschell174efc12014-05-23 12:54:04 -04005851 int cn;
5852 int bn;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04005853 struct cnode *cptr;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005854 int found = FALSE;
5855 int ncount = 0;
5856 int starto = 0;
Mark Hounschell7dfa3832014-05-23 10:14:02 -04005857 int i;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005858
5859 if (!d)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005860 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005861 un = dev_get_drvdata(d);
5862 if (!un || un->magic != DGAP_UNIT_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005863 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005864 ch = un->un_ch;
5865 if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005866 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005867 bd = ch->ch_bd;
5868 if (!bd || bd->magic != DGAP_BOARD_MAGIC)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005869 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005870 if (bd->state != BOARD_READY)
Mark Hounschellcf42c342014-02-28 12:42:09 -05005871 return 0;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005872
Mark Hounschell7d6069d72014-02-28 12:42:10 -05005873 bn = bd->boardnum;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005874 cn = ch->ch_portnum;
5875
5876 for (cptr = bd->bd_config; cptr; cptr = cptr->next) {
5877
5878 if ((cptr->type == BNODE) &&
Mark Hounschell84e88282014-03-10 15:46:54 -04005879 ((cptr->u.board.type == APORT2_920P) ||
5880 (cptr->u.board.type == APORT4_920P) ||
5881 (cptr->u.board.type == APORT8_920P) ||
5882 (cptr->u.board.type == PAPORT4) ||
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005883 (cptr->u.board.type == PAPORT8))) {
5884
Mark Hounschell84e88282014-03-10 15:46:54 -04005885 found = TRUE;
5886 if (cptr->u.board.v_start)
5887 starto = cptr->u.board.start;
5888 else
5889 starto = 1;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005890 }
5891
5892 if (cptr->type == TNODE && found == TRUE) {
5893 char *ptr1;
Daeseok Youn96045db2014-07-02 16:07:16 +09005894
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005895 if (strstr(cptr->u.ttyname, "tty")) {
5896 ptr1 = cptr->u.ttyname;
5897 ptr1 += 3;
Mark Hounschell305ec872014-02-28 12:42:13 -05005898 } else
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005899 ptr1 = cptr->u.ttyname;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005900
Mark Hounschellbbfbe832014-03-19 11:10:52 -04005901 for (i = 0; i < dgap_config_get_num_prts(bd); i++) {
5902 if (cn != i)
5903 continue;
5904
5905 return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
5906 (un->un_type == DGAP_PRINT) ?
5907 "pr" : "tty",
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005908 ptr1, i + starto);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005909 }
5910 }
5911
5912 if (cptr->type == CNODE) {
5913
5914 for (i = 0; i < cptr->u.conc.nport; i++) {
Mark Hounschellbbfbe832014-03-19 11:10:52 -04005915 if (cn != (i + ncount))
5916 continue;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005917
Mark Hounschell67d5dc82014-03-19 15:46:57 -04005918 return snprintf(buf, PAGE_SIZE, "%s%s%02ld\n",
Mark Hounschellbbfbe832014-03-19 11:10:52 -04005919 (un->un_type == DGAP_PRINT) ?
5920 "pr" : "tty",
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005921 cptr->u.conc.id,
Mark Hounschellbbfbe832014-03-19 11:10:52 -04005922 i + (cptr->u.conc.v_start ?
5923 cptr->u.conc.start : 1));
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005924 }
5925
5926 ncount += cptr->u.conc.nport;
5927 }
5928
5929 if (cptr->type == MNODE) {
5930
5931 for (i = 0; i < cptr->u.module.nport; i++) {
Mark Hounschellbbfbe832014-03-19 11:10:52 -04005932 if (cn != (i + ncount))
5933 continue;
5934
Mark Hounschell67d5dc82014-03-19 15:46:57 -04005935 return snprintf(buf, PAGE_SIZE, "%s%s%02ld\n",
Mark Hounschellbbfbe832014-03-19 11:10:52 -04005936 (un->un_type == DGAP_PRINT) ?
5937 "pr" : "tty",
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005938 cptr->u.module.id,
Mark Hounschellbbfbe832014-03-19 11:10:52 -04005939 i + (cptr->u.module.v_start ?
5940 cptr->u.module.start : 1));
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005941 }
5942
5943 ncount += cptr->u.module.nport;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005944 }
5945 }
5946
5947 return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n",
5948 (un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn);
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005949}
5950static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL);
5951
Mark Hounschell7568f7d2014-02-19 13:12:01 -05005952static struct attribute *dgap_sysfs_tty_entries[] = {
5953 &dev_attr_state.attr,
5954 &dev_attr_baud.attr,
5955 &dev_attr_msignals.attr,
5956 &dev_attr_iflag.attr,
5957 &dev_attr_cflag.attr,
5958 &dev_attr_oflag.attr,
5959 &dev_attr_lflag.attr,
5960 &dev_attr_digi_flag.attr,
5961 &dev_attr_rxcount.attr,
5962 &dev_attr_txcount.attr,
5963 &dev_attr_custom_name.attr,
5964 NULL
5965};
5966
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09005967
5968/* this function creates the sys files that will export each signal status
5969 * to sysfs each value will be put in a separate filename
5970 */
5971static void dgap_create_ports_sysfiles(struct board_t *bd)
5972{
5973 dev_set_drvdata(&bd->pdev->dev, bd);
5974 device_create_file(&(bd->pdev->dev), &dev_attr_ports_state);
5975 device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud);
5976 device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
5977 device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
5978 device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
5979 device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
5980 device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
5981 device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
5982 device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
5983 device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
5984}
5985
5986/* removes all the sys files created for that port */
5987static void dgap_remove_ports_sysfiles(struct board_t *bd)
5988{
5989 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state);
5990 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud);
5991 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
5992 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
5993 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
5994 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
5995 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
5996 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
5997 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
5998 device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
5999}
6000
6001/*
6002 * Copies the BIOS code from the user to the board,
6003 * and starts the BIOS running.
6004 */
6005static void dgap_do_bios_load(struct board_t *brd, const u8 *ubios, int len)
6006{
6007 u8 __iomem *addr;
6008 uint offset;
6009 unsigned int i;
6010
6011 if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
6012 return;
6013
6014 addr = brd->re_map_membase;
6015
6016 /*
6017 * clear POST area
6018 */
6019 for (i = 0; i < 16; i++)
6020 writeb(0, addr + POSTAREA + i);
6021
6022 /*
6023 * Download bios
6024 */
6025 offset = 0x1000;
6026 memcpy_toio(addr + offset, ubios, len);
6027
6028 writel(0x0bf00401, addr);
6029 writel(0, (addr + 4));
6030
6031 /* Clear the reset, and change states. */
6032 writeb(FEPCLR, brd->re_map_port);
6033}
6034
6035/*
6036 * Checks to see if the BIOS completed running on the card.
6037 */
6038static int dgap_test_bios(struct board_t *brd)
6039{
6040 u8 __iomem *addr;
6041 u16 word;
6042 u16 err1;
6043 u16 err2;
6044
6045 if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
6046 return -EINVAL;
6047
6048 addr = brd->re_map_membase;
6049 word = readw(addr + POSTAREA);
6050
6051 /*
6052 * It can take 5-6 seconds for a board to
6053 * pass the bios self test and post results.
6054 * Give it 10 seconds.
6055 */
6056 brd->wait_for_bios = 0;
6057 while (brd->wait_for_bios < 1000) {
6058 /* Check to see if BIOS thinks board is good. (GD). */
6059 if (word == *(u16 *) "GD")
6060 return 0;
6061 msleep_interruptible(10);
6062 brd->wait_for_bios++;
6063 word = readw(addr + POSTAREA);
6064 }
6065
6066 /* Gave up on board after too long of time taken */
6067 err1 = readw(addr + SEQUENCE);
6068 err2 = readw(addr + ERROR);
6069 dev_warn(&brd->pdev->dev, "%s failed diagnostics. Error #(%x,%x).\n",
6070 brd->name, err1, err2);
6071 brd->state = BOARD_FAILED;
6072 brd->dpastatus = BD_NOBIOS;
6073
6074 return -EIO;
6075}
6076
6077/*
6078 * Copies the FEP code from the user to the board,
6079 * and starts the FEP running.
6080 */
6081static void dgap_do_fep_load(struct board_t *brd, const u8 *ufep, int len)
6082{
6083 u8 __iomem *addr;
6084 uint offset;
6085
6086 if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
6087 return;
6088
6089 addr = brd->re_map_membase;
6090
6091 /*
6092 * Download FEP
6093 */
6094 offset = 0x1000;
6095 memcpy_toio(addr + offset, ufep, len);
6096
6097 /*
6098 * If board is a concentrator product, we need to give
6099 * it its config string describing how the concentrators look.
6100 */
6101 if ((brd->type == PCX) || (brd->type == PEPC)) {
6102 u8 string[100];
6103 u8 __iomem *config;
6104 u8 *xconfig;
6105 unsigned int i = 0;
6106
6107 xconfig = dgap_create_config_string(brd, string);
6108
6109 /* Write string to board memory */
6110 config = addr + CONFIG;
6111 for (; i < CONFIGSIZE; i++, config++, xconfig++) {
6112 writeb(*xconfig, config);
6113 if ((*xconfig & 0xff) == 0xff)
6114 break;
6115 }
6116 }
6117
6118 writel(0xbfc01004, (addr + 0xc34));
6119 writel(0x3, (addr + 0xc30));
6120
6121}
6122
6123/*
6124 * Waits for the FEP to report thats its ready for us to use.
6125 */
6126static int dgap_test_fep(struct board_t *brd)
6127{
6128 u8 __iomem *addr;
6129 u16 word;
6130 u16 err1;
6131 u16 err2;
6132
6133 if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
6134 return -EINVAL;
6135
6136 addr = brd->re_map_membase;
6137 word = readw(addr + FEPSTAT);
6138
6139 /*
6140 * It can take 2-3 seconds for the FEP to
6141 * be up and running. Give it 5 secs.
6142 */
6143 brd->wait_for_fep = 0;
6144 while (brd->wait_for_fep < 500) {
6145 /* Check to see if FEP is up and running now. */
6146 if (word == *(u16 *) "OS") {
6147 /*
6148 * Check to see if the board can support FEP5+ commands.
6149 */
6150 word = readw(addr + FEP5_PLUS);
6151 if (word == *(u16 *) "5A")
6152 brd->bd_flags |= BD_FEP5PLUS;
6153
6154 return 0;
6155 }
6156 msleep_interruptible(10);
6157 brd->wait_for_fep++;
6158 word = readw(addr + FEPSTAT);
6159 }
6160
6161 /* Gave up on board after too long of time taken */
6162 err1 = readw(addr + SEQUENCE);
6163 err2 = readw(addr + ERROR);
6164 dev_warn(&brd->pdev->dev,
6165 "FEPOS for %s not functioning. Error #(%x,%x).\n",
6166 brd->name, err1, err2);
6167 brd->state = BOARD_FAILED;
6168 brd->dpastatus = BD_NOFEP;
6169
6170 return -EIO;
6171}
6172
6173/*
6174 * Physically forces the FEP5 card to reset itself.
6175 */
6176static void dgap_do_reset_board(struct board_t *brd)
6177{
6178 u8 check;
6179 u32 check1;
6180 u32 check2;
6181 unsigned int i;
6182
6183 if (!brd || (brd->magic != DGAP_BOARD_MAGIC) ||
6184 !brd->re_map_membase || !brd->re_map_port)
6185 return;
6186
6187 /* FEPRST does not vary among supported boards */
6188 writeb(FEPRST, brd->re_map_port);
6189
6190 for (i = 0; i <= 1000; i++) {
6191 check = readb(brd->re_map_port) & 0xe;
6192 if (check == FEPRST)
6193 break;
6194 udelay(10);
6195
6196 }
6197 if (i > 1000) {
6198 dev_warn(&brd->pdev->dev,
6199 "dgap: Board not resetting... Failing board.\n");
6200 brd->state = BOARD_FAILED;
6201 brd->dpastatus = BD_NOFEP;
6202 return;
6203 }
6204
6205 /*
6206 * Make sure there really is memory out there.
6207 */
6208 writel(0xa55a3cc3, (brd->re_map_membase + LOWMEM));
6209 writel(0x5aa5c33c, (brd->re_map_membase + HIGHMEM));
6210 check1 = readl(brd->re_map_membase + LOWMEM);
6211 check2 = readl(brd->re_map_membase + HIGHMEM);
6212
6213 if ((check1 != 0xa55a3cc3) || (check2 != 0x5aa5c33c)) {
6214 dev_warn(&brd->pdev->dev,
6215 "No memory at %p for board.\n",
6216 brd->re_map_membase);
6217 brd->state = BOARD_FAILED;
6218 brd->dpastatus = BD_NOFEP;
6219 return;
6220 }
6221}
6222
6223#ifdef DIGI_CONCENTRATORS_SUPPORTED
6224/*
6225 * Sends a concentrator image into the FEP5 board.
6226 */
6227static void dgap_do_conc_load(struct board_t *brd, u8 *uaddr, int len)
6228{
6229 char __iomem *vaddr;
6230 u16 offset;
6231 struct downld_t *to_dp;
6232
6233 if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
6234 return;
6235
6236 vaddr = brd->re_map_membase;
6237
6238 offset = readw((u16 *) (vaddr + DOWNREQ));
6239 to_dp = (struct downld_t *) (vaddr + (int) offset);
6240 memcpy_toio(to_dp, uaddr, len);
6241
6242 /* Tell card we have data for it */
6243 writew(0, vaddr + (DOWNREQ));
6244
6245 brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS;
6246}
6247#endif
6248
6249#define EXPANSION_ROM_SIZE (64 * 1024)
6250#define FEP5_ROM_MAGIC (0xFEFFFFFF)
6251
6252static void dgap_get_vpd(struct board_t *brd)
6253{
6254 u32 magic;
6255 u32 base_offset;
6256 u16 rom_offset;
6257 u16 vpd_offset;
6258 u16 image_length;
6259 u16 i;
6260 u8 byte1;
6261 u8 byte2;
6262
6263 /*
6264 * Poke the magic number at the PCI Rom Address location.
6265 * If VPD is supported, the value read from that address
6266 * will be non-zero.
6267 */
6268 magic = FEP5_ROM_MAGIC;
6269 pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
6270 pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
6271
6272 /* VPD not supported, bail */
6273 if (!magic)
6274 return;
6275
6276 /*
6277 * To get to the OTPROM memory, we have to send the boards base
6278 * address or'ed with 1 into the PCI Rom Address location.
6279 */
6280 magic = brd->membase | 0x01;
6281 pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
6282 pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
6283
6284 byte1 = readb(brd->re_map_membase);
6285 byte2 = readb(brd->re_map_membase + 1);
6286
6287 /*
6288 * If the board correctly swapped to the OTPROM memory,
6289 * the first 2 bytes (header) should be 0x55, 0xAA
6290 */
6291 if (byte1 == 0x55 && byte2 == 0xAA) {
6292
6293 base_offset = 0;
6294
6295 /*
6296 * We have to run through all the OTPROM memory looking
6297 * for the VPD offset.
6298 */
6299 while (base_offset <= EXPANSION_ROM_SIZE) {
6300
6301 /*
6302 * Lots of magic numbers here.
6303 *
6304 * The VPD offset is located inside the ROM Data
6305 * Structure.
6306 *
6307 * We also have to remember the length of each
6308 * ROM Data Structure, so we can "hop" to the next
6309 * entry if the VPD isn't in the current
6310 * ROM Data Structure.
6311 */
6312 rom_offset = readw(brd->re_map_membase +
6313 base_offset + 0x18);
6314 image_length = readw(brd->re_map_membase +
6315 rom_offset + 0x10) * 512;
6316 vpd_offset = readw(brd->re_map_membase +
6317 rom_offset + 0x08);
6318
6319 /* Found the VPD entry */
6320 if (vpd_offset)
6321 break;
6322
6323 /* We didn't find a VPD entry, go to next ROM entry. */
6324 base_offset += image_length;
6325
6326 byte1 = readb(brd->re_map_membase + base_offset);
6327 byte2 = readb(brd->re_map_membase + base_offset + 1);
6328
6329 /*
6330 * If the new ROM offset doesn't have 0x55, 0xAA
6331 * as its header, we have run out of ROM.
6332 */
6333 if (byte1 != 0x55 || byte2 != 0xAA)
6334 break;
6335 }
6336
6337 /*
6338 * If we have a VPD offset, then mark the board
6339 * as having a valid VPD, and copy VPDSIZE (512) bytes of
6340 * that VPD to the buffer we have in our board structure.
6341 */
6342 if (vpd_offset) {
6343 brd->bd_flags |= BD_HAS_VPD;
6344 for (i = 0; i < VPDSIZE; i++) {
6345 brd->vpd[i] = readb(brd->re_map_membase +
6346 vpd_offset + i);
6347 }
6348 }
6349 }
6350
6351 /*
6352 * We MUST poke the magic number at the PCI Rom Address location again.
6353 * This makes the card report the regular board memory back to us,
6354 * rather than the OTPROM memory.
6355 */
6356 magic = FEP5_ROM_MAGIC;
6357 pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
6358}
6359
6360
6361static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf)
6362{
6363 return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
6364}
6365static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL);
6366
6367
6368static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf)
6369{
6370 return snprintf(buf, PAGE_SIZE, "%d\n", dgap_numboards);
6371}
6372static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL);
6373
6374
6375static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf)
6376{
6377 return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
6378}
6379static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL);
6380
6381
6382static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp,
6383 char *buf)
6384{
6385 return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter);
6386}
6387static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL);
6388
6389static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf)
6390{
6391 return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick);
6392}
6393
6394static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp,
6395 const char *buf, size_t count)
6396{
6397 if (sscanf(buf, "%d\n", &dgap_poll_tick) != 1)
6398 return -EINVAL;
6399 return count;
6400}
6401static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show,
6402 dgap_driver_pollrate_store);
6403
6404
6405static int dgap_create_driver_sysfiles(struct pci_driver *dgap_driver)
6406{
6407 int rc = 0;
6408 struct device_driver *driverfs = &dgap_driver->driver;
6409
6410 rc |= driver_create_file(driverfs, &driver_attr_version);
6411 rc |= driver_create_file(driverfs, &driver_attr_boards);
6412 rc |= driver_create_file(driverfs, &driver_attr_maxboards);
6413 rc |= driver_create_file(driverfs, &driver_attr_pollrate);
6414 rc |= driver_create_file(driverfs, &driver_attr_pollcounter);
6415
6416 return rc;
6417}
6418
6419static void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver)
6420{
6421 struct device_driver *driverfs = &dgap_driver->driver;
6422
6423 driver_remove_file(driverfs, &driver_attr_version);
6424 driver_remove_file(driverfs, &driver_attr_boards);
6425 driver_remove_file(driverfs, &driver_attr_maxboards);
6426 driver_remove_file(driverfs, &driver_attr_pollrate);
6427 driver_remove_file(driverfs, &driver_attr_pollcounter);
6428}
6429
Mark Hounschell7568f7d2014-02-19 13:12:01 -05006430static struct attribute_group dgap_tty_attribute_group = {
6431 .name = NULL,
6432 .attrs = dgap_sysfs_tty_entries,
6433};
6434
Mark Hounschellfe0ef8e2014-02-19 13:12:13 -05006435static void dgap_create_tty_sysfs(struct un_t *un, struct device *c)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05006436{
6437 int ret;
6438
6439 ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group);
Mark Hounschell54794d12014-03-04 16:03:07 -05006440 if (ret)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05006441 return;
Mark Hounschell7568f7d2014-02-19 13:12:01 -05006442
6443 dev_set_drvdata(c, un);
6444
6445}
6446
Mark Hounschellfe0ef8e2014-02-19 13:12:13 -05006447static void dgap_remove_tty_sysfs(struct device *c)
Mark Hounschell7568f7d2014-02-19 13:12:01 -05006448{
6449 sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group);
6450}
Mark Hounschell69edaa22014-02-19 13:12:02 -05006451
6452/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006453 * Create pr and tty device entries
Mark Hounschell69edaa22014-02-19 13:12:02 -05006454 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006455static int dgap_tty_register_ports(struct board_t *brd)
Mark Hounschell69edaa22014-02-19 13:12:02 -05006456{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006457 struct channel_t *ch;
6458 int i;
6459 int ret;
6460
6461 brd->serial_ports = kcalloc(brd->nasync, sizeof(*brd->serial_ports),
6462 GFP_KERNEL);
6463 if (!brd->serial_ports)
6464 return -ENOMEM;
6465
6466 brd->printer_ports = kcalloc(brd->nasync, sizeof(*brd->printer_ports),
6467 GFP_KERNEL);
6468 if (!brd->printer_ports) {
6469 ret = -ENOMEM;
6470 goto free_serial_ports;
6471 }
6472
6473 for (i = 0; i < brd->nasync; i++) {
6474 tty_port_init(&brd->serial_ports[i]);
6475 tty_port_init(&brd->printer_ports[i]);
6476 }
6477
6478 ch = brd->channels[0];
6479 for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
6480
6481 struct device *classp;
6482
6483 classp = tty_port_register_device(&brd->serial_ports[i],
6484 brd->serial_driver,
6485 i, NULL);
6486
6487 if (IS_ERR(classp)) {
6488 ret = PTR_ERR(classp);
6489 goto unregister_ttys;
6490 }
6491
6492 dgap_create_tty_sysfs(&ch->ch_tun, classp);
6493 ch->ch_tun.un_sysfs = classp;
6494
6495 classp = tty_port_register_device(&brd->printer_ports[i],
6496 brd->print_driver,
6497 i, NULL);
6498
6499 if (IS_ERR(classp)) {
6500 ret = PTR_ERR(classp);
6501 goto unregister_ttys;
6502 }
6503
6504 dgap_create_tty_sysfs(&ch->ch_pun, classp);
6505 ch->ch_pun.un_sysfs = classp;
6506 }
6507 dgap_create_ports_sysfiles(brd);
6508
6509 return 0;
6510
6511unregister_ttys:
6512 while (i >= 0) {
6513 ch = brd->channels[i];
6514 if (ch->ch_tun.un_sysfs) {
6515 dgap_remove_tty_sysfs(ch->ch_tun.un_sysfs);
6516 tty_unregister_device(brd->serial_driver, i);
6517 }
6518
6519 if (ch->ch_pun.un_sysfs) {
6520 dgap_remove_tty_sysfs(ch->ch_pun.un_sysfs);
6521 tty_unregister_device(brd->print_driver, i);
6522 }
6523 i--;
6524 }
6525
6526 for (i = 0; i < brd->nasync; i++) {
6527 tty_port_destroy(&brd->serial_ports[i]);
6528 tty_port_destroy(&brd->printer_ports[i]);
6529 }
6530
6531 kfree(brd->printer_ports);
6532 brd->printer_ports = NULL;
6533
6534free_serial_ports:
6535 kfree(brd->serial_ports);
6536 brd->serial_ports = NULL;
6537
6538 return ret;
6539}
6540
6541/*
6542 * dgap_cleanup_tty()
6543 *
6544 * Uninitialize the TTY portion of this driver. Free all memory and
6545 * resources.
6546 */
6547static void dgap_cleanup_tty(struct board_t *brd)
6548{
6549 struct device *dev;
6550 unsigned int i;
6551
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006552 for (i = 0; i < brd->nasync; i++) {
6553 tty_port_destroy(&brd->serial_ports[i]);
6554 dev = brd->channels[i]->ch_tun.un_sysfs;
6555 dgap_remove_tty_sysfs(dev);
6556 tty_unregister_device(brd->serial_driver, i);
6557 }
6558 tty_unregister_driver(brd->serial_driver);
6559 put_tty_driver(brd->serial_driver);
6560 kfree(brd->serial_ports);
6561
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006562 for (i = 0; i < brd->nasync; i++) {
6563 tty_port_destroy(&brd->printer_ports[i]);
6564 dev = brd->channels[i]->ch_pun.un_sysfs;
6565 dgap_remove_tty_sysfs(dev);
6566 tty_unregister_device(brd->print_driver, i);
6567 }
6568 tty_unregister_driver(brd->print_driver);
6569 put_tty_driver(brd->print_driver);
6570 kfree(brd->printer_ports);
6571}
6572
6573static int dgap_request_irq(struct board_t *brd)
6574{
Mark Hounschell174efc12014-05-23 12:54:04 -04006575 int rc;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006576
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006577 if (!brd || brd->magic != DGAP_BOARD_MAGIC)
6578 return -ENODEV;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006579
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006580 /*
6581 * Set up our interrupt handler if we are set to do interrupts.
6582 */
6583 if (dgap_config_get_useintr(brd) && brd->irq) {
Mark Hounschell69edaa22014-02-19 13:12:02 -05006584
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006585 rc = request_irq(brd->irq, dgap_intr, IRQF_SHARED, "DGAP", brd);
Mark Hounschell69edaa22014-02-19 13:12:02 -05006586
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006587 if (!rc)
6588 brd->intr_used = 1;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006589 }
Mark Hounschellcf42c342014-02-28 12:42:09 -05006590 return 0;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006591}
6592
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006593static void dgap_free_irq(struct board_t *brd)
Mark Hounschell69edaa22014-02-19 13:12:02 -05006594{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006595 if (brd->intr_used && brd->irq)
6596 free_irq(brd->irq, brd);
Mark Hounschell69edaa22014-02-19 13:12:02 -05006597}
6598
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006599static int dgap_firmware_load(struct pci_dev *pdev, int card_type,
6600 struct board_t *brd)
Mark Hounschell69edaa22014-02-19 13:12:02 -05006601{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006602 const struct firmware *fw;
6603 char *tmp_ptr;
6604 int ret;
6605 char *dgap_config_buf;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006606
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006607 dgap_get_vpd(brd);
6608 dgap_do_reset_board(brd);
Mark Hounschell69edaa22014-02-19 13:12:02 -05006609
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006610 if (fw_info[card_type].conf_name) {
6611 ret = request_firmware(&fw, fw_info[card_type].conf_name,
6612 &pdev->dev);
6613 if (ret) {
6614 dev_err(&pdev->dev, "config file %s not found\n",
6615 fw_info[card_type].conf_name);
6616 return ret;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006617 }
Mark Hounschell69edaa22014-02-19 13:12:02 -05006618
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006619 dgap_config_buf = kzalloc(fw->size + 1, GFP_KERNEL);
6620 if (!dgap_config_buf) {
6621 release_firmware(fw);
6622 return -ENOMEM;
6623 }
Mark Hounschell69edaa22014-02-19 13:12:02 -05006624
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006625 memcpy(dgap_config_buf, fw->data, fw->size);
6626 release_firmware(fw);
Mark Hounschell69edaa22014-02-19 13:12:02 -05006627
Mark Hounschell0be048c2014-05-28 16:17:55 -04006628 /*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006629 * preserve dgap_config_buf
6630 * as dgap_parsefile would
6631 * otherwise alter it.
Mark Hounschell0be048c2014-05-28 16:17:55 -04006632 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006633 tmp_ptr = dgap_config_buf;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006634
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006635 if (dgap_parsefile(&tmp_ptr) != 0) {
6636 kfree(dgap_config_buf);
6637 return -EINVAL;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006638 }
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006639 kfree(dgap_config_buf);
Mark Hounschell69edaa22014-02-19 13:12:02 -05006640 }
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006641
6642 /*
6643 * Match this board to a config the user created for us.
6644 */
6645 brd->bd_config =
6646 dgap_find_config(brd->type, brd->pci_bus, brd->pci_slot);
6647
6648 /*
6649 * Because the 4 port Xr products share the same PCI ID
6650 * as the 8 port Xr products, if we receive a NULL config
6651 * back, and this is a PAPORT8 board, retry with a
6652 * PAPORT4 attempt as well.
6653 */
6654 if (brd->type == PAPORT8 && !brd->bd_config)
6655 brd->bd_config =
6656 dgap_find_config(PAPORT4, brd->pci_bus, brd->pci_slot);
6657
6658 if (!brd->bd_config) {
6659 dev_err(&pdev->dev, "No valid configuration found\n");
6660 return -EINVAL;
6661 }
6662
6663 if (fw_info[card_type].bios_name) {
6664 ret = request_firmware(&fw, fw_info[card_type].bios_name,
6665 &pdev->dev);
6666 if (ret) {
6667 dev_err(&pdev->dev, "bios file %s not found\n",
6668 fw_info[card_type].bios_name);
6669 return ret;
6670 }
6671 dgap_do_bios_load(brd, fw->data, fw->size);
6672 release_firmware(fw);
6673
6674 /* Wait for BIOS to test board... */
6675 ret = dgap_test_bios(brd);
6676 if (ret)
6677 return ret;
6678 }
6679
6680 if (fw_info[card_type].fep_name) {
6681 ret = request_firmware(&fw, fw_info[card_type].fep_name,
6682 &pdev->dev);
6683 if (ret) {
6684 dev_err(&pdev->dev, "dgap: fep file %s not found\n",
6685 fw_info[card_type].fep_name);
6686 return ret;
6687 }
6688 dgap_do_fep_load(brd, fw->data, fw->size);
6689 release_firmware(fw);
6690
6691 /* Wait for FEP to load on board... */
6692 ret = dgap_test_fep(brd);
6693 if (ret)
6694 return ret;
6695 }
6696
6697#ifdef DIGI_CONCENTRATORS_SUPPORTED
6698 /*
6699 * If this is a CX or EPCX, we need to see if the firmware
6700 * is requesting a concentrator image from us.
6701 */
6702 if ((bd->type == PCX) || (bd->type == PEPC)) {
6703 chk_addr = (u16 *) (vaddr + DOWNREQ);
6704 /* Nonzero if FEP is requesting concentrator image. */
6705 check = readw(chk_addr);
6706 vaddr = brd->re_map_membase;
6707 }
6708
6709 if (fw_info[card_type].con_name && check && vaddr) {
6710 ret = request_firmware(&fw, fw_info[card_type].con_name,
6711 &pdev->dev);
6712 if (ret) {
6713 dev_err(&pdev->dev, "conc file %s not found\n",
6714 fw_info[card_type].con_name);
6715 return ret;
6716 }
6717 /* Put concentrator firmware loading code here */
6718 offset = readw((u16 *) (vaddr + DOWNREQ));
6719 memcpy_toio(offset, fw->data, fw->size);
6720
6721 dgap_do_conc_load(brd, (char *)fw->data, fw->size)
6722 release_firmware(fw);
6723 }
6724#endif
6725
6726 return 0;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006727}
6728
6729/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006730 * dgap_tty_init()
6731 *
6732 * Init the tty subsystem. Called once per board after board has been
6733 * downloaded and init'ed.
Mark Hounschell69edaa22014-02-19 13:12:02 -05006734 */
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006735static int dgap_tty_init(struct board_t *brd)
Mark Hounschell69edaa22014-02-19 13:12:02 -05006736{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006737 int i;
6738 int tlw;
6739 uint true_count;
6740 u8 __iomem *vaddr;
6741 u8 modem;
6742 struct channel_t *ch;
6743 struct bs_t __iomem *bs;
6744 struct cm_t __iomem *cm;
6745 int ret;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006746
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006747 /*
6748 * Initialize board structure elements.
6749 */
Mark Hounschell69edaa22014-02-19 13:12:02 -05006750
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006751 vaddr = brd->re_map_membase;
6752 true_count = readw((vaddr + NCHAN));
Mark Hounschell69edaa22014-02-19 13:12:02 -05006753
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006754 brd->nasync = dgap_config_get_num_prts(brd);
6755
6756 if (!brd->nasync)
6757 brd->nasync = brd->maxports;
6758
6759 if (brd->nasync > brd->maxports)
6760 brd->nasync = brd->maxports;
6761
6762 if (true_count != brd->nasync) {
6763 dev_warn(&brd->pdev->dev,
6764 "%s configured for %d ports, has %d ports.\n",
6765 brd->name, brd->nasync, true_count);
6766
6767 if ((brd->type == PPCM) &&
6768 (true_count == 64 || true_count == 0)) {
6769 dev_warn(&brd->pdev->dev,
6770 "Please make SURE the EBI cable running from the card\n");
6771 dev_warn(&brd->pdev->dev,
6772 "to each EM module is plugged into EBI IN!\n");
Mark Hounschell69edaa22014-02-19 13:12:02 -05006773 }
Mark Hounschell69edaa22014-02-19 13:12:02 -05006774
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006775 brd->nasync = true_count;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006776
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006777 /* If no ports, don't bother going any further */
6778 if (!brd->nasync) {
6779 brd->state = BOARD_FAILED;
6780 brd->dpastatus = BD_NOFEP;
6781 return -EIO;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006782 }
6783 }
6784
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006785 /*
6786 * Allocate channel memory that might not have been allocated
6787 * when the driver was first loaded.
6788 */
6789 for (i = 0; i < brd->nasync; i++) {
6790 brd->channels[i] =
6791 kzalloc(sizeof(struct channel_t), GFP_KERNEL);
6792 if (!brd->channels[i]) {
6793 ret = -ENOMEM;
6794 goto free_chan;
6795 }
6796 }
6797
6798 ch = brd->channels[0];
6799 vaddr = brd->re_map_membase;
6800
6801 bs = (struct bs_t __iomem *) ((ulong) vaddr + CHANBUF);
6802 cm = (struct cm_t __iomem *) ((ulong) vaddr + CMDBUF);
6803
6804 brd->bd_bs = bs;
6805
6806 /* Set up channel variables */
6807 for (i = 0; i < brd->nasync; i++, ch = brd->channels[i], bs++) {
6808
6809 spin_lock_init(&ch->ch_lock);
6810
6811 /* Store all our magic numbers */
6812 ch->magic = DGAP_CHANNEL_MAGIC;
6813 ch->ch_tun.magic = DGAP_UNIT_MAGIC;
6814 ch->ch_tun.un_type = DGAP_SERIAL;
6815 ch->ch_tun.un_ch = ch;
6816 ch->ch_tun.un_dev = i;
6817
6818 ch->ch_pun.magic = DGAP_UNIT_MAGIC;
6819 ch->ch_pun.un_type = DGAP_PRINT;
6820 ch->ch_pun.un_ch = ch;
6821 ch->ch_pun.un_dev = i;
6822
6823 ch->ch_vaddr = vaddr;
6824 ch->ch_bs = bs;
6825 ch->ch_cm = cm;
6826 ch->ch_bd = brd;
6827 ch->ch_portnum = i;
6828 ch->ch_digi = dgap_digi_init;
6829
6830 /*
6831 * Set up digi dsr and dcd bits based on altpin flag.
6832 */
6833 if (dgap_config_get_altpin(brd)) {
6834 ch->ch_dsr = DM_CD;
6835 ch->ch_cd = DM_DSR;
6836 ch->ch_digi.digi_flags |= DIGI_ALTPIN;
6837 } else {
6838 ch->ch_cd = DM_CD;
6839 ch->ch_dsr = DM_DSR;
6840 }
6841
6842 ch->ch_taddr = vaddr + (ioread16(&(ch->ch_bs->tx_seg)) << 4);
6843 ch->ch_raddr = vaddr + (ioread16(&(ch->ch_bs->rx_seg)) << 4);
6844 ch->ch_tx_win = 0;
6845 ch->ch_rx_win = 0;
6846 ch->ch_tsize = readw(&(ch->ch_bs->tx_max)) + 1;
6847 ch->ch_rsize = readw(&(ch->ch_bs->rx_max)) + 1;
6848 ch->ch_tstart = 0;
6849 ch->ch_rstart = 0;
6850
6851 /*
6852 * Set queue water marks, interrupt mask,
6853 * and general tty parameters.
6854 */
6855 tlw = ch->ch_tsize >= 2000 ? ((ch->ch_tsize * 5) / 8) :
6856 ch->ch_tsize / 2;
6857 ch->ch_tlw = tlw;
6858
6859 dgap_cmdw(ch, STLOW, tlw, 0);
6860
6861 dgap_cmdw(ch, SRLOW, ch->ch_rsize / 2, 0);
6862
6863 dgap_cmdw(ch, SRHIGH, 7 * ch->ch_rsize / 8, 0);
6864
6865 ch->ch_mistat = readb(&(ch->ch_bs->m_stat));
6866
6867 init_waitqueue_head(&ch->ch_flags_wait);
6868 init_waitqueue_head(&ch->ch_tun.un_flags_wait);
6869 init_waitqueue_head(&ch->ch_pun.un_flags_wait);
6870
6871 /* Turn on all modem interrupts for now */
6872 modem = (DM_CD | DM_DSR | DM_CTS | DM_RI);
6873 writeb(modem, &(ch->ch_bs->m_int));
6874
6875 /*
6876 * Set edelay to 0 if interrupts are turned on,
6877 * otherwise set edelay to the usual 100.
6878 */
6879 if (brd->intr_used)
6880 writew(0, &(ch->ch_bs->edelay));
6881 else
6882 writew(100, &(ch->ch_bs->edelay));
6883
6884 writeb(1, &(ch->ch_bs->idata));
6885 }
6886
6887 return 0;
6888
6889free_chan:
6890 while (--i >= 0) {
6891 kfree(brd->channels[i]);
6892 brd->channels[i] = NULL;
6893 }
6894 return ret;
Mark Hounschell69edaa22014-02-19 13:12:02 -05006895}
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09006896
6897/*
6898 * dgap_tty_free()
6899 *
6900 * Free the channles which are allocated in dgap_tty_init().
6901 */
6902static void dgap_tty_free(struct board_t *brd)
6903{
6904 int i;
6905
6906 for (i = 0; i < brd->nasync; i++)
6907 kfree(brd->channels[i]);
6908}
6909
6910static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6911{
6912 int rc;
6913 struct board_t *brd;
6914
6915 if (dgap_numboards >= MAXBOARDS)
6916 return -EPERM;
6917
6918 rc = pci_enable_device(pdev);
6919 if (rc)
6920 return -EIO;
6921
6922 brd = dgap_found_board(pdev, ent->driver_data, dgap_numboards);
6923 if (IS_ERR(brd))
6924 return PTR_ERR(brd);
6925
6926 rc = dgap_firmware_load(pdev, ent->driver_data, brd);
6927 if (rc)
6928 goto cleanup_brd;
6929
6930 rc = dgap_alloc_flipbuf(brd);
6931 if (rc)
6932 goto cleanup_brd;
6933
6934 rc = dgap_tty_register(brd);
6935 if (rc)
6936 goto free_flipbuf;
6937
6938 rc = dgap_request_irq(brd);
6939 if (rc)
6940 goto unregister_tty;
6941
6942 /*
6943 * Do tty device initialization.
6944 */
6945 rc = dgap_tty_init(brd);
6946 if (rc < 0)
6947 goto free_irq;
6948
6949 rc = dgap_tty_register_ports(brd);
6950 if (rc)
6951 goto tty_free;
6952
6953 brd->state = BOARD_READY;
6954 brd->dpastatus = BD_RUNNING;
6955
6956 dgap_board[dgap_numboards++] = brd;
6957
6958 return 0;
6959
6960tty_free:
6961 dgap_tty_free(brd);
6962free_irq:
6963 dgap_free_irq(brd);
6964unregister_tty:
6965 dgap_tty_unregister(brd);
6966free_flipbuf:
6967 dgap_free_flipbuf(brd);
6968cleanup_brd:
6969 dgap_cleanup_nodes();
6970 dgap_unmap(brd);
6971 kfree(brd);
6972
6973 return rc;
6974}
6975
Sudip Mukherjeed1c9f3e2015-05-07 16:42:20 +05306976/*
6977 * dgap_cleanup_board()
6978 *
6979 * Free all the memory associated with a board
6980 */
6981static void dgap_cleanup_board(struct board_t *brd)
6982{
6983 unsigned int i;
6984
6985 if (!brd || brd->magic != DGAP_BOARD_MAGIC)
6986 return;
6987
6988 dgap_free_irq(brd);
6989
6990 tasklet_kill(&brd->helper_tasklet);
6991
6992 dgap_unmap(brd);
6993
6994 /* Free all allocated channels structs */
6995 for (i = 0; i < MAXPORTS ; i++)
6996 kfree(brd->channels[i]);
6997
6998 kfree(brd->flipbuf);
6999 kfree(brd->flipflagbuf);
7000
7001 dgap_board[brd->boardnum] = NULL;
7002
7003 kfree(brd);
7004}
7005
Sudip Mukherjee174b83c2015-07-16 18:28:19 +05307006static void dgap_stop(bool removesys, struct pci_driver *drv)
Sudip Mukherjeeeda03952015-07-16 18:28:18 +05307007{
7008 unsigned long lock_flags;
7009
7010 spin_lock_irqsave(&dgap_poll_lock, lock_flags);
7011 dgap_poll_stop = 1;
7012 spin_unlock_irqrestore(&dgap_poll_lock, lock_flags);
7013
7014 del_timer_sync(&dgap_poll_timer);
Sudip Mukherjee174b83c2015-07-16 18:28:19 +05307015 if (removesys)
7016 dgap_remove_driver_sysfiles(drv);
Sudip Mukherjeeeda03952015-07-16 18:28:18 +05307017
7018 device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0));
7019 class_destroy(dgap_class);
7020 unregister_chrdev(DIGI_DGAP_MAJOR, "dgap");
7021}
7022
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09007023static void dgap_remove_one(struct pci_dev *dev)
7024{
Sudip Mukherjee1397e2f2015-05-07 16:42:21 +05307025 unsigned int i;
Sudip Mukherjee1397e2f2015-05-07 16:42:21 +05307026 struct pci_driver *drv = to_pci_driver(dev->dev.driver);
7027
Sudip Mukherjeeb8d1f262015-07-16 18:28:20 +05307028 dgap_stop(true, drv);
Sudip Mukherjee1397e2f2015-05-07 16:42:21 +05307029 for (i = 0; i < dgap_numboards; ++i) {
7030 dgap_remove_ports_sysfiles(dgap_board[i]);
7031 dgap_cleanup_tty(dgap_board[i]);
7032 dgap_cleanup_board(dgap_board[i]);
7033 }
7034
7035 dgap_cleanup_nodes();
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09007036}
7037
7038static struct pci_driver dgap_driver = {
7039 .name = "dgap",
7040 .probe = dgap_init_one,
7041 .id_table = dgap_pci_tbl,
7042 .remove = dgap_remove_one,
7043};
7044
7045/*
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09007046 * Start of driver.
7047 */
7048static int dgap_start(void)
7049{
7050 int rc;
7051 unsigned long flags;
7052 struct device *device;
7053
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09007054 dgap_numboards = 0;
7055
7056 pr_info("For the tools package please visit http://www.digi.com\n");
7057
7058 /*
7059 * Register our base character device into the kernel.
7060 */
7061
7062 /*
7063 * Register management/dpa devices
7064 */
7065 rc = register_chrdev(DIGI_DGAP_MAJOR, "dgap", &dgap_board_fops);
7066 if (rc < 0)
7067 return rc;
7068
7069 dgap_class = class_create(THIS_MODULE, "dgap_mgmt");
7070 if (IS_ERR(dgap_class)) {
7071 rc = PTR_ERR(dgap_class);
7072 goto failed_class;
7073 }
7074
7075 device = device_create(dgap_class, NULL,
7076 MKDEV(DIGI_DGAP_MAJOR, 0),
7077 NULL, "dgap_mgmt");
7078 if (IS_ERR(device)) {
7079 rc = PTR_ERR(device);
7080 goto failed_device;
7081 }
7082
7083 /* Start the poller */
7084 spin_lock_irqsave(&dgap_poll_lock, flags);
Somya Anand2049f1e2015-03-11 17:02:14 +05307085 setup_timer(&dgap_poll_timer, dgap_poll_handler, 0);
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09007086 dgap_poll_timer.data = 0;
7087 dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
7088 dgap_poll_timer.expires = dgap_poll_time;
7089 spin_unlock_irqrestore(&dgap_poll_lock, flags);
7090
7091 add_timer(&dgap_poll_timer);
7092
7093 return rc;
7094
7095failed_device:
7096 class_destroy(dgap_class);
7097failed_class:
7098 unregister_chrdev(DIGI_DGAP_MAJOR, "dgap");
7099 return rc;
7100}
7101
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09007102/************************************************************************
7103 *
7104 * Driver load/unload functions
7105 *
7106 ************************************************************************/
7107
7108/*
7109 * init_module()
7110 *
7111 * Module load. This is where it all starts.
7112 */
7113static int dgap_init_module(void)
7114{
7115 int rc;
7116
7117 pr_info("%s, Digi International Part Number %s\n", DG_NAME, DG_PART);
7118
7119 rc = dgap_start();
7120 if (rc)
7121 return rc;
7122
7123 rc = pci_register_driver(&dgap_driver);
Sudip Mukherjeeac4e5042015-07-16 18:28:17 +05307124 if (rc) {
Sudip Mukherjee174b83c2015-07-16 18:28:19 +05307125 dgap_stop(false, NULL);
Sudip Mukherjeeac4e5042015-07-16 18:28:17 +05307126 return rc;
7127 }
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09007128
7129 rc = dgap_create_driver_sysfiles(&dgap_driver);
7130 if (rc)
7131 goto err_unregister;
7132
7133 dgap_driver_state = DRIVER_READY;
7134
7135 return 0;
7136
7137err_unregister:
7138 pci_unregister_driver(&dgap_driver);
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09007139 return rc;
7140}
7141
7142/*
7143 * dgap_cleanup_module()
7144 *
7145 * Module unload. This is where it all ends.
7146 */
7147static void dgap_cleanup_module(void)
7148{
Daeseok Youn0b2cf5c2014-10-31 10:20:37 +09007149 if (dgap_numboards)
7150 pci_unregister_driver(&dgap_driver);
7151}
7152
7153module_init(dgap_init_module);
7154module_exit(dgap_cleanup_module);
7155
7156MODULE_LICENSE("GPL");
7157MODULE_AUTHOR("Digi International, http://www.digi.com");
7158MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line");
7159MODULE_SUPPORTED_DEVICE("dgap");