| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /********************************************************************* | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 2 |  * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3 |  * Filename:      discovery.c | 
 | 4 |  * Version:       0.1 | 
 | 5 |  * Description:   Routines for handling discoveries at the IrLMP layer | 
 | 6 |  * Status:        Experimental. | 
 | 7 |  * Author:        Dag Brattli <dagb@cs.uit.no> | 
 | 8 |  * Created at:    Tue Apr  6 15:33:50 1999 | 
 | 9 |  * Modified at:   Sat Oct  9 17:11:31 1999 | 
 | 10 |  * Modified by:   Dag Brattli <dagb@cs.uit.no> | 
 | 11 |  * Modified at:   Fri May 28  3:11 CST 1999 | 
 | 12 |  * Modified by:   Horst von Brand <vonbrand@sleipnir.valparaiso.cl> | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 13 |  * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 |  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved. | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 15 |  * | 
 | 16 |  *     This program is free software; you can redistribute it and/or | 
 | 17 |  *     modify it under the terms of the GNU General Public License as | 
 | 18 |  *     published by the Free Software Foundation; either version 2 of | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 |  *     the License, or (at your option) any later version. | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 20 |  * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 |  *     This program is distributed in the hope that it will be useful, | 
 | 22 |  *     but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 23 |  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
 | 24 |  *     GNU General Public License for more details. | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 25 |  * | 
 | 26 |  *     You should have received a copy of the GNU General Public License | 
 | 27 |  *     along with this program; if not, write to the Free Software | 
 | 28 |  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 |  *     MA 02111-1307 USA | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 30 |  * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 |  ********************************************************************/ | 
 | 32 |  | 
 | 33 | #include <linux/string.h> | 
 | 34 | #include <linux/socket.h> | 
| Al Viro | d7fe0f2 | 2006-12-03 23:15:30 -0500 | [diff] [blame] | 35 | #include <linux/fs.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 | #include <linux/seq_file.h> | 
 | 37 |  | 
 | 38 | #include <net/irda/irda.h> | 
 | 39 | #include <net/irda/irlmp.h> | 
 | 40 |  | 
 | 41 | #include <net/irda/discovery.h> | 
 | 42 |  | 
 | 43 | /* | 
 | 44 |  * Function irlmp_add_discovery (cachelog, discovery) | 
 | 45 |  * | 
 | 46 |  *    Add a new discovery to the cachelog, and remove any old discoveries | 
 | 47 |  *    from the same device | 
 | 48 |  * | 
 | 49 |  * Note : we try to preserve the time this device was *first* discovered | 
 | 50 |  * (as opposed to the time of last discovery used for cleanup). This is | 
 | 51 |  * used by clients waiting for discovery events to tell if the device | 
 | 52 |  * discovered is "new" or just the same old one. They can't rely there | 
 | 53 |  * on a binary flag (new/old), because not all discovery events are | 
 | 54 |  * propagated to them, and they might not always listen, so they would | 
 | 55 |  * miss some new devices popping up... | 
 | 56 |  * Jean II | 
 | 57 |  */ | 
 | 58 | void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new) | 
 | 59 | { | 
 | 60 | 	discovery_t *discovery, *node; | 
 | 61 | 	unsigned long flags; | 
 | 62 |  | 
 | 63 | 	/* Set time of first discovery if node is new (see below) */ | 
 | 64 | 	new->firststamp = new->timestamp; | 
 | 65 |  | 
 | 66 | 	spin_lock_irqsave(&cachelog->hb_spinlock, flags); | 
 | 67 |  | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 68 | 	/* | 
 | 69 | 	 * Remove all discoveries of devices that has previously been | 
 | 70 | 	 * discovered on the same link with the same name (info), or the | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 71 | 	 * same daddr. We do this since some devices (mostly PDAs) change | 
 | 72 | 	 * their device address between every discovery. | 
 | 73 | 	 */ | 
 | 74 | 	discovery = (discovery_t *) hashbin_get_first(cachelog); | 
 | 75 | 	while (discovery != NULL ) { | 
 | 76 | 		node = discovery; | 
 | 77 |  | 
 | 78 | 		/* Be sure to stay one item ahead */ | 
 | 79 | 		discovery = (discovery_t *) hashbin_get_next(cachelog); | 
 | 80 |  | 
 | 81 | 		if ((node->data.saddr == new->data.saddr) && | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 82 | 		    ((node->data.daddr == new->data.daddr) || | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | 		     (strcmp(node->data.info, new->data.info) == 0))) | 
 | 84 | 		{ | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 85 | 			/* This discovery is a previous discovery | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 | 			 * from the same device, so just remove it | 
 | 87 | 			 */ | 
 | 88 | 			hashbin_remove_this(cachelog, (irda_queue_t *) node); | 
 | 89 | 			/* Check if hints bits are unchanged */ | 
 | 90 | 			if(u16ho(node->data.hints) == u16ho(new->data.hints)) | 
 | 91 | 				/* Set time of first discovery for this node */ | 
 | 92 | 				new->firststamp = node->firststamp; | 
 | 93 | 			kfree(node); | 
 | 94 | 		} | 
 | 95 | 	} | 
 | 96 |  | 
 | 97 | 	/* Insert the new and updated version */ | 
 | 98 | 	hashbin_insert(cachelog, (irda_queue_t *) new, new->data.daddr, NULL); | 
 | 99 |  | 
 | 100 | 	spin_unlock_irqrestore(&cachelog->hb_spinlock, flags); | 
 | 101 | } | 
 | 102 |  | 
 | 103 | /* | 
 | 104 |  * Function irlmp_add_discovery_log (cachelog, log) | 
 | 105 |  * | 
 | 106 |  *    Merge a disovery log into the cachelog. | 
 | 107 |  * | 
 | 108 |  */ | 
 | 109 | void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log) | 
 | 110 | { | 
 | 111 | 	discovery_t *discovery; | 
 | 112 |  | 
 | 113 | 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__); | 
 | 114 |  | 
 | 115 | 	/* | 
 | 116 | 	 *  If log is missing this means that IrLAP was unable to perform the | 
 | 117 | 	 *  discovery, so restart discovery again with just the half timeout | 
 | 118 | 	 *  of the normal one. | 
 | 119 | 	 */ | 
 | 120 | 	/* Well... It means that there was nobody out there - Jean II */ | 
 | 121 | 	if (log == NULL) { | 
 | 122 | 		/* irlmp_start_discovery_timer(irlmp, 150); */ | 
 | 123 | 		return; | 
 | 124 | 	} | 
 | 125 |  | 
 | 126 | 	/* | 
 | 127 | 	 * Locking : we are the only owner of this discovery log, so | 
 | 128 | 	 * no need to lock it. | 
 | 129 | 	 * We just need to lock the global log in irlmp_add_discovery(). | 
 | 130 | 	 */ | 
 | 131 | 	discovery = (discovery_t *) hashbin_remove_first(log); | 
 | 132 | 	while (discovery != NULL) { | 
 | 133 | 		irlmp_add_discovery(cachelog, discovery); | 
 | 134 |  | 
 | 135 | 		discovery = (discovery_t *) hashbin_remove_first(log); | 
 | 136 | 	} | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 137 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 | 	/* Delete the now empty log */ | 
 | 139 | 	hashbin_delete(log, (FREE_FUNC) kfree); | 
 | 140 | } | 
 | 141 |  | 
 | 142 | /* | 
 | 143 |  * Function irlmp_expire_discoveries (log, saddr, force) | 
 | 144 |  * | 
 | 145 |  *    Go through all discoveries and expire all that has stayed too long | 
 | 146 |  * | 
 | 147 |  * Note : this assume that IrLAP won't change its saddr, which | 
 | 148 |  * currently is a valid assumption... | 
 | 149 |  */ | 
 | 150 | void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force) | 
 | 151 | { | 
 | 152 | 	discovery_t *		discovery; | 
 | 153 | 	discovery_t *		curr; | 
 | 154 | 	unsigned long		flags; | 
 | 155 | 	discinfo_t *		buffer = NULL; | 
 | 156 | 	int			n;		/* Size of the full log */ | 
 | 157 | 	int			i = 0;		/* How many we expired */ | 
 | 158 |  | 
 | 159 | 	IRDA_ASSERT(log != NULL, return;); | 
 | 160 | 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__); | 
 | 161 |  | 
 | 162 | 	spin_lock_irqsave(&log->hb_spinlock, flags); | 
 | 163 |  | 
 | 164 | 	discovery = (discovery_t *) hashbin_get_first(log); | 
 | 165 | 	while (discovery != NULL) { | 
 | 166 | 		/* Be sure to be one item ahead */ | 
 | 167 | 		curr = discovery; | 
 | 168 | 		discovery = (discovery_t *) hashbin_get_next(log); | 
 | 169 |  | 
 | 170 | 		/* Test if it's time to expire this discovery */ | 
 | 171 | 		if ((curr->data.saddr == saddr) && | 
 | 172 | 		    (force || | 
 | 173 | 		     ((jiffies - curr->timestamp) > DISCOVERY_EXPIRE_TIMEOUT))) | 
 | 174 | 		{ | 
 | 175 | 			/* Create buffer as needed. | 
 | 176 | 			 * As this function get called a lot and most time | 
 | 177 | 			 * we don't have anything to put in the log (we are | 
 | 178 | 			 * quite picky), we can save a lot of overhead | 
 | 179 | 			 * by not calling kmalloc. Jean II */ | 
 | 180 | 			if(buffer == NULL) { | 
 | 181 | 				/* Create the client specific buffer */ | 
 | 182 | 				n = HASHBIN_GET_SIZE(log); | 
 | 183 | 				buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC); | 
 | 184 | 				if (buffer == NULL) { | 
 | 185 | 					spin_unlock_irqrestore(&log->hb_spinlock, flags); | 
 | 186 | 					return; | 
 | 187 | 				} | 
 | 188 |  | 
 | 189 | 			} | 
 | 190 |  | 
 | 191 | 			/* Copy discovery information */ | 
 | 192 | 			memcpy(&(buffer[i]), &(curr->data), | 
 | 193 | 			       sizeof(discinfo_t)); | 
 | 194 | 			i++; | 
 | 195 |  | 
 | 196 | 			/* Remove it from the log */ | 
 | 197 | 			curr = hashbin_remove_this(log, (irda_queue_t *) curr); | 
| Jesper Juhl | a51482b | 2005-11-08 09:41:34 -0800 | [diff] [blame] | 198 | 			kfree(curr); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 199 | 		} | 
 | 200 | 	} | 
 | 201 |  | 
 | 202 | 	/* Drop the spinlock before calling the higher layers, as | 
 | 203 | 	 * we can't guarantee they won't call us back and create a | 
 | 204 | 	 * deadlock. We will work on our own private data, so we | 
| Robert P. J. Day | 3a4fa0a | 2007-10-19 23:10:43 +0200 | [diff] [blame] | 205 | 	 * don't care to be interrupted. - Jean II */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | 	spin_unlock_irqrestore(&log->hb_spinlock, flags); | 
 | 207 |  | 
 | 208 | 	if(buffer == NULL) | 
 | 209 | 		return; | 
 | 210 |  | 
 | 211 | 	/* Tell IrLMP and registered clients about it */ | 
 | 212 | 	irlmp_discovery_expiry(buffer, i); | 
 | 213 |  | 
 | 214 | 	/* Free up our buffer */ | 
 | 215 | 	kfree(buffer); | 
 | 216 | } | 
 | 217 |  | 
 | 218 | #if 0 | 
 | 219 | /* | 
 | 220 |  * Function irlmp_dump_discoveries (log) | 
 | 221 |  * | 
 | 222 |  *    Print out all discoveries in log | 
 | 223 |  * | 
 | 224 |  */ | 
 | 225 | void irlmp_dump_discoveries(hashbin_t *log) | 
 | 226 | { | 
 | 227 | 	discovery_t *discovery; | 
 | 228 |  | 
 | 229 | 	IRDA_ASSERT(log != NULL, return;); | 
 | 230 |  | 
 | 231 | 	discovery = (discovery_t *) hashbin_get_first(log); | 
 | 232 | 	while (discovery != NULL) { | 
 | 233 | 		IRDA_DEBUG(0, "Discovery:\n"); | 
 | 234 | 		IRDA_DEBUG(0, "  daddr=%08x\n", discovery->data.daddr); | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 235 | 		IRDA_DEBUG(0, "  saddr=%08x\n", discovery->data.saddr); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 236 | 		IRDA_DEBUG(0, "  nickname=%s\n", discovery->data.info); | 
 | 237 |  | 
 | 238 | 		discovery = (discovery_t *) hashbin_get_next(log); | 
 | 239 | 	} | 
 | 240 | } | 
 | 241 | #endif | 
 | 242 |  | 
 | 243 | /* | 
 | 244 |  * Function irlmp_copy_discoveries (log, pn, mask) | 
 | 245 |  * | 
 | 246 |  *    Copy all discoveries in a buffer | 
 | 247 |  * | 
 | 248 |  * This function implement a safe way for lmp clients to access the | 
 | 249 |  * discovery log. The basic problem is that we don't want the log | 
 | 250 |  * to change (add/remove) while the client is reading it. If the | 
 | 251 |  * lmp client manipulate directly the hashbin, he is sure to get | 
 | 252 |  * into troubles... | 
 | 253 |  * The idea is that we copy all the current discovery log in a buffer | 
 | 254 |  * which is specific to the client and pass this copy to him. As we | 
 | 255 |  * do this operation with the spinlock grabbed, we are safe... | 
 | 256 |  * Note : we don't want those clients to grab the spinlock, because | 
 | 257 |  * we have no control on how long they will hold it... | 
 | 258 |  * Note : we choose to copy the log in "struct irda_device_info" to | 
 | 259 |  * save space... | 
 | 260 |  * Note : the client must kfree himself() the log... | 
 | 261 |  * Jean II | 
 | 262 |  */ | 
 | 263 | struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, | 
 | 264 | 						__u16 mask, int old_entries) | 
 | 265 | { | 
 | 266 | 	discovery_t *		discovery; | 
 | 267 | 	unsigned long		flags; | 
 | 268 | 	discinfo_t *		buffer = NULL; | 
 | 269 | 	int			j_timeout = (sysctl_discovery_timeout * HZ); | 
 | 270 | 	int			n;		/* Size of the full log */ | 
 | 271 | 	int			i = 0;		/* How many we picked */ | 
 | 272 |  | 
 | 273 | 	IRDA_ASSERT(pn != NULL, return NULL;); | 
 | 274 | 	IRDA_ASSERT(log != NULL, return NULL;); | 
 | 275 |  | 
 | 276 | 	/* Save spin lock */ | 
 | 277 | 	spin_lock_irqsave(&log->hb_spinlock, flags); | 
 | 278 |  | 
 | 279 | 	discovery = (discovery_t *) hashbin_get_first(log); | 
 | 280 | 	while (discovery != NULL) { | 
 | 281 | 		/* Mask out the ones we don't want : | 
 | 282 | 		 * We want to match the discovery mask, and to get only | 
 | 283 | 		 * the most recent one (unless we want old ones) */ | 
 | 284 | 		if ((u16ho(discovery->data.hints) & mask) && | 
 | 285 | 		    ((old_entries) || | 
 | 286 | 		     ((jiffies - discovery->firststamp) < j_timeout)) ) { | 
 | 287 | 			/* Create buffer as needed. | 
 | 288 | 			 * As this function get called a lot and most time | 
 | 289 | 			 * we don't have anything to put in the log (we are | 
 | 290 | 			 * quite picky), we can save a lot of overhead | 
 | 291 | 			 * by not calling kmalloc. Jean II */ | 
 | 292 | 			if(buffer == NULL) { | 
 | 293 | 				/* Create the client specific buffer */ | 
 | 294 | 				n = HASHBIN_GET_SIZE(log); | 
 | 295 | 				buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC); | 
 | 296 | 				if (buffer == NULL) { | 
 | 297 | 					spin_unlock_irqrestore(&log->hb_spinlock, flags); | 
 | 298 | 					return NULL; | 
 | 299 | 				} | 
 | 300 |  | 
 | 301 | 			} | 
 | 302 |  | 
 | 303 | 			/* Copy discovery information */ | 
 | 304 | 			memcpy(&(buffer[i]), &(discovery->data), | 
 | 305 | 			       sizeof(discinfo_t)); | 
 | 306 | 			i++; | 
 | 307 | 		} | 
 | 308 | 		discovery = (discovery_t *) hashbin_get_next(log); | 
 | 309 | 	} | 
 | 310 |  | 
 | 311 | 	spin_unlock_irqrestore(&log->hb_spinlock, flags); | 
 | 312 |  | 
 | 313 | 	/* Get the actual number of device in the buffer and return */ | 
 | 314 | 	*pn = i; | 
 | 315 | 	return(buffer); | 
 | 316 | } | 
 | 317 |  | 
 | 318 | #ifdef CONFIG_PROC_FS | 
 | 319 | static inline discovery_t *discovery_seq_idx(loff_t pos) | 
 | 320 |  | 
 | 321 | { | 
 | 322 | 	discovery_t *discovery; | 
 | 323 |  | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 324 | 	for (discovery = (discovery_t *) hashbin_get_first(irlmp->cachelog); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 325 | 	     discovery != NULL; | 
 | 326 | 	     discovery = (discovery_t *) hashbin_get_next(irlmp->cachelog)) { | 
 | 327 | 		if (pos-- == 0) | 
 | 328 | 			break; | 
 | 329 | 	} | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 330 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 331 | 	return discovery; | 
 | 332 | } | 
 | 333 |  | 
 | 334 | static void *discovery_seq_start(struct seq_file *seq, loff_t *pos) | 
 | 335 | { | 
 | 336 | 	spin_lock_irq(&irlmp->cachelog->hb_spinlock); | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 337 | 	return *pos ? discovery_seq_idx(*pos - 1) : SEQ_START_TOKEN; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 338 | } | 
 | 339 |  | 
 | 340 | static void *discovery_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 
 | 341 | { | 
 | 342 | 	++*pos; | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 343 | 	return (v == SEQ_START_TOKEN) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 344 | 		? (void *) hashbin_get_first(irlmp->cachelog) | 
 | 345 | 		: (void *) hashbin_get_next(irlmp->cachelog); | 
 | 346 | } | 
 | 347 |  | 
 | 348 | static void discovery_seq_stop(struct seq_file *seq, void *v) | 
 | 349 | { | 
 | 350 | 	spin_unlock_irq(&irlmp->cachelog->hb_spinlock); | 
 | 351 | } | 
 | 352 |  | 
 | 353 | static int discovery_seq_show(struct seq_file *seq, void *v) | 
 | 354 | { | 
 | 355 | 	if (v == SEQ_START_TOKEN) | 
 | 356 | 		seq_puts(seq, "IrLMP: Discovery log:\n\n"); | 
 | 357 | 	else { | 
 | 358 | 		const discovery_t *discovery = v; | 
 | 359 |  | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 360 | 		seq_printf(seq, "nickname: %s, hint: 0x%02x%02x", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 361 | 			   discovery->data.info, | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 362 | 			   discovery->data.hints[0], | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 363 | 			   discovery->data.hints[1]); | 
 | 364 | #if 0 | 
 | 365 | 		if ( discovery->data.hints[0] & HINT_PNP) | 
 | 366 | 			seq_puts(seq, "PnP Compatible "); | 
 | 367 | 		if ( discovery->data.hints[0] & HINT_PDA) | 
 | 368 | 			seq_puts(seq, "PDA/Palmtop "); | 
 | 369 | 		if ( discovery->data.hints[0] & HINT_COMPUTER) | 
 | 370 | 			seq_puts(seq, "Computer "); | 
 | 371 | 		if ( discovery->data.hints[0] & HINT_PRINTER) | 
 | 372 | 			seq_puts(seq, "Printer "); | 
 | 373 | 		if ( discovery->data.hints[0] & HINT_MODEM) | 
 | 374 | 			seq_puts(seq, "Modem "); | 
 | 375 | 		if ( discovery->data.hints[0] & HINT_FAX) | 
 | 376 | 			seq_puts(seq, "Fax "); | 
 | 377 | 		if ( discovery->data.hints[0] & HINT_LAN) | 
 | 378 | 			seq_puts(seq, "LAN Access "); | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 379 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 380 | 		if ( discovery->data.hints[1] & HINT_TELEPHONY) | 
 | 381 | 			seq_puts(seq, "Telephony "); | 
 | 382 | 		if ( discovery->data.hints[1] & HINT_FILE_SERVER) | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 383 | 			seq_puts(seq, "File Server "); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 384 | 		if ( discovery->data.hints[1] & HINT_COMM) | 
 | 385 | 			seq_puts(seq, "IrCOMM "); | 
 | 386 | 		if ( discovery->data.hints[1] & HINT_OBEX) | 
 | 387 | 			seq_puts(seq, "IrOBEX "); | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 388 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 389 | 		seq_printf(seq,", saddr: 0x%08x, daddr: 0x%08x\n\n", | 
 | 390 | 			       discovery->data.saddr, | 
 | 391 | 			       discovery->data.daddr); | 
| YOSHIFUJI Hideaki | 6819bc2 | 2007-02-09 23:24:53 +0900 | [diff] [blame] | 392 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 393 | 		seq_putc(seq, '\n'); | 
 | 394 | 	} | 
 | 395 | 	return 0; | 
 | 396 | } | 
 | 397 |  | 
| Philippe De Muyter | 56b3d97 | 2007-07-10 23:07:31 -0700 | [diff] [blame] | 398 | static const struct seq_operations discovery_seq_ops = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 399 | 	.start  = discovery_seq_start, | 
 | 400 | 	.next   = discovery_seq_next, | 
 | 401 | 	.stop   = discovery_seq_stop, | 
 | 402 | 	.show   = discovery_seq_show, | 
 | 403 | }; | 
 | 404 |  | 
 | 405 | static int discovery_seq_open(struct inode *inode, struct file *file) | 
 | 406 | { | 
 | 407 | 	IRDA_ASSERT(irlmp != NULL, return -EINVAL;); | 
 | 408 |  | 
 | 409 | 	return seq_open(file, &discovery_seq_ops); | 
 | 410 | } | 
 | 411 |  | 
| Arjan van de Ven | 9a32144 | 2007-02-12 00:55:35 -0800 | [diff] [blame] | 412 | const struct file_operations discovery_seq_fops = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 413 | 	.owner		= THIS_MODULE, | 
 | 414 | 	.open           = discovery_seq_open, | 
 | 415 | 	.read           = seq_read, | 
 | 416 | 	.llseek         = seq_lseek, | 
 | 417 | 	.release	= seq_release, | 
 | 418 | }; | 
 | 419 | #endif |