Linux Audio

Check our new training course

Loading...
v3.1
 
  1/*
  2 * IPWireless 3G PCMCIA Network Driver
  3 *
  4 * Original code
  5 *   by Stephen Blackheath <stephen@blacksapphire.com>,
  6 *      Ben Martel <benm@symmetric.co.nz>
  7 *
  8 * Copyrighted as follows:
  9 *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
 10 *
 11 * Various driver changes and rewrites, port to new kernels
 12 *   Copyright (C) 2006-2007 Jiri Kosina
 13 *
 14 * Misc code cleanups and updates
 15 *   Copyright (C) 2007 David Sterba
 16 */
 17
 18#include <linux/init.h>
 19#include <linux/kernel.h>
 20#include <linux/module.h>
 21#include <linux/mutex.h>
 22#include <linux/ppp_defs.h>
 23#include <linux/if.h>
 24#include <linux/if_ppp.h>
 25#include <linux/sched.h>
 26#include <linux/serial.h>
 27#include <linux/slab.h>
 28#include <linux/tty.h>
 29#include <linux/tty_driver.h>
 30#include <linux/tty_flip.h>
 31#include <linux/uaccess.h>
 32
 33#include "tty.h"
 34#include "network.h"
 35#include "hardware.h"
 36#include "main.h"
 37
 38#define IPWIRELESS_PCMCIA_START 	(0)
 39#define IPWIRELESS_PCMCIA_MINORS	(24)
 40#define IPWIRELESS_PCMCIA_MINOR_RANGE	(8)
 41
 42#define TTYTYPE_MODEM    (0)
 43#define TTYTYPE_MONITOR  (1)
 44#define TTYTYPE_RAS_RAW  (2)
 45
 46struct ipw_tty {
 
 47	int index;
 48	struct ipw_hardware *hardware;
 49	unsigned int channel_idx;
 50	unsigned int secondary_channel_idx;
 51	int tty_type;
 52	struct ipw_network *network;
 53	struct tty_struct *linux_tty;
 54	int open_count;
 55	unsigned int control_lines;
 56	struct mutex ipw_tty_mutex;
 57	int tx_bytes_queued;
 58	int closing;
 59};
 60
 61static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS];
 62
 63static struct tty_driver *ipw_tty_driver;
 64
 65static char *tty_type_name(int tty_type)
 66{
 67	static char *channel_names[] = {
 68		"modem",
 69		"monitor",
 70		"RAS-raw"
 71	};
 72
 73	return channel_names[tty_type];
 74}
 75
 76static void report_registering(struct ipw_tty *tty)
 77{
 78	char *iftype = tty_type_name(tty->tty_type);
 79
 80	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
 81	       ": registering %s device ttyIPWp%d\n", iftype, tty->index);
 82}
 83
 84static void report_deregistering(struct ipw_tty *tty)
 85{
 86	char *iftype = tty_type_name(tty->tty_type);
 87
 88	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
 89	       ": deregistering %s device ttyIPWp%d\n", iftype,
 90	       tty->index);
 91}
 92
 93static struct ipw_tty *get_tty(int minor)
 94{
 95	if (minor < ipw_tty_driver->minor_start
 96			|| minor >= ipw_tty_driver->minor_start +
 97			IPWIRELESS_PCMCIA_MINORS)
 98		return NULL;
 99	else {
100		int minor_offset = minor - ipw_tty_driver->minor_start;
101
102		/*
103		 * The 'ras_raw' channel is only available when 'loopback' mode
104		 * is enabled.
105		 * Number of minor starts with 16 (_RANGE * _RAS_RAW).
106		 */
107		if (!ipwireless_loopback &&
108				minor_offset >=
109				 IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
110			return NULL;
111
112		return ttys[minor_offset];
113	}
114}
115
116static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
117{
118	int minor = linux_tty->index;
119	struct ipw_tty *tty = get_tty(minor);
120
121	if (!tty)
122		return -ENODEV;
123
124	mutex_lock(&tty->ipw_tty_mutex);
125
126	if (tty->closing) {
127		mutex_unlock(&tty->ipw_tty_mutex);
128		return -ENODEV;
129	}
130	if (tty->open_count == 0)
131		tty->tx_bytes_queued = 0;
132
133	tty->open_count++;
134
135	tty->linux_tty = linux_tty;
136	linux_tty->driver_data = tty;
137	linux_tty->low_latency = 1;
138
139	if (tty->tty_type == TTYTYPE_MODEM)
140		ipwireless_ppp_open(tty->network);
141
142	mutex_unlock(&tty->ipw_tty_mutex);
143
144	return 0;
145}
146
147static void do_ipw_close(struct ipw_tty *tty)
148{
149	tty->open_count--;
150
151	if (tty->open_count == 0) {
152		struct tty_struct *linux_tty = tty->linux_tty;
153
154		if (linux_tty != NULL) {
155			tty->linux_tty = NULL;
156			linux_tty->driver_data = NULL;
157
158			if (tty->tty_type == TTYTYPE_MODEM)
159				ipwireless_ppp_close(tty->network);
160		}
161	}
162}
163
164static void ipw_hangup(struct tty_struct *linux_tty)
165{
166	struct ipw_tty *tty = linux_tty->driver_data;
167
168	if (!tty)
169		return;
170
171	mutex_lock(&tty->ipw_tty_mutex);
172	if (tty->open_count == 0) {
173		mutex_unlock(&tty->ipw_tty_mutex);
174		return;
175	}
176
177	do_ipw_close(tty);
178
179	mutex_unlock(&tty->ipw_tty_mutex);
180}
181
182static void ipw_close(struct tty_struct *linux_tty, struct file *filp)
183{
184	ipw_hangup(linux_tty);
185}
186
187/* Take data received from hardware, and send it out the tty */
188void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
189			unsigned int length)
190{
191	struct tty_struct *linux_tty;
192	int work = 0;
193
194	mutex_lock(&tty->ipw_tty_mutex);
195	linux_tty = tty->linux_tty;
196	if (linux_tty == NULL) {
197		mutex_unlock(&tty->ipw_tty_mutex);
198		return;
199	}
200
201	if (!tty->open_count) {
202		mutex_unlock(&tty->ipw_tty_mutex);
203		return;
204	}
205	mutex_unlock(&tty->ipw_tty_mutex);
206
207	work = tty_insert_flip_string(linux_tty, data, length);
208
209	if (work != length)
210		printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
211				": %d chars not inserted to flip buffer!\n",
212				length - work);
213
214	/*
215	 * This may sleep if ->low_latency is set
216	 */
217	if (work)
218		tty_flip_buffer_push(linux_tty);
219}
220
221static void ipw_write_packet_sent_callback(void *callback_data,
222					   unsigned int packet_length)
223{
224	struct ipw_tty *tty = callback_data;
225
226	/*
227	 * Packet has been sent, so we subtract the number of bytes from our
228	 * tally of outstanding TX bytes.
229	 */
230	tty->tx_bytes_queued -= packet_length;
231}
232
233static int ipw_write(struct tty_struct *linux_tty,
234		     const unsigned char *buf, int count)
235{
236	struct ipw_tty *tty = linux_tty->driver_data;
237	int room, ret;
238
239	if (!tty)
240		return -ENODEV;
241
242	mutex_lock(&tty->ipw_tty_mutex);
243	if (!tty->open_count) {
244		mutex_unlock(&tty->ipw_tty_mutex);
245		return -EINVAL;
246	}
247
248	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
249	if (room < 0)
250		room = 0;
251	/* Don't allow caller to write any more than we have room for */
252	if (count > room)
253		count = room;
254
255	if (count == 0) {
256		mutex_unlock(&tty->ipw_tty_mutex);
257		return 0;
258	}
259
260	ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS,
261			       buf, count,
262			       ipw_write_packet_sent_callback, tty);
263	if (ret == -1) {
264		mutex_unlock(&tty->ipw_tty_mutex);
265		return 0;
266	}
267
268	tty->tx_bytes_queued += count;
269	mutex_unlock(&tty->ipw_tty_mutex);
270
271	return count;
272}
273
274static int ipw_write_room(struct tty_struct *linux_tty)
275{
276	struct ipw_tty *tty = linux_tty->driver_data;
277	int room;
278
279	/* FIXME: Exactly how is the tty object locked here .. */
280	if (!tty)
281		return -ENODEV;
282
283	if (!tty->open_count)
284		return -EINVAL;
285
286	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
287	if (room < 0)
288		room = 0;
289
290	return room;
291}
292
293static int ipwireless_get_serial_info(struct ipw_tty *tty,
294				      struct serial_struct __user *retinfo)
295{
296	struct serial_struct tmp;
297
298	if (!retinfo)
299		return (-EFAULT);
300
301	memset(&tmp, 0, sizeof(tmp));
302	tmp.type = PORT_UNKNOWN;
303	tmp.line = tty->index;
304	tmp.port = 0;
305	tmp.irq = 0;
306	tmp.flags = 0;
307	tmp.baud_base = 115200;
308	tmp.close_delay = 0;
309	tmp.closing_wait = 0;
310	tmp.custom_divisor = 0;
311	tmp.hub6 = 0;
312	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
313		return -EFAULT;
314
 
 
 
315	return 0;
316}
317
 
 
 
 
 
 
318static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
319{
320	struct ipw_tty *tty = linux_tty->driver_data;
321
322	if (!tty)
323		return 0;
324
325	if (!tty->open_count)
326		return 0;
327
328	return tty->tx_bytes_queued;
329}
330
331static int get_control_lines(struct ipw_tty *tty)
332{
333	unsigned int my = tty->control_lines;
334	unsigned int out = 0;
335
336	if (my & IPW_CONTROL_LINE_RTS)
337		out |= TIOCM_RTS;
338	if (my & IPW_CONTROL_LINE_DTR)
339		out |= TIOCM_DTR;
340	if (my & IPW_CONTROL_LINE_CTS)
341		out |= TIOCM_CTS;
342	if (my & IPW_CONTROL_LINE_DSR)
343		out |= TIOCM_DSR;
344	if (my & IPW_CONTROL_LINE_DCD)
345		out |= TIOCM_CD;
346
347	return out;
348}
349
350static int set_control_lines(struct ipw_tty *tty, unsigned int set,
351			     unsigned int clear)
352{
353	int ret;
354
355	if (set & TIOCM_RTS) {
356		ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1);
357		if (ret)
358			return ret;
359		if (tty->secondary_channel_idx != -1) {
360			ret = ipwireless_set_RTS(tty->hardware,
361					  tty->secondary_channel_idx, 1);
362			if (ret)
363				return ret;
364		}
365	}
366	if (set & TIOCM_DTR) {
367		ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1);
368		if (ret)
369			return ret;
370		if (tty->secondary_channel_idx != -1) {
371			ret = ipwireless_set_DTR(tty->hardware,
372					  tty->secondary_channel_idx, 1);
373			if (ret)
374				return ret;
375		}
376	}
377	if (clear & TIOCM_RTS) {
378		ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0);
379		if (tty->secondary_channel_idx != -1) {
380			ret = ipwireless_set_RTS(tty->hardware,
381					  tty->secondary_channel_idx, 0);
382			if (ret)
383				return ret;
384		}
385	}
386	if (clear & TIOCM_DTR) {
387		ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0);
388		if (tty->secondary_channel_idx != -1) {
389			ret = ipwireless_set_DTR(tty->hardware,
390					  tty->secondary_channel_idx, 0);
391			if (ret)
392				return ret;
393		}
394	}
395	return 0;
396}
397
398static int ipw_tiocmget(struct tty_struct *linux_tty)
399{
400	struct ipw_tty *tty = linux_tty->driver_data;
401	/* FIXME: Exactly how is the tty object locked here .. */
402
403	if (!tty)
404		return -ENODEV;
405
406	if (!tty->open_count)
407		return -EINVAL;
408
409	return get_control_lines(tty);
410}
411
412static int
413ipw_tiocmset(struct tty_struct *linux_tty,
414	     unsigned int set, unsigned int clear)
415{
416	struct ipw_tty *tty = linux_tty->driver_data;
417	/* FIXME: Exactly how is the tty object locked here .. */
418
419	if (!tty)
420		return -ENODEV;
421
422	if (!tty->open_count)
423		return -EINVAL;
424
425	return set_control_lines(tty, set, clear);
426}
427
428static int ipw_ioctl(struct tty_struct *linux_tty,
429		     unsigned int cmd, unsigned long arg)
430{
431	struct ipw_tty *tty = linux_tty->driver_data;
432
433	if (!tty)
434		return -ENODEV;
435
436	if (!tty->open_count)
437		return -EINVAL;
438
439	/* FIXME: Exactly how is the tty object locked here .. */
440
441	switch (cmd) {
442	case TIOCGSERIAL:
443		return ipwireless_get_serial_info(tty, (void __user *) arg);
444
445	case TIOCSSERIAL:
446		return 0;	/* Keeps the PCMCIA scripts happy. */
447	}
448
449	if (tty->tty_type == TTYTYPE_MODEM) {
450		switch (cmd) {
451		case PPPIOCGCHAN:
452			{
453				int chan = ipwireless_ppp_channel_index(
454							tty->network);
455
456				if (chan < 0)
457					return -ENODEV;
458				if (put_user(chan, (int __user *) arg))
459					return -EFAULT;
460			}
461			return 0;
462
463		case PPPIOCGUNIT:
464			{
465				int unit = ipwireless_ppp_unit_number(
466						tty->network);
467
468				if (unit < 0)
469					return -ENODEV;
470				if (put_user(unit, (int __user *) arg))
471					return -EFAULT;
472			}
473			return 0;
474
475		case FIONREAD:
476			{
477				int val = 0;
478
479				if (put_user(val, (int __user *) arg))
480					return -EFAULT;
481			}
482			return 0;
483		case TCFLSH:
484			return tty_perform_flush(linux_tty, arg);
485		}
486	}
487	return -ENOIOCTLCMD;
488}
489
490static int add_tty(int j,
491		    struct ipw_hardware *hardware,
492		    struct ipw_network *network, int channel_idx,
493		    int secondary_channel_idx, int tty_type)
494{
495	ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL);
496	if (!ttys[j])
497		return -ENOMEM;
498	ttys[j]->index = j;
499	ttys[j]->hardware = hardware;
500	ttys[j]->channel_idx = channel_idx;
501	ttys[j]->secondary_channel_idx = secondary_channel_idx;
502	ttys[j]->network = network;
503	ttys[j]->tty_type = tty_type;
504	mutex_init(&ttys[j]->ipw_tty_mutex);
 
505
506	tty_register_device(ipw_tty_driver, j, NULL);
507	ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
508
509	if (secondary_channel_idx != -1)
510		ipwireless_associate_network_tty(network,
511						 secondary_channel_idx,
512						 ttys[j]);
513	if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j])
514		report_registering(ttys[j]);
 
 
 
 
515	return 0;
516}
517
518struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware,
519				      struct ipw_network *network)
520{
521	int i, j;
522
523	for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) {
524		int allfree = 1;
525
526		for (j = i; j < IPWIRELESS_PCMCIA_MINORS;
527				j += IPWIRELESS_PCMCIA_MINOR_RANGE)
528			if (ttys[j] != NULL) {
529				allfree = 0;
530				break;
531			}
532
533		if (allfree) {
534			j = i;
535
536			if (add_tty(j, hardware, network,
537					IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS,
538					TTYTYPE_MODEM))
539				return NULL;
540
541			j += IPWIRELESS_PCMCIA_MINOR_RANGE;
542			if (add_tty(j, hardware, network,
543					IPW_CHANNEL_DIALLER, -1,
544					TTYTYPE_MONITOR))
545				return NULL;
546
547			j += IPWIRELESS_PCMCIA_MINOR_RANGE;
548			if (add_tty(j, hardware, network,
549					IPW_CHANNEL_RAS, -1,
550					TTYTYPE_RAS_RAW))
551				return NULL;
552
553			return ttys[i];
554		}
555	}
556	return NULL;
557}
558
559/*
560 * Must be called before ipwireless_network_free().
561 */
562void ipwireless_tty_free(struct ipw_tty *tty)
563{
564	int j;
565	struct ipw_network *network = ttys[tty->index]->network;
566
567	for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS;
568			j += IPWIRELESS_PCMCIA_MINOR_RANGE) {
569		struct ipw_tty *ttyj = ttys[j];
570
571		if (ttyj) {
572			mutex_lock(&ttyj->ipw_tty_mutex);
573			if (get_tty(j + ipw_tty_driver->minor_start) == ttyj)
574				report_deregistering(ttyj);
 
 
575			ttyj->closing = 1;
576			if (ttyj->linux_tty != NULL) {
577				mutex_unlock(&ttyj->ipw_tty_mutex);
578				tty_hangup(ttyj->linux_tty);
579				/* Wait till the tty_hangup has completed */
580				flush_work_sync(&ttyj->linux_tty->hangup_work);
581				/* FIXME: Exactly how is the tty object locked here
582				   against a parallel ioctl etc */
 
 
583				mutex_lock(&ttyj->ipw_tty_mutex);
584			}
585			while (ttyj->open_count)
586				do_ipw_close(ttyj);
587			ipwireless_disassociate_network_ttys(network,
588							     ttyj->channel_idx);
589			tty_unregister_device(ipw_tty_driver, j);
 
590			ttys[j] = NULL;
591			mutex_unlock(&ttyj->ipw_tty_mutex);
592			kfree(ttyj);
593		}
594	}
595}
596
597static const struct tty_operations tty_ops = {
598	.open = ipw_open,
599	.close = ipw_close,
600	.hangup = ipw_hangup,
601	.write = ipw_write,
602	.write_room = ipw_write_room,
603	.ioctl = ipw_ioctl,
604	.chars_in_buffer = ipw_chars_in_buffer,
605	.tiocmget = ipw_tiocmget,
606	.tiocmset = ipw_tiocmset,
 
 
607};
608
609int ipwireless_tty_init(void)
610{
611	int result;
612
613	ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS);
614	if (!ipw_tty_driver)
615		return -ENOMEM;
616
617	ipw_tty_driver->owner = THIS_MODULE;
618	ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
619	ipw_tty_driver->name = "ttyIPWp";
620	ipw_tty_driver->major = 0;
621	ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START;
622	ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
623	ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL;
624	ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
625	ipw_tty_driver->init_termios = tty_std_termios;
626	ipw_tty_driver->init_termios.c_cflag =
627	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
628	ipw_tty_driver->init_termios.c_ispeed = 9600;
629	ipw_tty_driver->init_termios.c_ospeed = 9600;
630	tty_set_operations(ipw_tty_driver, &tty_ops);
631	result = tty_register_driver(ipw_tty_driver);
632	if (result) {
633		printk(KERN_ERR IPWIRELESS_PCCARD_NAME
634		       ": failed to register tty driver\n");
635		put_tty_driver(ipw_tty_driver);
636		return result;
637	}
638
639	return 0;
640}
641
642void ipwireless_tty_release(void)
643{
644	int ret;
645
646	ret = tty_unregister_driver(ipw_tty_driver);
647	put_tty_driver(ipw_tty_driver);
648	if (ret != 0)
649		printk(KERN_ERR IPWIRELESS_PCCARD_NAME
650			": tty_unregister_driver failed with code %d\n", ret);
651}
652
653int ipwireless_tty_is_modem(struct ipw_tty *tty)
654{
655	return tty->tty_type == TTYTYPE_MODEM;
656}
657
658void
659ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
660					  unsigned int channel_idx,
661					  unsigned int control_lines,
662					  unsigned int changed_mask)
663{
664	unsigned int old_control_lines = tty->control_lines;
665
666	tty->control_lines = (tty->control_lines & ~changed_mask)
667		| (control_lines & changed_mask);
668
669	/*
670	 * If DCD is de-asserted, we close the tty so pppd can tell that we
671	 * have gone offline.
672	 */
673	if ((old_control_lines & IPW_CONTROL_LINE_DCD)
674			&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
675			&& tty->linux_tty) {
676		tty_hangup(tty->linux_tty);
677	}
678}
679
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * IPWireless 3G PCMCIA Network Driver
  4 *
  5 * Original code
  6 *   by Stephen Blackheath <stephen@blacksapphire.com>,
  7 *      Ben Martel <benm@symmetric.co.nz>
  8 *
  9 * Copyrighted as follows:
 10 *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
 11 *
 12 * Various driver changes and rewrites, port to new kernels
 13 *   Copyright (C) 2006-2007 Jiri Kosina
 14 *
 15 * Misc code cleanups and updates
 16 *   Copyright (C) 2007 David Sterba
 17 */
 18
 
 19#include <linux/kernel.h>
 20#include <linux/module.h>
 21#include <linux/mutex.h>
 22#include <linux/ppp_defs.h>
 23#include <linux/if.h>
 24#include <linux/ppp-ioctl.h>
 25#include <linux/sched.h>
 26#include <linux/serial.h>
 27#include <linux/slab.h>
 28#include <linux/tty.h>
 29#include <linux/tty_driver.h>
 30#include <linux/tty_flip.h>
 31#include <linux/uaccess.h>
 32
 33#include "tty.h"
 34#include "network.h"
 35#include "hardware.h"
 36#include "main.h"
 37
 38#define IPWIRELESS_PCMCIA_START 	(0)
 39#define IPWIRELESS_PCMCIA_MINORS	(24)
 40#define IPWIRELESS_PCMCIA_MINOR_RANGE	(8)
 41
 42#define TTYTYPE_MODEM    (0)
 43#define TTYTYPE_MONITOR  (1)
 44#define TTYTYPE_RAS_RAW  (2)
 45
 46struct ipw_tty {
 47	struct tty_port port;
 48	int index;
 49	struct ipw_hardware *hardware;
 50	unsigned int channel_idx;
 51	unsigned int secondary_channel_idx;
 52	int tty_type;
 53	struct ipw_network *network;
 
 
 54	unsigned int control_lines;
 55	struct mutex ipw_tty_mutex;
 56	int tx_bytes_queued;
 57	int closing;
 58};
 59
 60static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS];
 61
 62static struct tty_driver *ipw_tty_driver;
 63
 64static char *tty_type_name(int tty_type)
 65{
 66	static char *channel_names[] = {
 67		"modem",
 68		"monitor",
 69		"RAS-raw"
 70	};
 71
 72	return channel_names[tty_type];
 73}
 74
 75static struct ipw_tty *get_tty(int index)
 76{
 77	/*
 78	 * The 'ras_raw' channel is only available when 'loopback' mode
 79	 * is enabled.
 80	 * Number of minor starts with 16 (_RANGE * _RAS_RAW).
 81	 */
 82	if (!ipwireless_loopback && index >=
 83			 IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
 
 
 
 
 
 
 
 
 
 
 
 
 
 84		return NULL;
 
 
 
 
 
 
 
 
 
 
 
 
 85
 86	return ttys[index];
 
 87}
 88
 89static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
 90{
 91	struct ipw_tty *tty = get_tty(linux_tty->index);
 
 92
 93	if (!tty)
 94		return -ENODEV;
 95
 96	mutex_lock(&tty->ipw_tty_mutex);
 97	if (tty->port.count == 0)
 
 
 
 
 
 98		tty->tx_bytes_queued = 0;
 99
100	tty->port.count++;
101
102	tty->port.tty = linux_tty;
103	linux_tty->driver_data = tty;
104	tty->port.low_latency = 1;
105
106	if (tty->tty_type == TTYTYPE_MODEM)
107		ipwireless_ppp_open(tty->network);
108
109	mutex_unlock(&tty->ipw_tty_mutex);
110
111	return 0;
112}
113
114static void do_ipw_close(struct ipw_tty *tty)
115{
116	tty->port.count--;
117
118	if (tty->port.count == 0) {
119		struct tty_struct *linux_tty = tty->port.tty;
120
121		if (linux_tty != NULL) {
122			tty->port.tty = NULL;
123			linux_tty->driver_data = NULL;
124
125			if (tty->tty_type == TTYTYPE_MODEM)
126				ipwireless_ppp_close(tty->network);
127		}
128	}
129}
130
131static void ipw_hangup(struct tty_struct *linux_tty)
132{
133	struct ipw_tty *tty = linux_tty->driver_data;
134
135	if (!tty)
136		return;
137
138	mutex_lock(&tty->ipw_tty_mutex);
139	if (tty->port.count == 0) {
140		mutex_unlock(&tty->ipw_tty_mutex);
141		return;
142	}
143
144	do_ipw_close(tty);
145
146	mutex_unlock(&tty->ipw_tty_mutex);
147}
148
149static void ipw_close(struct tty_struct *linux_tty, struct file *filp)
150{
151	ipw_hangup(linux_tty);
152}
153
154/* Take data received from hardware, and send it out the tty */
155void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
156			unsigned int length)
157{
 
158	int work = 0;
159
160	mutex_lock(&tty->ipw_tty_mutex);
 
 
 
 
 
161
162	if (!tty->port.count) {
163		mutex_unlock(&tty->ipw_tty_mutex);
164		return;
165	}
166	mutex_unlock(&tty->ipw_tty_mutex);
167
168	work = tty_insert_flip_string(&tty->port, data, length);
169
170	if (work != length)
171		printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
172				": %d chars not inserted to flip buffer!\n",
173				length - work);
174
 
 
 
175	if (work)
176		tty_flip_buffer_push(&tty->port);
177}
178
179static void ipw_write_packet_sent_callback(void *callback_data,
180					   unsigned int packet_length)
181{
182	struct ipw_tty *tty = callback_data;
183
184	/*
185	 * Packet has been sent, so we subtract the number of bytes from our
186	 * tally of outstanding TX bytes.
187	 */
188	tty->tx_bytes_queued -= packet_length;
189}
190
191static int ipw_write(struct tty_struct *linux_tty,
192		     const unsigned char *buf, int count)
193{
194	struct ipw_tty *tty = linux_tty->driver_data;
195	int room, ret;
196
197	if (!tty)
198		return -ENODEV;
199
200	mutex_lock(&tty->ipw_tty_mutex);
201	if (!tty->port.count) {
202		mutex_unlock(&tty->ipw_tty_mutex);
203		return -EINVAL;
204	}
205
206	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
207	if (room < 0)
208		room = 0;
209	/* Don't allow caller to write any more than we have room for */
210	if (count > room)
211		count = room;
212
213	if (count == 0) {
214		mutex_unlock(&tty->ipw_tty_mutex);
215		return 0;
216	}
217
218	ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS,
219			       buf, count,
220			       ipw_write_packet_sent_callback, tty);
221	if (ret == -1) {
222		mutex_unlock(&tty->ipw_tty_mutex);
223		return 0;
224	}
225
226	tty->tx_bytes_queued += count;
227	mutex_unlock(&tty->ipw_tty_mutex);
228
229	return count;
230}
231
232static int ipw_write_room(struct tty_struct *linux_tty)
233{
234	struct ipw_tty *tty = linux_tty->driver_data;
235	int room;
236
237	/* FIXME: Exactly how is the tty object locked here .. */
238	if (!tty)
239		return -ENODEV;
240
241	if (!tty->port.count)
242		return -EINVAL;
243
244	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
245	if (room < 0)
246		room = 0;
247
248	return room;
249}
250
251static int ipwireless_get_serial_info(struct tty_struct *linux_tty,
252				      struct serial_struct *ss)
253{
254	struct ipw_tty *tty = linux_tty->driver_data;
255
256	if (!tty)
257		return -ENODEV;
258
259	if (!tty->port.count)
260		return -EINVAL;
 
 
 
 
 
 
 
 
 
 
 
261
262	ss->type = PORT_UNKNOWN;
263	ss->line = tty->index;
264	ss->baud_base = 115200;
265	return 0;
266}
267
268static int ipwireless_set_serial_info(struct tty_struct *linux_tty,
269				      struct serial_struct *ss)
270{
271	return 0;	/* Keeps the PCMCIA scripts happy. */
272}
273
274static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
275{
276	struct ipw_tty *tty = linux_tty->driver_data;
277
278	if (!tty)
279		return 0;
280
281	if (!tty->port.count)
282		return 0;
283
284	return tty->tx_bytes_queued;
285}
286
287static int get_control_lines(struct ipw_tty *tty)
288{
289	unsigned int my = tty->control_lines;
290	unsigned int out = 0;
291
292	if (my & IPW_CONTROL_LINE_RTS)
293		out |= TIOCM_RTS;
294	if (my & IPW_CONTROL_LINE_DTR)
295		out |= TIOCM_DTR;
296	if (my & IPW_CONTROL_LINE_CTS)
297		out |= TIOCM_CTS;
298	if (my & IPW_CONTROL_LINE_DSR)
299		out |= TIOCM_DSR;
300	if (my & IPW_CONTROL_LINE_DCD)
301		out |= TIOCM_CD;
302
303	return out;
304}
305
306static int set_control_lines(struct ipw_tty *tty, unsigned int set,
307			     unsigned int clear)
308{
309	int ret;
310
311	if (set & TIOCM_RTS) {
312		ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1);
313		if (ret)
314			return ret;
315		if (tty->secondary_channel_idx != -1) {
316			ret = ipwireless_set_RTS(tty->hardware,
317					  tty->secondary_channel_idx, 1);
318			if (ret)
319				return ret;
320		}
321	}
322	if (set & TIOCM_DTR) {
323		ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1);
324		if (ret)
325			return ret;
326		if (tty->secondary_channel_idx != -1) {
327			ret = ipwireless_set_DTR(tty->hardware,
328					  tty->secondary_channel_idx, 1);
329			if (ret)
330				return ret;
331		}
332	}
333	if (clear & TIOCM_RTS) {
334		ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0);
335		if (tty->secondary_channel_idx != -1) {
336			ret = ipwireless_set_RTS(tty->hardware,
337					  tty->secondary_channel_idx, 0);
338			if (ret)
339				return ret;
340		}
341	}
342	if (clear & TIOCM_DTR) {
343		ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0);
344		if (tty->secondary_channel_idx != -1) {
345			ret = ipwireless_set_DTR(tty->hardware,
346					  tty->secondary_channel_idx, 0);
347			if (ret)
348				return ret;
349		}
350	}
351	return 0;
352}
353
354static int ipw_tiocmget(struct tty_struct *linux_tty)
355{
356	struct ipw_tty *tty = linux_tty->driver_data;
357	/* FIXME: Exactly how is the tty object locked here .. */
358
359	if (!tty)
360		return -ENODEV;
361
362	if (!tty->port.count)
363		return -EINVAL;
364
365	return get_control_lines(tty);
366}
367
368static int
369ipw_tiocmset(struct tty_struct *linux_tty,
370	     unsigned int set, unsigned int clear)
371{
372	struct ipw_tty *tty = linux_tty->driver_data;
373	/* FIXME: Exactly how is the tty object locked here .. */
374
375	if (!tty)
376		return -ENODEV;
377
378	if (!tty->port.count)
379		return -EINVAL;
380
381	return set_control_lines(tty, set, clear);
382}
383
384static int ipw_ioctl(struct tty_struct *linux_tty,
385		     unsigned int cmd, unsigned long arg)
386{
387	struct ipw_tty *tty = linux_tty->driver_data;
388
389	if (!tty)
390		return -ENODEV;
391
392	if (!tty->port.count)
393		return -EINVAL;
394
395	/* FIXME: Exactly how is the tty object locked here .. */
 
 
 
 
 
 
 
 
 
396	if (tty->tty_type == TTYTYPE_MODEM) {
397		switch (cmd) {
398		case PPPIOCGCHAN:
399			{
400				int chan = ipwireless_ppp_channel_index(
401							tty->network);
402
403				if (chan < 0)
404					return -ENODEV;
405				if (put_user(chan, (int __user *) arg))
406					return -EFAULT;
407			}
408			return 0;
409
410		case PPPIOCGUNIT:
411			{
412				int unit = ipwireless_ppp_unit_number(
413						tty->network);
414
415				if (unit < 0)
416					return -ENODEV;
417				if (put_user(unit, (int __user *) arg))
418					return -EFAULT;
419			}
420			return 0;
421
422		case FIONREAD:
423			{
424				int val = 0;
425
426				if (put_user(val, (int __user *) arg))
427					return -EFAULT;
428			}
429			return 0;
430		case TCFLSH:
431			return tty_perform_flush(linux_tty, arg);
432		}
433	}
434	return -ENOIOCTLCMD;
435}
436
437static int add_tty(int j,
438		    struct ipw_hardware *hardware,
439		    struct ipw_network *network, int channel_idx,
440		    int secondary_channel_idx, int tty_type)
441{
442	ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL);
443	if (!ttys[j])
444		return -ENOMEM;
445	ttys[j]->index = j;
446	ttys[j]->hardware = hardware;
447	ttys[j]->channel_idx = channel_idx;
448	ttys[j]->secondary_channel_idx = secondary_channel_idx;
449	ttys[j]->network = network;
450	ttys[j]->tty_type = tty_type;
451	mutex_init(&ttys[j]->ipw_tty_mutex);
452	tty_port_init(&ttys[j]->port);
453
454	tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL);
455	ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
456
457	if (secondary_channel_idx != -1)
458		ipwireless_associate_network_tty(network,
459						 secondary_channel_idx,
460						 ttys[j]);
461	/* check if we provide raw device (if loopback is enabled) */
462	if (get_tty(j))
463		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
464		       ": registering %s device ttyIPWp%d\n",
465		       tty_type_name(tty_type), j);
466
467	return 0;
468}
469
470struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware,
471				      struct ipw_network *network)
472{
473	int i, j;
474
475	for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) {
476		int allfree = 1;
477
478		for (j = i; j < IPWIRELESS_PCMCIA_MINORS;
479				j += IPWIRELESS_PCMCIA_MINOR_RANGE)
480			if (ttys[j] != NULL) {
481				allfree = 0;
482				break;
483			}
484
485		if (allfree) {
486			j = i;
487
488			if (add_tty(j, hardware, network,
489					IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS,
490					TTYTYPE_MODEM))
491				return NULL;
492
493			j += IPWIRELESS_PCMCIA_MINOR_RANGE;
494			if (add_tty(j, hardware, network,
495					IPW_CHANNEL_DIALLER, -1,
496					TTYTYPE_MONITOR))
497				return NULL;
498
499			j += IPWIRELESS_PCMCIA_MINOR_RANGE;
500			if (add_tty(j, hardware, network,
501					IPW_CHANNEL_RAS, -1,
502					TTYTYPE_RAS_RAW))
503				return NULL;
504
505			return ttys[i];
506		}
507	}
508	return NULL;
509}
510
511/*
512 * Must be called before ipwireless_network_free().
513 */
514void ipwireless_tty_free(struct ipw_tty *tty)
515{
516	int j;
517	struct ipw_network *network = ttys[tty->index]->network;
518
519	for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS;
520			j += IPWIRELESS_PCMCIA_MINOR_RANGE) {
521		struct ipw_tty *ttyj = ttys[j];
522
523		if (ttyj) {
524			mutex_lock(&ttyj->ipw_tty_mutex);
525			if (get_tty(j))
526				printk(KERN_INFO IPWIRELESS_PCCARD_NAME
527				       ": deregistering %s device ttyIPWp%d\n",
528				       tty_type_name(ttyj->tty_type), j);
529			ttyj->closing = 1;
530			if (ttyj->port.tty != NULL) {
531				mutex_unlock(&ttyj->ipw_tty_mutex);
532				tty_vhangup(ttyj->port.tty);
 
 
533				/* FIXME: Exactly how is the tty object locked here
534				   against a parallel ioctl etc */
535				/* FIXME2: hangup does not mean all processes
536				 * are gone */
537				mutex_lock(&ttyj->ipw_tty_mutex);
538			}
539			while (ttyj->port.count)
540				do_ipw_close(ttyj);
541			ipwireless_disassociate_network_ttys(network,
542							     ttyj->channel_idx);
543			tty_unregister_device(ipw_tty_driver, j);
544			tty_port_destroy(&ttyj->port);
545			ttys[j] = NULL;
546			mutex_unlock(&ttyj->ipw_tty_mutex);
547			kfree(ttyj);
548		}
549	}
550}
551
552static const struct tty_operations tty_ops = {
553	.open = ipw_open,
554	.close = ipw_close,
555	.hangup = ipw_hangup,
556	.write = ipw_write,
557	.write_room = ipw_write_room,
558	.ioctl = ipw_ioctl,
559	.chars_in_buffer = ipw_chars_in_buffer,
560	.tiocmget = ipw_tiocmget,
561	.tiocmset = ipw_tiocmset,
562	.set_serial = ipwireless_set_serial_info,
563	.get_serial = ipwireless_get_serial_info,
564};
565
566int ipwireless_tty_init(void)
567{
568	int result;
569
570	ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS);
571	if (!ipw_tty_driver)
572		return -ENOMEM;
573
 
574	ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
575	ipw_tty_driver->name = "ttyIPWp";
576	ipw_tty_driver->major = 0;
577	ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START;
578	ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
579	ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL;
580	ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
581	ipw_tty_driver->init_termios = tty_std_termios;
582	ipw_tty_driver->init_termios.c_cflag =
583	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
584	ipw_tty_driver->init_termios.c_ispeed = 9600;
585	ipw_tty_driver->init_termios.c_ospeed = 9600;
586	tty_set_operations(ipw_tty_driver, &tty_ops);
587	result = tty_register_driver(ipw_tty_driver);
588	if (result) {
589		printk(KERN_ERR IPWIRELESS_PCCARD_NAME
590		       ": failed to register tty driver\n");
591		put_tty_driver(ipw_tty_driver);
592		return result;
593	}
594
595	return 0;
596}
597
598void ipwireless_tty_release(void)
599{
600	int ret;
601
602	ret = tty_unregister_driver(ipw_tty_driver);
603	put_tty_driver(ipw_tty_driver);
604	if (ret != 0)
605		printk(KERN_ERR IPWIRELESS_PCCARD_NAME
606			": tty_unregister_driver failed with code %d\n", ret);
607}
608
609int ipwireless_tty_is_modem(struct ipw_tty *tty)
610{
611	return tty->tty_type == TTYTYPE_MODEM;
612}
613
614void
615ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
616					  unsigned int channel_idx,
617					  unsigned int control_lines,
618					  unsigned int changed_mask)
619{
620	unsigned int old_control_lines = tty->control_lines;
621
622	tty->control_lines = (tty->control_lines & ~changed_mask)
623		| (control_lines & changed_mask);
624
625	/*
626	 * If DCD is de-asserted, we close the tty so pppd can tell that we
627	 * have gone offline.
628	 */
629	if ((old_control_lines & IPW_CONTROL_LINE_DCD)
630			&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
631			&& tty->port.tty) {
632		tty_hangup(tty->port.tty);
633	}
634}
635