⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irnet_irda.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *	IrNET protocol module : Synchronous PPP over an IrDA socket. * *		Jean II - HPL `00 - <jt@hpl.hp.com> * * This file implement the IRDA interface of IrNET. * Basically, we sit on top of IrTTP. We set up IrTTP, IrIAS properly, * and exchange frames with IrTTP. */#include "irnet_irda.h"		/* Private header *//************************* CONTROL CHANNEL *************************//* * When ppp is not active, /dev/irnet act as a control channel. * Writting allow to set up the IrDA destination of the IrNET channel, * and any application may be read events happening on IrNET... *//*------------------------------------------------------------------*//* * Post an event to the control channel... * Put the event in the log, and then wait all process blocked on read * so they can read the log... */static voidirnet_post_event(irnet_socket *	ap,		 irnet_event	event,		 __u32		saddr,		 __u32		daddr,		 char *		name){  unsigned long		flags;		/* For spinlock */  int			index;		/* In the log */  DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, daddr=%08x, name=``%s'')\n",	 (unsigned int) ap, event, daddr, name);  /* Protect this section via spinlock.   * Note : as we are the only event producer, we only need to exclude   * ourself when touching the log, which is nice and easy.   */  spin_lock_irqsave(&irnet_events.spinlock, flags);  /* Copy the event in the log */  index = irnet_events.index;  irnet_events.log[index].event = event;  irnet_events.log[index].daddr = daddr;  irnet_events.log[index].saddr = saddr;  /* Try to copy IrDA nickname */  if(name)    strcpy(irnet_events.log[index].name, name);  else    irnet_events.log[index].name[0] = '\0';  /* Try to get ppp unit number */  if((ap != (irnet_socket *) NULL) && (ap->ppp_open))    irnet_events.log[index].unit = ppp_unit_number(&ap->chan);  else    irnet_events.log[index].unit = -1;  /* Increment the index   * Note that we increment the index only after the event is written,   * to make sure that the readers don't get garbage... */  irnet_events.index = (index + 1) % IRNET_MAX_EVENTS;  DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index);  /* Spin lock end */  spin_unlock_irqrestore(&irnet_events.spinlock, flags);  /* Now : wake up everybody waiting for events... */  wake_up_interruptible_all(&irnet_events.rwait);  DEXIT(CTRL_TRACE, "\n");}/************************* IRDA SUBROUTINES *************************//* * These are a bunch of subroutines called from other functions * down there, mostly common code or to improve readability... * * Note : we duplicate quite heavily some routines of af_irda.c, * because our input structure (self) is quite different * (struct irnet instead of struct irda_sock), which make sharing * the same code impossible (at least, without templates). *//*------------------------------------------------------------------*//* * Function irda_open_tsap (self) * *    Open local Transport Service Access Point (TSAP) * * Create a IrTTP instance for us and set all the IrTTP callbacks. */static inline intirnet_open_tsap(irnet_socket *	self){  notify_t	notify;		/* Callback structure */  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n");  /* Initialize IrTTP callbacks to be used by the IrDA stack */  irda_notify_init(&notify);  notify.connect_confirm	= irnet_connect_confirm;  notify.connect_indication	= irnet_connect_indication;  notify.disconnect_indication	= irnet_disconnect_indication;  notify.data_indication	= irnet_data_indication;  /*notify.udata_indication	= NULL;*/  notify.flow_indication	= irnet_flow_indication;  notify.status_indication	= irnet_status_indication;  notify.instance		= self;  strncpy(notify.name, IRNET_NOTIFY_NAME, NOTIFY_MAX_NAME);  /* Open an IrTTP instance */  self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,			       &notify);	  DABORT(self->tsap == NULL, -ENOMEM,	 IRDA_SR_ERROR, "Unable to allocate TSAP !\n");  /* Remember which TSAP selector we actually got */  self->stsap_sel = self->tsap->stsap_sel;  DEXIT(IRDA_SR_TRACE, " - tsap=0x%X, sel=0x%X\n",	(unsigned int) self->tsap, self->stsap_sel);  return 0;}/*------------------------------------------------------------------*//* * Function irnet_ias_to_tsap (self, result, value) * *    Examine an IAS object and extract TSAP * * We do an IAP query to find the TSAP associated with the IrNET service. * When IrIAP pass us the result of the query, this function look at * the return values to check for failures and extract the TSAP if * possible. * Also deallocate value * The failure is in self->errno * Return TSAP or -1 */static inline __u8irnet_ias_to_tsap(irnet_socket *	self,		  int			result,		  struct ias_value *	value){  __u8	dtsap_sel = 0;		/* TSAP we are looking for */  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* By default, no error */  self->errno = 0;  /* Check if request succeeded */  switch(result)    {      /* Standard errors : service not available */    case IAS_CLASS_UNKNOWN:    case IAS_ATTRIB_UNKNOWN:      DEBUG(IRDA_SR_INFO, "IAS object doesn't exist ! (%d)\n", result);      self->errno = -EADDRNOTAVAIL;      break;      /* Other errors, most likely IrDA stack failure */    default :      DEBUG(IRDA_SR_INFO, "IAS query failed ! (%d)\n", result);      self->errno = -EHOSTUNREACH;      break;      /* Success : we got what we wanted */    case IAS_SUCCESS:      break;    }  /* Check what was returned to us */  if(value != NULL)    {      /* What type of argument have we got ? */      switch(value->type)	{	case IAS_INTEGER:	  DEBUG(IRDA_SR_INFO, "result=%d\n", value->t.integer);	  if(value->t.integer != -1)	    /* Get the remote TSAP selector */	    dtsap_sel = value->t.integer;	  else 	    self->errno = -EADDRNOTAVAIL;	  break;	default:	  self->errno = -EADDRNOTAVAIL;	  DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", value->type);	  break;	}      /* Cleanup */      irias_delete_value(value);    }  else	/* value == NULL */    {      /* Nothing returned to us - usually result != SUCCESS */      if(!(self->errno))	{	  DERROR(IRDA_SR_ERROR,		 "IrDA bug : result == SUCCESS && value == NULL\n");	  self->errno = -EHOSTUNREACH;	}    }  DEXIT(IRDA_SR_TRACE, "\n");  /* Return the TSAP */  return(dtsap_sel);}/*------------------------------------------------------------------*//* * Function irnet_find_lsap_sel (self) * *    Try to lookup LSAP selector in remote LM-IAS * * Basically, we start a IAP query, and then go to sleep. When the query * return, irnet_getvalue_confirm will wake us up, and we can examine the * result of the query... * Note that in some case, the query fail even before we go to sleep, * creating some races... */static inline intirnet_find_lsap_sel(irnet_socket *	self){  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* This should not happen */  DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n");  /* Create an IAP instance, will be closed in irnet_getvalue_confirm() */  self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,			   irnet_getvalue_confirm);  /* Treat unexpected signals as disconnect */  self->errno = -EHOSTUNREACH;  /* Query remote LM-IAS */  iriap_getvaluebyclass_request(self->iriap, self->rsaddr, self->daddr,				IRNET_SERVICE_NAME, IRNET_IAS_VALUE);  /* The above request is non-blocking.   * After a while, IrDA will call us back in irnet_getvalue_confirm()   * We will then call irnet_ias_to_tsap() and finish the   * connection procedure */  DEXIT(IRDA_SR_TRACE, "\n");  return 0;}/*------------------------------------------------------------------*//* * Function irnet_connect_tsap (self) * *    Initialise the TTP socket and initiate TTP connection * */static inline intirnet_connect_tsap(irnet_socket *	self){  int		err;  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* Open a local TSAP (an IrTTP instance) */  err = irnet_open_tsap(self);  if(err != 0)    {      clear_bit(0, &self->ttp_connect);      DERROR(IRDA_SR_ERROR, "connect aborted!\n");      return(err);    }  /* Connect to remote device */  err = irttp_connect_request(self->tsap, self->dtsap_sel, 			      self->rsaddr, self->daddr, NULL, 			      self->max_sdu_size_rx, NULL);  if(err != 0)    {      clear_bit(0, &self->ttp_connect);      DERROR(IRDA_SR_ERROR, "connect aborted!\n");      return(err);    }  /* The above call is non-blocking.   * After a while, the IrDA stack will either call us back in   * irnet_connect_confirm() or irnet_disconnect_indication()   * See you there ;-) */  DEXIT(IRDA_SR_TRACE, "\n");  return(err);}/*------------------------------------------------------------------*//* * Function irnet_discover_next_daddr (self) * *    Query the IrNET TSAP of the next device in the log. * * Used in the TSAP discovery procedure. */static inline intirnet_discover_next_daddr(irnet_socket *	self){  /* Close the last instance of IrIAP, and open a new one.   * We can't reuse the IrIAP instance in the IrIAP callback */  if(self->iriap)    {      iriap_close(self->iriap);      self->iriap = NULL;    }  /* Create a new IAP instance */  self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,			   irnet_discovervalue_confirm);  /* Next discovery - before the call to avoid races */  self->disco_index++;  /* Check if we have one more address to try */  if(self->disco_index < self->disco_number)    {      /* Query remote LM-IAS */      iriap_getvaluebyclass_request(self->iriap,				    self->discoveries[self->disco_index].saddr,				    self->discoveries[self->disco_index].daddr,				    IRNET_SERVICE_NAME, IRNET_IAS_VALUE);      /* The above request is non-blocking.       * After a while, IrDA will call us back in irnet_discovervalue_confirm()       * We will then call irnet_ias_to_tsap() and come back here again... */      return(0);    }  else    return(1);}/*------------------------------------------------------------------*//* * Function irnet_discover_daddr_and_lsap_sel (self) * *    This try to find a device with the requested service. * * Initiate a TSAP discovery procedure. * It basically look into the discovery log. For each address in the list, * it queries the LM-IAS of the device to find if this device offer * the requested service. * If there is more than one node supporting the service, we complain * to the user (it should move devices around). * If we find one node which have the requested TSAP, we connect to it. * * This function just start the whole procedure. It request the discovery * log and submit the first IAS query. * The bulk of the job is handled in irnet_discovervalue_confirm() * * Note : this procedure fails if there is more than one device in range * on the same dongle, because IrLMP doesn't disconnect the LAP when the * last LSAP is closed. Moreover, we would need to wait the LAP * disconnection... */static inline intirnet_discover_daddr_and_lsap_sel(irnet_socket *	self){  int	ret;  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* Ask lmp for the current discovery log */  self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask,					    DISCOVERY_DEFAULT_SLOTS);  /* Check if the we got some results */  if(self->discoveries == NULL)    {      self->disco_number = -1;      clear_bit(0, &self->ttp_connect);      DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n");    }  DEBUG(IRDA_SR_INFO, "Got the log (0x%X), size is %d\n",	(unsigned int) self->discoveries, self->disco_number);  /* Start with the first discovery */  self->disco_index = -1;  self->daddr = DEV_ADDR_ANY;  /* This will fail if the log is empty - this is non-blocking */  ret = irnet_discover_next_daddr(self);  if(ret)    {      /* Close IAP */      iriap_close(self->iriap);      self->iriap = NULL;      /* Cleanup our copy of the discovery log */      kfree(self->discoveries);      self->discoveries = NULL;      clear_bit(0, &self->ttp_connect);      DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");    }  /* Follow me in irnet_discovervalue_confirm() */  DEXIT(IRDA_SR_TRACE, "\n");  return(0);}/*------------------------------------------------------------------*//* * Function irnet_dname_to_daddr (self) * *    Convert an IrDA nickname to a valid IrDA address * * It basically look into the discovery log until there is a match. */static inline intirnet_dname_to_daddr(irnet_socket *	self){  struct irda_device_info *discoveries;	/* Copy of the discovery log */  int	number;			/* Number of nodes in the log */  int	i;  DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);  /* Ask lmp for the current discovery log */  discoveries = irlmp_get_discoveries(&number, 0xffff,				      DISCOVERY_DEFAULT_SLOTS);  /* Check if the we got some results */  if(discoveries == NULL)    DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");  /*    * Now, check all discovered devices (if any), and connect   * client only about the services that the client is   * interested in...   */  for(i = 0; i < number; i++)    {      /* Does the name match ? */      if(!strncmp(discoveries[i].info, self->rname, NICKNAME_MAX_LEN))	{	  /* Yes !!! Get it.. */	  self->daddr = discoveries[i].daddr;	  DEBUG(IRDA_SR_INFO, "discovered device ``%s'' at address 0x%08x.\n",		self->rname, self->daddr);	  kfree(discoveries);	  DEXIT(IRDA_SR_TRACE, "\n");	  return 0;	}    }  /* No luck ! */  DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname);  kfree(discoveries);  return(-EADDRNOTAVAIL);}/************************* SOCKET ROUTINES *************************//* * This are the main operations on IrNET sockets, basically to create * and destroy IrNET sockets. These are called from the PPP part... */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -