示例#1
0
文件: route.c 项目: F0rth/pimd
mrtentry_t *switch_shortest_path(u_int32 source, u_int32 group)
{
    mrtentry_t *mrtentry_ptr;

    /* TODO: XXX: prepare and send immediately the (S,G) join? */
    if ((mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE)) !=
        (mrtentry_t *)NULL) {
        if (mrtentry_ptr->flags & MRTF_NEW) {
            mrtentry_ptr->flags &= ~MRTF_NEW;
        }
        else if (mrtentry_ptr->flags & MRTF_RP) {
            /* (S,G)RPbit with iif toward RP. Reset to (S,G) with iif
             * toward S. Delete the kernel cache (if any), because
             * change_interfaces() will reset it with iif toward S
             * and no data will arrive from RP before the switch
             * really occurs.
             */
            mrtentry_ptr->flags &= ~MRTF_RP;
            mrtentry_ptr->incoming = mrtentry_ptr->source->incoming;
            mrtentry_ptr->upstream = mrtentry_ptr->source->upstream;
            delete_mrtentry_all_kernel_cache(mrtentry_ptr);
            change_interfaces(mrtentry_ptr,
                              mrtentry_ptr->incoming,
                              mrtentry_ptr->joined_oifs,
                              mrtentry_ptr->pruned_oifs,
                              mrtentry_ptr->leaves,
                              mrtentry_ptr->asserted_oifs, 0);
        }

        SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
        FIRE_TIMER(mrtentry_ptr->jp_timer);
    }

    return mrtentry_ptr;
}
示例#2
0
static int
getMcdStatus(int timeout)
{
	int st;

	McdTimeout = timeout;
	SET_TIMER(mcdStatTimer, 1);
	sleep_on(&mcd_waitq);
	if (McdTimeout <= 0)
		return -1;

	st = inb(MCDPORT(0)) & 0xFF;
	if (st == 0xFF)
		return -1;

	if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
		/* XXX might be an error? look at q-channel? */
		audioStatus = CDROM_AUDIO_COMPLETED;

	if (st & MST_DSK_CHG)
	{
		mcdDiskChanged = 1;
		tocUpToDate = 0;
		audioStatus = CDROM_AUDIO_NO_STATUS;
	}

	return st;
}
示例#3
0
void do_pummel( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;

   if (IS_NPC(ch)) return;
   if (!IS_CLASS(ch, CLASS_SKYBLADE) )
   {
     send_to_char("Huh?\n\r",ch);
     return;
   }
   if (ch->pcdata->powers[SKYBLADE_SKILLS] < 2)
   {
     send_to_char("You haven't mastered the skills abilities enough.\n\r",ch);
     return;
   }
   if (!TIME_UP(ch, TIMER_PUMMEL))
   {
     send_to_char("You are too tired from the last time.\n\r",ch);
     return;
   }
   if ((victim = ch->fighting) == NULL)
   {
     send_to_char("You aren't fighting anyone though.\n\r",ch);
     return;
   }
   if (IS_NPC(victim))
   {
      send_to_char("They aren't stanced though.\n\r",ch);
      return;
   }
   SET_TIMER(ch, TIMER_PUMMEL, 5);
   do_stance(victim, "");
   WAIT_STATE(victim,12);
   return;
}
示例#4
0
文件: d4lib.c 项目: lion-simba/reink
static void _flushData(int fd)
{
   int rd    = 0;
   struct itimerval ti, oti;
   char buf[1024];
   int len = 1023;
   int count = 200;
   usleep(d4RdTimeout);

   /* for error handling in case of timeout */
   timeoutGot = 0;

   /* set errno to 0 in order to get correct informations */
   /* in case of error                                    */
   errno = 0;

   if (debugD4)
     fprintf(stderr, "flush data: length: %i\n", len);
   do
     {
       usleep(d4RdTimeout);
       SET_TIMER(ti,oti, d4RdTimeout);
       rd = read(fd, buf, len);
       if (debugD4)
	 fprintf(stderr, "flush: read: %i %s\n", rd,
		 rd < 0 && errno != 0 ?strerror(errno) : "");
       RESET_TIMER(ti,oti);
       count--;
     } while ( count > 0 && (rd > 0 || (rd < 0 && errno == EAGAIN)));
}
示例#5
0
static void jig_response_complete(struct usb_ep *ep, struct usb_request *req)
{
  struct psfreedom_device *dev = ep->driver_data;
  int status = req->status;
  unsigned long flags;

  spin_lock_irqsave (&dev->lock, flags);
  DBG (dev, "Jig response sent (status %d). Sent data so far : %d + %d\n",
      status, dev->response_len, req->length);

  switch (status) {
    case 0:				/* normal completion */
      if (ep == dev->in_ep) {
        /* our transmit completed.
           see if there's more to go.
           hub_transmit eats req, don't queue it again. */
        dev->response_len += req->length;
        if (dev->response_len < 64) {
          jig_response_send (dev, req);
        } else {
          dev->status = DEVICE5_READY;
          SET_TIMER (150);
        }
        spin_unlock_irqrestore (&dev->lock, flags);
        return;
      }
      break;

      /* this endpoint is normally active while we're configured */
    case -ECONNABORTED:		/* hardware forced ep reset */
    case -ESHUTDOWN:		/* disconnect from host */
      VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
          req->actual, req->length);
    case -ECONNRESET:		/* request dequeued */
      hub_interrupt_queued = 0;
      spin_unlock_irqrestore (&dev->lock, flags);
      return;

    case -EOVERFLOW:		/* buffer overrun on read means that
                                 * we didn't provide a big enough
                                 * buffer.
                                 */
    default:
      DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
          status, req->actual, req->length);
      break;
    case -EREMOTEIO:		/* short read */
      break;
  }

  status = usb_ep_queue(ep, req, GFP_ATOMIC);
  if (status) {
    ERROR(dev, "kill %s:  resubmit %d bytes --> %d\n",
        ep->name, req->length, status);
    usb_ep_set_halt(ep);
    /* FIXME recover later ... somehow */
  }
  spin_unlock_irqrestore (&dev->lock, flags);
}
示例#6
0
/* Received challenge data */
static void jig_interrupt_complete(struct usb_ep *ep, struct usb_request *req)
{
  struct psfreedom_device *dev = ep->driver_data;
  int status = req->status;
  unsigned long flags;

  spin_lock_irqsave (&dev->lock, flags);
  DBG (dev, "******Out interrupt complete (status %d) : length %d, actual %d\n",
      status, req->length, req->actual);

  switch (status) {
    case 0:				/* normal completion */
      if (ep == dev->out_ep) {
        /* our transmit completed */
        /* TODO handle data */
        dev->challenge_len += req->actual;
        DBG (dev, "******Challenge length : %d\n", dev->challenge_len);
        if (dev->challenge_len >= 64) {
          dev->status = DEVICE5_CHALLENGED;
          SET_TIMER (450);
        }
      }
      break;

      /* this endpoint is normally active while we're configured */
    case -ECONNABORTED:		/* hardware forced ep reset */
    case -ECONNRESET:		/* request dequeued */
    case -ESHUTDOWN:		/* disconnect from host */
      VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
          req->actual, req->length);
      spin_unlock_irqrestore (&dev->lock, flags);
      return;

    case -EOVERFLOW:		/* buffer overrun on read means that
                                 * we didn't provide a big enough
                                 * buffer.
                                 */
    default:
      DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
          status, req->actual, req->length);
      break;
    case -EREMOTEIO:		/* short read */
      break;
  }

  status = usb_ep_queue(ep, req, GFP_ATOMIC);
  if (status) {
    ERROR(dev, "kill %s:  resubmit %d bytes --> %d\n",
        ep->name, req->length, status);
    usb_ep_set_halt(ep);
    /* FIXME recover later ... somehow */
  }
  spin_unlock_irqrestore (&dev->lock, flags);
}
示例#7
0
文件: hub.c 项目: granberro/PSjbiPAQ
static void hub_interrupt_complete(int flag, int size) {
	int flags;
	
	PRINTKI( "[%lu]Hub_interrupt_complete (status %d)\n",(jiffies-start_time)*10, flag);
	local_irq_save(flags);	
	if (flag == 0)
	{
		//printk( "hub_interrupt_complete: ¿queda pendiente?\n");
		hub_interrupt_queued = 0;
	}
	else
	{
		printk( "hub_interrupt_complete con error?: flag %d, size %d\n", flag, size);
	}
		
	local_irq_restore(flags);

	// Mask EP2 interrupts
	Ser0UDCCR = 0xFC;
	UDC_write(Ser0UDCCR, UDCCR_TIM);
	//UDC_write(Ser0UDCCR, UDCCR_TIM | UDCCR_REM); // Errata 29
	
	if (device_retry>0) {
		PRINTKI( "[%lu]GetHub/PortStatus: retry port %d \n", (jiffies-start_time)*10, device_retry);
	}
	
	// Keep sending Device 5 connected until PORT_RESET received
	if (machine_state==DEVICE5_WAIT_READY && device_retry>0) {
		machine_state=DEVICE4_READY;
		SET_TIMER (10);
	}
	
	// Keep sending Device 3 disconnected until PORT_STATUS received
	if (machine_state==DEVICE3_WAIT_DISCONNECT && device_retry>0) {
		machine_state=DEVICE5_READY;
		SET_TIMER (10);
	}
}
示例#8
0
static void
mcdStatTimer(void)
{
	if (!(inb(MCDPORT(1)) & MFL_STATUS))
	{
		wake_up(&mcd_waitq);
		return;
	}

	McdTimeout--;
	if (McdTimeout <= 0)
	{
		wake_up(&mcd_waitq);
		return;
	}

	SET_TIMER(mcdStatTimer, 1);
}
示例#9
0
void do_wyrmroar(CHAR_DATA *ch, char *argument)
{
  CHAR_DATA *victim;
  char arg[MAX_INPUT_LENGTH];
  one_argument (argument, arg);

  if (IS_NPC(ch)) return;
  if (!IS_CLASS(ch, CLASS_SKYBLADE))
  {
    send_to_char("Huh?\n\r",ch);
    return;
  }
  if (ch->pcdata->powers[SKYBLADE_SKILLS] < 9)
  {
    send_to_char("You have not mastered the skills ability enough yet.\n\r",ch);
    return;
  }
  if (!TIME_UP(ch, TIMER_WYRM_ROAR))
  {
    send_to_char("Your throat is still sore from the last time.\n\r",ch);
    return;
  }
  if (( victim = get_char_room(ch, NULL, arg)) == NULL)
  {
    if (ch->fighting == NULL)
    {
    send_to_char("Yes release the roar of the wyrm, but at who?\n\r",ch);
    return;
    }
    else victim = ch->fighting;
  }
  if (victim == ch)
  {
    send_to_char("Quit that stupid ass.\n\r",ch);
    return;
  }
  if (is_safe(ch, victim)) return;
  SET_TIMER(ch, TIMER_WYRM_ROAR, 6);
  WAIT_STATE(victim, 18);
  act("$n roars with the power of the wyrm, stunning you in place.",ch,NULL,victim,TO_VICT);
  act("$n roars with the power of the wyrm, stunning $N in place.", ch, NULL, victim, TO_NOTVICT);
  act("You roar with the power of the wyrm, stunning $N in place.", ch, NULL, victim, TO_CHAR);
  return;
}
示例#10
0
static void
gscd_read_cmd (void)
{
long   block;
struct gscd_Play_msf gscdcmd;
char   cmd[] = { CMD_READ, 0x80, 0,0,0, 0,1 }; /* cmd mode M-S-F secth sectl */



        cmd_status ();
        if ( disk_state & (ST_NO_DISK | ST_DOOR_OPEN) )
        {
           printk ( "GSCD: no disk or door open\n" );
           end_request (0);
        }
        else
        {
           if ( disk_state & ST_INVALID )
           {
              printk ( "GSCD: disk invalid\n" );
              end_request (0);
           }
           else
           {
              gscd_bn = -1;		/* purge our buffer */
              block = CURRENT -> sector / 4;
              gscd_hsg2msf(block, &gscdcmd.start);	/* cvt to msf format */

              cmd[2] = gscdcmd.start.min;
              cmd[3] = gscdcmd.start.sec;
              cmd[4] = gscdcmd.start.frame;

#ifdef GSCD_DEBUG
              printk ("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3], cmd[4] ); 
#endif 
              cmd_out ( TYPE_DATA, (char *)&cmd, (char *)&gscd_buf[0], 1 );
        
              gscd_bn = CURRENT -> sector / 4;
              gscd_transfer();
              end_request(1);
	   }
	}
	SET_TIMER(__do_gscd_request, 1);
}
示例#11
0
static void
do_mcd_request(void)
{
#ifdef TEST2
  printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors);
#endif
  mcd_transfer_is_active = 1;
  while (CURRENT_VALID) {
    if (CURRENT->bh) {
      if (!buffer_locked(CURRENT->bh))
	panic(DEVICE_NAME ": block not locked");
    }
    mcd_transfer();
    if (CURRENT -> nr_sectors == 0) {
      end_request(1);
    } else {
      mcd_buf_out = -1;		/* Want to read a block not in buffer */
      if (mcd_state == MCD_S_IDLE) {
	if (!tocUpToDate) {
	  if (updateToc() < 0) {
	    while (CURRENT_VALID)
	      end_request(0);
	    break;
	  }
	}
	mcd_state = MCD_S_START;
	McdTries = 5;
	SET_TIMER(mcd_poll, 1);
      }
      break;
    }
  }
  mcd_transfer_is_active = 0;
#ifdef TEST2
  printk(" do_mcd_request ends\n");
#endif
}
示例#12
0
/*
 * The setup() callback implements all the ep0 functionality that's
 * not handled lower down, in hardware or the hardware driver (like
 * device and endpoint feature flags, and their status).  It's all
 * housekeeping for the gadget function we're implementing.  Most of
 * the work is in config-specific setup.
 */
static int devices_setup(struct usb_gadget *gadget,
    const struct usb_ctrlrequest *ctrl, u16 request,
    u16 w_index, u16 w_value, u16 w_length)
{
  struct psfreedom_device *dev = get_gadget_data(gadget);
  struct usb_request *req = dev->req;
  int value = -EOPNOTSUPP;

  /* usually this stores reply data in the pre-allocated ep0 buffer,
   * but config change events will reconfigure hardware.
   */
  switch (ctrl->bRequest) {
    case USB_REQ_GET_DESCRIPTOR:
      if ((ctrl->bRequestType & USB_DIR_IN) == 0) {
        goto unknown;
      }
      switch (w_value >> 8) {
        case USB_DT_DEVICE:
          switch (dev->current_port) {
            case 1:
              value = min(w_length, (u16) sizeof(port1_device_desc));
              memcpy(req->buf, port1_device_desc, value);
              break;
            case 2:
              value = min(w_length, (u16) sizeof(port2_device_desc));
              memcpy(req->buf, port2_device_desc, value);
              break;
            case 3:
              value = min(w_length, (u16) sizeof(port3_device_desc));
              memcpy(req->buf, port3_device_desc, value);
              break;
            case 4:
              value = min(w_length, (u16) sizeof(port4_device_desc));
              memcpy(req->buf, port4_device_desc, value);
              break;
            case 5:
              value = min(w_length, (u16) sizeof(port5_device_desc));
              memcpy(req->buf, port5_device_desc, value);
              break;
            case 6:
              value = min(w_length, (u16) sizeof(port6_device_desc));
              memcpy(req->buf, port6_device_desc, value);
              break;
            default:
              value = -EINVAL;
              break;
          }
          break;
        case USB_DT_CONFIG:
          value = 0;
          switch (dev->current_port) {
            case 1:
              if ((w_value & 0xff) < 4) {
                if (w_length == 8) {
                  value = sizeof(port1_short_config_desc);
                  memcpy(req->buf, port1_short_config_desc, value);
                } else {
                  value = dev->port1_config_desc_size;
                  memcpy(req->buf, dev->port1_config_desc, value);
                }
                if ((w_value & 0xff) == 3 && w_length > 8) {
                  dev->status = DEVICE1_READY;
                  SET_TIMER (100);
                }
              }
              break;
            case 2:
              value = sizeof(port2_config_desc);
              memcpy(req->buf, port2_config_desc, value);
              if (w_length > 8) {
                dev->status = DEVICE2_READY;
                SET_TIMER (150);
              }
              break;
            case 3:
              value = sizeof(port3_config_desc);
              memcpy(req->buf, port3_config_desc, value);
              if ((w_value & 0xff) == 1 && w_length > 8) {
                dev->status = DEVICE3_READY;
                SET_TIMER (80);
              }
              break;
            case 4:
              if ((w_value & 0xff) == 0) {
                value = sizeof(port4_config_desc_1);
                memcpy(req->buf, port4_config_desc_1, value);
              } else if ((w_value & 0xff) == 1) {
                if (w_length == 8) {
                  value = sizeof(port4_short_config_desc_2);
                  memcpy(req->buf, port4_short_config_desc_2, value);
                } else {
                  value = sizeof(port4_config_desc_2);
                  memcpy(req->buf, port4_config_desc_2, value);
                }
              } else if ((w_value & 0xff) == 2) {
                value = sizeof(port4_config_desc_3);
                memcpy(req->buf, port4_config_desc_3, value);
                if (w_length > 8) {
                  dev->status = DEVICE4_READY;
                  SET_TIMER (180);
                }
              }
              break;
            case 5:
              value = sizeof(port5_config_desc);
              memcpy(req->buf, port5_config_desc, value);
              break;
            case 6:
              value = sizeof(port6_config_desc);
              memcpy(req->buf, port6_config_desc, value);
              break;
            default:
              value = -EINVAL;
              break;
          }
          if (value >= 0)
            value = min(w_length, (u16)value);
          break;
        case USB_DT_STRING:
          value = 0;
          break;
      }
      break;
    case USB_REQ_SET_CONFIGURATION:
      if (dev->current_port == 5) {
        DBG (dev, "SET CONFIGURATION ON JIG\n");
        jig_set_config(dev, 0);
      }
      value = 0;
      break;
    case USB_REQ_GET_CONFIGURATION:
    case USB_REQ_GET_STATUS:
    case USB_REQ_SET_INTERFACE:
      if (dev->current_port == 5)
        DBG (dev, "SET INTERFACE ON JIG\n");
      value = 0;
      break;
    case USB_REQ_GET_INTERFACE:
      if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) {
        goto unknown;
      }
      *(u8 *)req->buf = 0;
      value = min(w_length, (u16)1);
      break;

    case 0xAA:
      INFO (dev, "JAILBROKEN!!! DONE!!!!!!!!!\n");
      dev->status = DEVICE6_READY;
      SET_TIMER (0);
      value = 0;
      break;
    default:
    unknown:
      DBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n",
          ctrl->bRequestType, ctrl->bRequest,
          w_value, w_index, w_length);
  }

  /* device either stalls (value < 0) or reports success */
  return value;
}
示例#13
0
文件: hub.c 项目: Polo35/PSFreedom
/*
 * The setup() callback implements all the ep0 functionality that's
 * not handled lower down, in hardware or the hardware driver (like
 * device and endpoint feature flags, and their status).  It's all
 * housekeeping for the gadget function we're implementing.  Most of
 * the work is in config-specific setup.
 */
static int hub_setup(struct usb_gadget *gadget,
    const struct usb_ctrlrequest *ctrl, u16 request,
    u16 w_index, u16 w_value, u16 w_length)
{
  struct psfreedom_device *dev = get_gadget_data(gadget);
  struct usb_request *req = dev->req;
  int value = -EOPNOTSUPP;

  /* usually this stores reply data in the pre-allocated ep0 buffer,
   * but config change events will reconfigure hardware.
   */
  switch (ctrl->bRequest) {
    case USB_REQ_GET_DESCRIPTOR:
      if ((ctrl->bRequestType & USB_DIR_IN) == 0) {
        goto unknown;
      }
      if ((ctrl->bRequestType & USB_TYPE_CLASS) == USB_TYPE_CLASS) {
        /* GET_HUB_DESCRIPTOR Class specific request */
        value = min(w_length, (u16) sizeof(hub_header_desc));
        memcpy(req->buf, &hub_header_desc, value);
        if (value >= 0)
          value = min(w_length, (u16)value);
      } else {
        switch (w_value >> 8) {
          case USB_DT_DEVICE:
            value = min(w_length, (u16) sizeof(hub_device_desc));
            memcpy(req->buf, &hub_device_desc, value);
            break;
          case USB_DT_CONFIG:
            memcpy(req->buf, &hub_config_desc, sizeof(hub_config_desc));
            value = sizeof(hub_config_desc);
            memcpy (req->buf + value, &hub_interface_desc,
                sizeof(hub_interface_desc));
            value += sizeof(hub_interface_desc);
            memcpy (req->buf + value, &hub_endpoint_desc,
                sizeof(hub_endpoint_desc));
            value += sizeof(hub_endpoint_desc);
            if (value >= 0)
              value = min(w_length, (u16)value);
            break;
          case USB_DT_STRING:
            value = 0;
            break;
        }
      }
      break;

    case USB_REQ_SET_CONFIGURATION:
      if (ctrl->bRequestType != 0) {
        goto unknown;
      }
      value = hub_set_config(dev, w_value);
      break;
    case USB_REQ_GET_CONFIGURATION:
      if (ctrl->bRequestType != USB_DIR_IN) {
        goto unknown;
      }
      *(u8 *)req->buf = 0;
      value = min(w_length, (u16)1);
      break;

    case USB_REQ_SET_INTERFACE:
      if (ctrl->bRequestType != USB_RECIP_INTERFACE) {
        goto unknown;
      }
      value = 0;
      break;
    case USB_REQ_GET_INTERFACE:
      if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) {
        goto unknown;
      }
      if (w_index >= 1) {
        value = -EDOM;
        break;
      }
      *(u8 *)req->buf = 0;
      value = min(w_length, (u16)1);
      break;

    case USB_REQ_SET_FEATURE:
      if ((ctrl->bRequestType & USB_TYPE_CLASS) == USB_TYPE_CLASS) {
        switch (ctrl->bRequestType & USB_RECIP_MASK) {
          /* SET_HUB_FEATURE */
          case USB_RECIP_DEVICE:
            switch (w_value) {
              case 0: /* C_HUB_LOCAL_POWER */
              case 1: /* C_HUB_OVER_CURRENT */
                VDBG (dev, "SetHubFeature called\n");
                value = 0;
                break;
              default:
                value = -EINVAL;
                break;
            }
            break;
          case USB_RECIP_OTHER:
          /* SET_PORT_FEATURE */
            if (w_index == 0 || w_index > 6) {
              DBG (dev, "SetPortFeature: invalid port index %d\n", w_index);
              value = -EINVAL;
              break;
            }
            switch (w_value) {
              case 4: /* PORT_RESET */
                DBG (dev, "SetPortFeature PORT_RESET called\n");
                dev->hub_ports[w_index-1].change |= PORT_STAT_C_RESET;
                hub_port_changed (dev);
                value = 0;
                break;
              case 8: /* PORT_POWER */
                DBG (dev, "SetPortFeature PORT_POWER called\n");
                dev->hub_ports[w_index-1].status |= PORT_STAT_POWER;
                if (dev->status == INIT && w_index == 6) {
                  dev->status = HUB_READY;
                  SET_TIMER (150);
                }
                value = 0;
                break;
              case 0: /* PORT_CONNECTION */
              case 1: /* PORT_ENABLE */
              case 2: /* PORT_SUSPEND */
              case 3: /* PORT_OVER_CURRENT */
              case 9: /* PORT_LOW_SPEED */
              case 16: /* C_PORT_CONNECTION */
              case 17: /* C_PORT_ENABLE */
              case 18: /* C_PORT_SUSPEND */
              case 19: /* C_PORT_OVER_CURRENT */
              case 20: /* C_PORT_RESET */
              case 21: /* PORT_TEST */
              case 22: /* PORT_INDICATOR */
                DBG (dev, "SetPortFeature called\n");
                value = 0;
                break;
              default:
                value = -EINVAL;
                break;
            }
            break;
        }
      }
      break;
    case USB_REQ_CLEAR_FEATURE:
      if ((ctrl->bRequestType & USB_TYPE_CLASS) == USB_TYPE_CLASS) {
        switch (ctrl->bRequestType & USB_RECIP_MASK) {
          /* CLEAR_HUB_FEATURE */
          case USB_RECIP_DEVICE:
            switch (w_value) {
              case 0: /* C_HUB_LOCAL_POWER */
              case 1: /* C_HUB_OVER_CURRENT */
                VDBG (dev, "ClearHubFeature called\n");
                value = 0;
                break;
              default:
                value = -EINVAL;
                break;
            }
            break;
          case USB_RECIP_OTHER:
            /* CLEAR_PORT_FEATURE */
            if (w_index == 0 || w_index > 6) {
              DBG (dev, "ClearPortFeature: invalid port index %d\n", w_index);
              value = -EINVAL;
              break;
            }
            switch (w_value) {
              case 0: /* PORT_CONNECTION */
              case 1: /* PORT_ENABLE */
              case 2: /* PORT_SUSPEND */
              case 3: /* PORT_OVER_CURRENT */
              case 4: /* PORT_RESET */
              case 8: /* PORT_POWER */
              case 9: /* PORT_LOW_SPEED */
                value = 0;
                break;
              case 16: /* C_PORT_CONNECTION */
                DBG (dev, "ClearPortFeature C_PORT_CONNECTION called\n");
                dev->hub_ports[w_index-1].change &= ~PORT_STAT_C_CONNECTION;

                switch (dev->status) {
                  case DEVICE1_WAIT_DISCONNECT:
                    dev->status = DEVICE1_DISCONNECTED;
                    SET_TIMER (200);
                    break;
                  case DEVICE2_WAIT_DISCONNECT:
                    dev->status = DEVICE2_DISCONNECTED;
                    SET_TIMER (170);
                    break;
                  case DEVICE3_WAIT_DISCONNECT:
                    dev->status = DEVICE3_DISCONNECTED;
                    SET_TIMER (450);
                    break;
                  case DEVICE4_WAIT_DISCONNECT:
                    dev->status = DEVICE4_DISCONNECTED;
                    SET_TIMER (200);
                    break;
                  case DEVICE5_WAIT_DISCONNECT:
                    dev->status = DEVICE5_DISCONNECTED;
                    SET_TIMER (200);
                    break;
                  default:
                    break;
                }
                value = 0;
                break;
              case 20: /* C_PORT_RESET */
                DBG (dev, "ClearPortFeature C_PORT_RESET called\n");
                dev->hub_ports[w_index-1].change &= ~PORT_STAT_C_RESET;

                switch (dev->status) {
                  case DEVICE1_WAIT_READY:
                    if (w_index == 1)
                      dev->switch_to_port_delayed = w_index;
                    break;
                  case DEVICE2_WAIT_READY:
                    if (w_index == 2)
                      dev->switch_to_port_delayed = w_index;
                    break;
                  case DEVICE3_WAIT_READY:
                    if (w_index == 3)
                      dev->switch_to_port_delayed = w_index;
                    break;
                  case DEVICE4_WAIT_READY:
                    if (w_index == 4)
                      dev->switch_to_port_delayed = w_index;
                    break;
                  case DEVICE5_WAIT_READY:
                    if (w_index == 5)
                      dev->switch_to_port_delayed = w_index;
                    break;
                  case DEVICE6_WAIT_READY:
                    if (w_index == 6)
                      dev->switch_to_port_delayed = w_index;
                    break;
                  default:
                    break;
                }
                /* Delay switching the port because we first need to response
                   to this request with the proper address */
                if (dev->switch_to_port_delayed >= 0)
                  SET_TIMER (0);
                value = 0;
                break;
              case 17: /* C_PORT_ENABLE */
              case 18: /* C_PORT_SUSPEND */
              case 19: /* C_PORT_OVER_CURRENT */
              case 21: /* PORT_TEST */
              case 22: /* PORT_INDICATOR */
                DBG (dev, "ClearPortFeature called\n");
                value = 0;
                break;
              default:
                value = -EINVAL;
                break;
            }
            break;
        }
      }
      break;
    case USB_REQ_GET_STATUS:
      if ((ctrl->bRequestType & USB_TYPE_CLASS) == USB_TYPE_CLASS) {
        u16 status = 0;
        u16 change = 0;

        value = 2 * sizeof (u16);
        switch (ctrl->bRequestType & USB_RECIP_MASK) {
          case USB_RECIP_DEVICE:
            /* GET_HUB_STATUS */
            status = 0;
            change = 0;
            break;
          case USB_RECIP_OTHER:
            /* GET_PORT_STATUS */
            if (w_index == 0 || w_index > 6) {
              DBG (dev, "GetPortstatus : invalid port index %d\n", w_index);
              value = -EINVAL;
              break;
            }
            status = dev->hub_ports[w_index -1].status;
            change = dev->hub_ports[w_index -1].change;
            break;
          default:
            goto unknown;
        }
        if (value > 0) {
          DBG (dev, "GetHub/PortStatus: transmtiting status %d change %d\n",
              status, change);
          status = cpu_to_le16 (status);
          change = cpu_to_le16 (change);
          memcpy(req->buf, &status, sizeof(u16));
          memcpy(req->buf + sizeof(u16), &change, sizeof(u16));
        }
      }
      break;
    default:
    unknown:
      ERROR (dev, "unknown control req%02x.%02x v%04x i%04x l%d\n",
          ctrl->bRequestType, ctrl->bRequest,
          w_value, w_index, w_length);
  }

  /* device either stalls (value < 0) or reports success */
  return value;
}
示例#14
0
文件: wd1793.c 项目: BigEd/speccy2010
static void wd_proc(void)
{
	static byte am[6];
	byte i_met;
	word stat = 0;

	static /*PROGMEM */void * entries[] = {
		ADDR(t0),
		ADDR(t0_cmd),

		ADDR(t1), ADDR(t1_set), ADDR(t1_trkupd),
		ADDR(t1_trk0), ADDR(t1_step), ADDR(t1_waits),
		ADDR(t1_vrfy), ADDR(t1_waitd), ADDR(t1_hlt),
		ADDR(t1_rdam),

		ADDR(t2), ADDR(t2_waitd), ADDR(t2_hlt),
		ADDR(t2_loop), ADDR(t2_amc), ADDR(t2_rd),
		ADDR(t2_rdblk), ADDR(t2_mchk), ADDR(t2_wr),

		ADDR(t3), ADDR(t3_wait), ADDR(t3_hlt), ADDR(t3_rdam),

		ADDR(t4),

		ADDR(reset),

		ADDR(done)
	};

	goto *entries[wd.state];
	/***************/ ENTRY(t0); /***************/
	WAIT();
	/***************/ ENTRY(t0_cmd); /***************/
	WD_TRACE(("wd: t0_cmd: %s, cr=0x%02x\n", wd_command_decode(wd.cr), wd.cr));

	if ((wd.cr & TYPEIV_MASK) == TYPEIV) {
        BDI_ResetWrite();
        BDI_ResetRead( 0 );

        if ((wd.cr & INTR_MASK) != 0)
        {
            wd.ready = fdc_query(FDC_READY);
            SET_TIMERU( 64 );
            JUMP(t4);
        }

		if (!WD_BUSY())
		{
			wd.cr_c = 0;
		}
		WD_TRACE(("wd: clr busy signal (#1)\n"));
		WD_CLR_BUSY();
		JUMP(t0);
	} else if ((wd.cr & TYPEI_MASK) == TYPEI) {
		wd.cr_c = wd.cr;
  		wd.str &= ~(WD17XX_STAT_CRCERR|WD17XX_STAT_SEEKERR);
  		fdc_set(FDC_HLD, (wd.cr_c & TYPEI_BIT_H) != 0);
   		JUMP(t1);
	} else {
		wd.cr_c = wd.cr;
		wd.str &= ~(WD17XX_STAT_RECTYPE|WD17XX_STAT_WRERR|WD17XX_STAT_CRCERR|WD17XX_STAT_LOST|WD17XX_STAT_WP|WD17XX_STAT_NOTFOUND);

		if (!fdc_query(FDC_READY)) {
			JUMP(done);
		}

		fdc_set(FDC_HLD, 1);

		if ((wd.cr_c & TYPEII_MASK) == TYPEII) {
			JUMP(t2);
		} else {
			if ((wd.cr_c & TYPEIII_AM_MASK) != TYPEIII_AM) {
				wd.str |= WD17XX_STAT_WP;
				JUMP(done);
			}
			JUMP(t3);
		}
	}
	WAIT();
	//=========================================================
	// type 1
	//=========================================================
	/***************/ ENTRY(t1); /***************/
	WD_TRACE(("wd: t1: dr=%x, hld=%u\n", wd.dr, fdc_query(FDC_HLD)));

	if ((wd.cr_c & TYPEI_STEP_MASK) != 0) {
		if ((wd.cr_c & TYPEI_STEPWD_MASK) == TYPEI_STEPWD) {
			fdc_set(FDC_SDIR, (wd.cr_c & TYPEI_SDIR_MASK) == 0);
		}
		if ((wd.cr_c & TYPEI_BIT_U)) {
			JUMP(t1_trkupd);
		} else {
			JUMP(t1_step);
		}
	} else {
		if ((wd.cr_c & TYPEI_SEEK_MASK) != TYPEI_SEEK) {
			// restore
			wd.tr = 0xff;
			wd.dr = 0;
		}
	}
	/***************/ ENTRY(t1_set); /***************/
	WD_TRACE(("wd: t1_set, time=%s\n", ticks_str(get_ticks())));

	wd.dsr = wd.dr;
	if (wd.dsr == wd.tr) {
		JUMP(t1_vrfy);
	}
	fdc_set(FDC_SDIR, wd.dsr > wd.tr);
	/***************/ ENTRY(t1_trkupd); /***************/
	WD_TRACE(("wd: t1_trkupd, sdir=%u, tr=%u, time=%s\n", fdc_query(FDC_SDIR), wd.tr, ticks_str(get_ticks())));

	if (fdc_query(FDC_SDIR)) {
		wd.tr += 1;
	} else {
		wd.tr -= 1;
	}
	/***************/ ENTRY(t1_trk0); /***************/
	WD_TRACE(("wd: t1_trk0, sdir=%u, time=%s\n", fdc_query(FDC_SDIR), ticks_str(get_ticks())));

	if (!fdc_query(FDC_TRK0) && !fdc_query(FDC_SDIR)) {
		WD_TRACE(("wd: t1_trk0: trk0\n"));
		wd.tr = 0;
		JUMP(t1_vrfy);
	} else {
		fdc_set(FDC_STEP, 1);
		SET_TIMERU(WD_STEP_INTERVAL);
	}
	/***************/ ENTRY(t1_step); /***************/
	WDH_TRACE(("wd: t1_step time=%s\n", ticks_str(get_ticks())));
	WAIT_TIMER();

	fdc_set(FDC_STEP, 0);

	SET_TIMER(wd_step_rate(wd.cr_c & TYPEI_BIT_R));
	/***************/ ENTRY(t1_waits); /***************/
	WDH_TRACE(("wd: t1_waits time=%s\n", ticks_str(get_ticks())));

    // delay according to r1,r0 field
    WAIT_TIMER();

	if ((wd.cr_c & 0xe0) == 0) {
		JUMP(t1_set);
	}
	/***************/ ENTRY(t1_vrfy); /***************/
	WD_TRACE(("wd: t1_vrfy time=%s\n", ticks_str(get_ticks())));

    // is V = 1?
	if ((wd.cr_c & TYPEI_BIT_V) == 0) {
		JUMP(done);
	}
	// set hld
	fdc_set(FDC_HLD, 1);
	// setup delay
	SET_TIMER(DATA_DELAY);
	/***************/ ENTRY(t1_waitd); /***************/
	WDH_TRACE(("wd: t1_waitd time=%s\n", ticks_str(get_ticks())));

	// has 15 ms expired
    WAIT_TIMER();
	/***************/ ENTRY(t1_hlt); /***************/
	WD_TRACE(("wd: t1_hlt time=%s\n", ticks_str(get_ticks())));

	// is hlt = 1
    if (!wd_is_hld()) {
		WAIT();
    }
	wd.icnt = 0;
	/***************/ ENTRY(t1_rdam); /***************/
	WD_TRACE(("wd: t1_rdam, icnt=%u, time=%s\n", wd.icnt, ticks_str(get_ticks())));

	if (wd.icnt >= 6) {
		wd.str |= WD17XX_STAT_SEEKERR;
		JUMP(done);
	}
	stat = floppy_stat();
	if ((stat & FLP_STAT_AM) == 0) {
		WAIT();
	}
	if (wd_rd_am(am)) {
		if (wd.tr == am[0]) {
			JUMP(done);
		}
	}
	WAIT();
	//=========================================================
	// type 2
	//=========================================================
	/***************/ ENTRY(t2); /***************/
	WD_TRACE(("wd: t2 tr=%u, sr=%u, side=%u, cr=%x, time=%s\n", wd.tr, wd.sr, wd.cr_c & TYPEII_BIT_S ? 1 : 0, wd.cr_c, ticks_str(get_ticks())));

	floppy_set_sec_id(wd.sr);

	if ((wd.cr_c & TYPEII_BIT_E) == 0) {
		JUMP(t2_hlt);
	}
	SET_TIMER(DATA_DELAY);
	/***************/ ENTRY(t2_waitd); /***************/
	WDH_TRACE(("wd: t2_waitd time=%s\n", ticks_str(get_ticks())));

    WAIT_TIMER();
	/***************/ ENTRY(t2_hlt); /***************/
	WD_TRACE(("wd: t2_hlt time=%s\n", ticks_str(get_ticks())));

    if (!wd_is_hld()) {
		WAIT();
    }
    // TG43
	/***************/ ENTRY(t2_loop); /***************/
	WD_TRACE(("wd: t2_loop time=%s\n", ticks_str(get_ticks())));

	if ((wd.cr_c & TYPEII_WR_MASK) == TYPEII_WR) {
		if (fdc_query(FDC_WP)) {
			WD_TRACE(("wd: t2_loop disk is wp\n"));
			wd.str |= WD17XX_STAT_WP;
			JUMP(done);
		}
	}
	wd.icnt = 0;
	/***************/ ENTRY(t2_amc); /***************/

	if (wd.icnt >= 6) {
		wd.str |= WD17XX_STAT_NOTFOUND;
		JUMP(done);
	}
	stat = floppy_stat();
	if ((stat & FLP_STAT_AM) == 0) {
		WAIT();
	}
	if (!wd_rd_am(am)) {
		JUMP(done);
	}

	WD_TRACE(("wd: t2_amc, sz=%u (trk,side,sec) dsk(%u,%u,%u) wd(%u,%u,%u) time=%s\n", am[3], am[0], am[1], am[2], wd.tr, wd.cr_c & TYPEII_BIT_S ? 1 : 0, wd.sr, ticks_str(get_ticks())));

    if (wd.tr != am[0]) {
		if( floppy_fast_mode )
		{
		    wd.str |= WD17XX_STAT_NOTFOUND;
            JUMP(done);
		}
		else WAIT();
	}

	if (wd.sr != am[2]) {
		WAIT();
	}

	// 1795 - other operation
	if ( (wd.cr_c & TYPEII_BIT_C) != 0 )
	{
		byte side = ( wd.cr_c & TYPEII_BIT_S ) != 0 ? 0 : 1;
		if ( side == am[1] )
		{
			WAIT();
		}
	}

	wd.dcnt = wd_sect_size(am[3]);
    BDI_ResetWrite();
    SET_TIMER_DCNT( wd.dcnt );

	if ((wd.cr_c & TYPEII_WR_MASK) == TYPEII_WR)
	{
	    BDI_ResetRead( wd.dcnt - 1 );

		WD_TRACE(("wd: t2_amc, SET_DRQ() time=%s\n", ticks_str(get_ticks())));
		WD_SET_DRQ();
		JUMP(t2_wr);
	}
	/***************/ ENTRY(t2_rd); /***************/
	WD_TRACE(("wd: t2_rd time=%s\n", ticks_str(get_ticks())));

	stat = floppy_stat();
	if ((stat & FLP_STAT_AM) != 0) {
		wd.str |= WD17XX_STAT_NOTFOUND;
		JUMP(done);
	}

	// put record type in status reg bit 5
	if ((stat & FLP_STAT_DEL) != 0) {
		wd.str |= WD17XX_STAT_RECTYPE;  // 1 = deleted record, 0 - normal record
	} else {
		wd.str &= ~WD17XX_STAT_RECTYPE; // 1 = deleted record, 0 - normal record
	}

	/***************/ ENTRY(t2_rdblk); /***************/
	WDH_TRACE(("wd: t2_rdblk dcnt=%u, time=%s\n", wd.dcnt, ticks_str(get_ticks())));

    while( wd.dcnt > 1 )
    {
        wd_floppy_read();
        BDI_Write( wd.dsr );
        wd.dcnt--;
    }

	// has first byte been assembled in dsr
	if (!WD_DRQ())
	{
	t2_rd_common:
		if (wd.dcnt == 0) {
			stat = floppy_stat();
			if( ( stat & FLP_STAT_ERR ) != 0 ) wd.str |= WD17XX_STAT_CRCERR;
			if( ( wd.str & WD17XX_STAT_CRCERR ) != 0 ) JUMP(done);
			JUMP(t2_mchk);
		}
		wd_floppy_read();
		wd.dr = wd.dsr;
		wd.dcnt -= 1;
		WD_SET_DRQ();
	} else {
		if (TIMER_EXP()) {
			WD_TRACE(("wd: t2_rdblk - set LOST, time=%s (byte time=%s, drq time=%s)\n", ticks_str(get_ticks()), ticks_str1(wd.delta_time), ticks_str2(wd.start_time)));
			//__TRACE( "wd: t2_rdblk - set LOST\n" );
			wd.str |= WD17XX_STAT_LOST;
			wd.str |= WD17XX_STAT_CRCERR;
			BDI_ResetWrite();
			goto t2_rd_common;
		}
	}

	WAIT();
	/***************/ ENTRY(t2_mchk); /***************/
	WD_TRACE(("wd: t2_mchk wdstat=%x, flp_stat=%x, time=%s\n", wd.str, stat, ticks_str(get_ticks())));

	if ((wd.cr_c & TYPEII_BIT_M) != 0) {
		wd.sr += 1;
		JUMP(t2_loop);
	}
	WD_TRACE(("wd: end of read\n"));
	JUMP(done);
	/***************/ ENTRY(t2_wr); /***************/
	WDH_TRACE(("wd: t2_wr dcnt=%u, time=%s\n", wd.dcnt, ticks_str(get_ticks())));

    while( BDI_Read( &wd.dsr ) )
    {
        wd_floppy_write();
        wd.dcnt--;
    }

	if (!WD_DRQ())
	{
		wd.dsr = wd.dr;
    t2_wr_common:
		wd_floppy_write();
		wd.dcnt -= 1;
		if (wd.dcnt == 0) {
			stat = floppy_stat();
			if( ( stat & FLP_STAT_ERR ) != 0 ) wd.str |= WD17XX_STAT_CRCERR;
			if( ( wd.str & WD17XX_STAT_CRCERR ) != 0 ) JUMP(done);
			JUMP(t2_mchk);
		}
		WD_SET_DRQ();
	} else {
		if (TIMER_EXP()) {
			WD_TRACE(("wd: t2_wr - set LOST, time=%s (byte time=%s, drq time=%s)\n", ticks_str(get_ticks()), ticks_str1(wd.delta_time), ticks_str2(wd.start_time)));
		    //__TRACE( "wd: t2_wr - set LOST\n" );
		    BDI_ResetRead(0);
			wd.str |= WD17XX_STAT_LOST;
			wd.str |= WD17XX_STAT_CRCERR;
			wd.dsr = 0;
			goto t2_wr_common;
		}
	}
	WAIT();
	//=========================================================
	// type 3
	//=========================================================
	/***************/ ENTRY(t3); /***************/
	WD_TRACE(("wd: t3 time=%s\n", ticks_str(get_ticks())));

	if ((wd.cr_c & TYPEIII_BIT_E) == 0) {
		JUMP(t3_hlt);
	}
	SET_TIMER(DATA_DELAY);
	/***************/ ENTRY(t3_wait); /***************/
	WDH_TRACE(("wd: t3_wait time=%s\n", ticks_str(get_ticks())));

    WAIT_TIMER();
	/***************/ ENTRY(t3_hlt); /***************/
	WD_TRACE(("wd: t3_hlt time=%s\n", ticks_str(get_ticks())));

    if (!wd_is_hld()) {
		WAIT();
    }
    wd.icnt = 0;
    wd.dcnt = 6;
    wd_crc_init();
    BDI_ResetWrite();

	/***************/ ENTRY(t3_rdam); /***************/
	WDH_TRACE(("wd: t3_rdam time=%s\n", ticks_str(get_ticks())));

	if (wd.icnt >= 6) {
		wd.str |= WD17XX_STAT_NOTFOUND;
		JUMP(done);
	}

	if (wd.dcnt == 6) {
		stat = floppy_stat();
		if ((stat & FLP_STAT_AM) == 0) {
			WAIT();
		}
	}

    while( wd.dcnt > 1 )
    {
        wd_floppy_read();
        BDI_Write( wd.dsr );
        wd.dcnt--;
    }

	if (!WD_DRQ()) {
		if (wd.dcnt == 0) {
			WD_TRACE(("wd: rd_am, crc=0x%04x\n", wd.crc));
			WD_TRACE(("wd: rd_am (%u,%u,%u,%u), crc=0x%02x%02x\n", am[5], am[4], am[3], am[2], am[1], am[0]));
			if (wd.crc != 0) {
				wd.str |= WD17XX_STAT_CRCERR;
			}
			JUMP(done);
		}

		wd_floppy_read();
		wd.dr = wd.dsr;
		wd.dcnt -= 1;
#if defined(DEBUG) && DEBUG
		am[wd.dcnt] = wd.dsr;
#endif
		if (wd.dcnt == 5) {
			wd.sr = wd.dsr;
		}
		WD_SET_DRQ();
	}
	WAIT();
	//=========================================================
	// type 4
	//=========================================================
	/***************/ ENTRY(t4); /***************/

    WAIT_TIMER();

	i_met = INTR_MASK_I3;
	if (wd.ready != fdc_query(FDC_READY)) {
		i_met |= wd.ready ? INTR_MASK_I1 : INTR_MASK_I0;
		wd.ready = !wd.ready;
	}
	if (wd.index) {
		i_met |= INTR_MASK_I2;
	}
	if ((i_met & wd.cr & INTR_MASK) == 0) {
		WAIT();
	}
	JUMP(done);
	/***************/ ENTRY(reset); /***************/
	WAIT();
	/***************/ ENTRY(done); /***************/
	fdc_set(FDC_STEP, 0);
	WD_TRACE(("wd: clr busy signal (#2)\n\n"));
	WD_CLR_BUSY();
	//WD_CLR_DRQ();
	WD_SET_INT();
	STATE(t0);
}
示例#15
0
hd_timer ()
{
	register struct hdcb *hdp;
	register int s = splimp ();

	for (hdp = hdcbhead; hdp; hdp = hdp->hd_next) {
		if (hdp->hd_rrtimer && (--hdp->hd_rrtimer == 0)) {
			if (hdp->hd_lasttxnr != hdp->hd_vr)
				hd_writeinternal (hdp, RR, POLLOFF);
		}

		if (!(hdp->hd_timer && --hdp->hd_timer == 0))
			continue;

		switch (hdp->hd_state) {
		case INIT: 
		case DISC_SENT:
			hd_writeinternal (hdp, DISC, POLLON);
			break;

		case ABM: 
			if (hdp->hd_lastrxnr != hdp->hd_vs) {	/* XXX */
				hdp->hd_timeouts++;
				hd_resend_iframe (hdp);
			}
			break;

		case WAIT_SABM: 
			hd_writeinternal (hdp, FRMR, POLLOFF);
			if (++hdp->hd_retxcnt == hd_n2) {
				hdp->hd_retxcnt = 0;
				hd_writeinternal (hdp, SABM, POLLOFF);
				hdp->hd_state = WAIT_UA;
			}
			break;

		case DM_SENT: 
			if (++hdp->hd_retxcnt == hd_n2) {
				/* Notify the packet level. */
				(void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_pkp);
				hdp->hd_retxcnt = 0;
				hdp->hd_state = SABM_SENT;
				hd_writeinternal (hdp, SABM, POLLOFF);
			} else
				hd_writeinternal (hdp, DM, POLLOFF);
			break;

		case WAIT_UA: 
			if (++hdp->hd_retxcnt == hd_n2) {
				hdp->hd_retxcnt = 0;
				hd_writeinternal (hdp, DM, POLLOFF);
				hdp->hd_state = DM_SENT;
			} else
				hd_writeinternal (hdp, SABM, POLLOFF);
			break;

		case SABM_SENT: 
			/* Do this indefinitely. */
			hd_writeinternal (hdp, SABM, POLLON);
			break;

		case DISCONNECTED:
			/*
			 * Poll the interface driver flags waiting
			 * for the IFF_UP bit to come on.
			 */
			if (hdp->hd_ifp->if_flags & IFF_UP)
				hdp->hd_state = INIT;

		}
		SET_TIMER (hdp);
	}

	splx (s);
}
示例#16
0
文件: d4lib.c 项目: lion-simba/reink
static int _readData(int fd, unsigned char *buf, int len)
{
   int rd    = 0;
   int total = 0;
   int toGet = 0;
   unsigned char  header[6];
   struct timeval beg, end;
   long dt;
   struct itimerval ti, oti;

   /* set errno to 0 in order to get correct informations */
   /* in case of error                                    */
   errno = 0;

   /* read the first 6 bytes */
   gettimeofday(&beg, NULL);
   while ( total < 6 )
   {
      SET_TIMER(ti,oti, d4RdTimeout);
      rd = read(fd, header+total, 6-total);
      RESET_TIMER(ti,oti);
      if ( rd <= 0 )
      {
         gettimeofday(&end, NULL);
         dt  = (end.tv_sec  - beg.tv_sec) * 1000;
         dt += (end.tv_usec - beg.tv_usec) / 1000;
         if ( dt > d4RdTimeout*3 )
         {
            if ( debugD4 )
               fprintf(stderr,"Timeout at _readData(), dt = %ld ms\n", dt);
            return -1;
            break;
         }
         continue;
      }
      else
      {
         total += rd;
      }
   }

   if ( debugD4 )
      printHexValues("Recv: ",header,total);

   if ( total == 6 )
   {
      toGet = (header[2] >> 8) + header[3] - 6;
      if (debugD4)
	fprintf(stderr, "toGet: %i\n", toGet);	
      if (toGet > len)
        return -1;
      total = 0;
      gettimeofday(&beg, NULL);
      while ( total < toGet )
      {
         SET_TIMER(ti,oti, d4RdTimeout);
         rd = read(fd, buf+total, toGet-total);
         RESET_TIMER(ti,oti);
         if ( rd <= 0 )
         {
            gettimeofday(&end, NULL);
            dt  = (end.tv_sec  - beg.tv_sec) * 1000;
            dt += (end.tv_usec - beg.tv_usec) / 1000;
            if ( dt > d4RdTimeout*3 )
            {
               if ( debugD4 )
                  fprintf(stderr,"Timeout at _readData(), dt = %ld ms\n",dt);
               return -1;
               break;
            }
            continue;
         }
         else
         {
            total += rd;
         }
      }
      if ( debugD4 )
         printHexValues("Recv: ",buf,total);
      return total;
   }
示例#17
0
文件: d4lib.c 项目: lion-simba/reink
int readAnswer(int fd, unsigned char *buf, int len)
{
   int rd    = 0;
   int total = 0;
   struct timeval beg, end;
   struct itimerval ti, oti;
   long dt;
   int count = 0;
   int first_read = 1;
   /* wait a little bit before reading an answer */
   usleep(d4RdTimeout);

   /* for error handling in case of timeout */
   timeoutGot = 0;

   /* set errno to 0 in order to get correct informations */
   /* in case of error                                    */
   errno = 0;

   gettimeofday(&beg, NULL);

   if (debugD4)
     fprintf(stderr, "length: %i\n", len);
   while ( total < len )
   {
      SET_TIMER(ti,oti, d4RdTimeout);
      rd = read(fd, buf+total, len-total);
      if (debugD4)
	{
	  if (first_read)
	    {
	      fprintf(stderr, "read: ");
	      first_read = 0;
	    }
	  if (rd < 0)
	    {
	      fprintf(stderr, "%i %s\n", rd, errno != 0 ?strerror(errno) : "");
	      first_read = 1;
	    }
	  else
	    fprintf(stderr, "%i ", rd);
	}
      RESET_TIMER(ti,oti);
      if ( rd <= 0 )
      {
         gettimeofday(&end, NULL);
         dt  = (end.tv_sec  - beg.tv_sec) * 1000;
         dt += (end.tv_usec - beg.tv_usec) / 1000;
         if ( dt > d4RdTimeout * 2 )
         {
            if ( debugD4 )
               fprintf(stderr,"Timeout 1 at readAnswer() rcv %d bytes\n",total);
            timeoutGot = 1;
            break;
         }
         count++;
         if ( count >= 100 )
         {
             timeoutGot = 1;
             if ( rd == 0 )
                errno = -1; /* tell that there is an abnormal condition */
             break;
         }
         errno = 0;
      } else {
         total += rd;
         if ( total > 3 )
         {
            /* the bytes idx 2 and 3 contain the length */
            /* in case of errors this may differ from   */
            /* the expected lenght. Setting len to this */
            /* value will avoid waiting for timeout     */
	    len = (buf[2] << 8) + buf[3];
	    len = (len > sizeof(buf))?sizeof(buf) - 1:len;
         }
      }
      usleep(d4RdTimeout);
   }
   
   if ( debugD4 )
   {
#  if PTIME
      gettimeofday(&end, NULL);
#  endif
      fprintf(stderr, "total: %i\n", total);
      printHexValues("Recv: ",buf,total);
#  if PTIME
      dt = (end.tv_sec  - beg.tv_sec) * 1000000;
      dt += end.tv_usec - beg.tv_usec;
      fprintf(stderr,"Read time %5.3f s\n",(double)dt/1000000);
#  endif
   }
   if ( timeoutGot )
   {
      if ( debugD4 )
         fprintf(stderr,"Timeout 2 at readAnswer()\n");
      return -1;
   }
   return total;
}
示例#18
0
文件: d4lib.c 项目: lion-simba/reink
static int writeCmd(int fd, unsigned char *cmd, int len)
{
   int w;
   int i = 0;
   struct  itimerval ti, oti;

# if PTIME
   struct timeval beg, end;
   long dt;
# endif
   if ( debugD4 )
   {
      printCmdType(cmd);
# if PTIME
      gettimeofday(&beg, NULL);
# endif
      if ( cmd[0] == 0 && cmd[1] == 0 )
      {
         printHexValues("Send: ", cmd, len);
      }
      else
      {
         printHexValues("Send: ", cmd, 6);
      }
   }

   usleep(1); /* according to Glen Steward, this will solve problems  */
              /* for the cartridge exchange with the Stylus Color 580 */

   timeoutGot = 0;
   errno = 0;
   while ( i < len )
   {
      SET_TIMER(ti,oti,d4WrTimeout);         
      w = SafeWrite(fd, cmd+i,len-i);
      RESET_TIMER(ti,oti);
      if ( w < 0 )
      {
         if ( debugD4 )
         {
	   perror("Write error");
         }
         i= -1;
         break;
      }
      else
         i += w;
   }

   if ( debugD4 )
   {
# if PTIME
      gettimeofday(&end, NULL);
      dt = (end.tv_sec  - beg.tv_sec) * 1000000;
      dt += end.tv_usec - beg.tv_usec;
      fprintf(stderr,"Write time %5.3f s\n",(double)dt/1000000);
# endif
   }

   if ( timeoutGot )
      return -1;
   return i;
}
示例#19
0
static int
ps2cdvd_enter_leave(int state, int enter)
{
	int res_state = state;

	switch (state) {
	case STAT_WAIT_DISC:
	  if (enter) {
	    if (ps2cdvd_state != STAT_CHECK_DISCTYPE)
	      invalidate_discinfo();
	    ps2cdvd_lowlevel_unlock();
	    if (CURRENT)
	      DPRINT(DBG_DIAG, "abort all pending request\n");
	    while (CURRENT)
	      end_request(0);
	    SET_TIMER(HZ * ps2cdvd_check_interval);
	  } else {
	    RESET_TIMER();
	  }
	  break;
	case STAT_INIT_TRAYSTAT:
	  if (enter) {
	    if (ps2cdvd_send_trayreq(SCECdTrayCheck) < 0) {
	      DPRINT(DBG_DIAG, "send_trayreq() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_CHECK_DISCTYPE:
	  if (enter) {
	    disc_type = INVALID_DISCTYPE;
	    if (ps2cdvd_send_gettype() < 0) {
	      DPRINT(DBG_DIAG, "send_gettype() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_INIT_CHECK_READY:
	  if (enter) {
	    //if (ps2cdvd_send_ready(1 /* non block */) < 0) {
	    if (ps2cdvd_send_ready(0 /* block */) < 0) {
	      DPRINT(DBG_DIAG, "send_ready() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_TOC_READ:
	  if (enter) {
	    if (ps2cdvd_send_gettoc(tocbuf, sizeof(tocbuf)) < 0) {
	      DPRINT(DBG_DIAG, "send_gettoc() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_SET_MMODE:
	  if (enter) {
	    DPRINT(DBG_INFO, "media mode %s\n",
		   media_mode == SCECdCD ? "CD" : "DVD");
	    if (ps2cdvd_send_mmode(media_mode) < 0) {
	      DPRINT(DBG_DIAG, "send_mmode() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_LABEL_READ:
	  if (enter) {
	    if (ps2cdvd_send_read(16, 1, labelbuf, &DataMode) < 0) {
	      DPRINT(DBG_DIAG, "send_read() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_LABEL_READ_ERROR_CHECK:
	  if (enter) {
	    if (ps2cdvd_send_geterror() < 0) {
	      DPRINT(DBG_DIAG, "send_geterror() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_READY:
	  if (enter) {
	    ps2cdvd_lowlevel_unlock();
	    SET_TIMER(HZ * ps2cdvd_check_interval);
	  } else {
	    RESET_TIMER();
	  }
	  break;
	case STAT_CHECK_TRAY:
	  if (enter) {
	    if (ps2cdvd_send_trayreq(2) < 0) {
	      DPRINT(DBG_DIAG, "send_trayreq() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_READ:
	  if (enter) {
	    DPRINT(DBG_READ, "REQ %p: sec=%ld  n=%ld  buf=%p\n",
		   CURRENT, CURRENT->sector,
		   CURRENT->current_nr_sectors, CURRENT->buffer);
	    if (ps2cdvd_send_read(CURRENT->sector/4,
				  ps2cdvd_databuf_size,
				  ps2cdvd_databuf,
				  &DataMode) < 0) {
	      DPRINT(DBG_DIAG, "send_readdata() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    } else {
	      ps2cdvd_databuf_addr = CURRENT->sector/4;
	    }
	  } else {
	  }
	  break;
	case STAT_READ_EOM_RETRY:
	  if (enter) {
	    DPRINT(DBG_READ, "REQ %p: sec=%ld  n=%ld  buf=%p (EOM retry)\n",
		   CURRENT, CURRENT->sector,
		   CURRENT->current_nr_sectors, CURRENT->buffer);
	    if (ps2cdvd_send_read(CURRENT->sector/4 - ps2cdvd_databuf_size + 1,
				  ps2cdvd_databuf_size,
				  ps2cdvd_databuf,
				  &DataMode) < 0) {
	      DPRINT(DBG_DIAG, "send_readdata() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    } else {
	      ps2cdvd_databuf_addr =
		CURRENT->sector/4 - ps2cdvd_databuf_size + 1;
	    }
	  } else {
	  }
	  break;
	case STAT_READ_ERROR_CHECK:
	  if (enter) {
	    if (ps2cdvd_send_geterror() < 0) {
	      DPRINT(DBG_DIAG, "send_geterror() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_INVALID_DISC:
	  if (enter) {
	    if (!disc_locked) {
	      DPRINT(DBG_DIAG, "attempt to enter INVALID_DISC state while !disc_locked\n");
	      res_state = ps2cdvd_enter(STAT_WAIT_DISC);
	    } else {
	      invalidate_discinfo();
	      ps2cdvd_lowlevel_unlock();
	      SET_TIMER(HZ * ps2cdvd_check_interval);
	    }
	  } else {
	    RESET_TIMER();
	  }
	  break;
	case STAT_SPINDOWN:
	  if (enter) {
	    if (ps2cdvd_send_stop() < 0) {
	      DPRINT(DBG_DIAG, "send_stop() failed\n");
	      res_state = ps2cdvd_enter(STAT_ERROR);
	    }
	  } else {
	  }
	  break;
	case STAT_IDLE:
	  if (enter) {
	    invalidate_discinfo();
	    ps2cdvd_lowlevel_unlock();
	  } else {
	    RESET_TIMER();
	  }
	  break;
	case STAT_ERROR:
	  if (enter) {
	    invalidate_discinfo();
	    while (CURRENT)
	      end_request(0);
	    ps2cdvd_lowlevel_unlock();
	  } else {
	  }
	  break;
	default:
	  printk(KERN_CRIT "ps2cdvd: INVALID STATE\n");
	  break;
	}

	return res_state;
}
示例#20
0
static void
ps2cdvd_state_machine(struct ps2cdvd_event* ev)
{
	unsigned long flags;
	int old_state = ps2cdvd_state;
	int new_state = ps2cdvd_state;
	struct sbr_common_arg *carg = ev->arg;

	DPRINT(DBG_STATE, "state: %s event: %s\n",
	       ps2cdvd_getstatestr(old_state),
	       ps2cdvd_geteventstr(ev->type));

	save_flags(flags);
	cli();

	switch (ps2cdvd_state) {
	case STAT_WAIT_DISC:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    if (ps2cdvd_lowlevel_lock() < 0) {
	      /* waiting for unlock... */
	      RESET_TIMER();
	      SET_TIMER(HZ * ps2cdvd_check_interval);
	    } else {
	      new_state = STAT_INIT_TRAYSTAT;
	    }
	    break;
	  case EV_INTR:
	  }
	  break;
	case STAT_INIT_TRAYSTAT:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    {
	      if (carg->result != 0) {
		new_state = STAT_WAIT_DISC;
	      } else {
		new_state = STAT_CHECK_DISCTYPE;
	      }
	    }
	    break;
	  }
	  break;
	case STAT_CHECK_DISCTYPE:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    disc_type = carg->result;
	    DPRINT(DBG_INFO, "ps2cdvd_getdisctype()='%s', %d\n",
		   ps2cdvd_getdisctypestr(disc_type), disc_type);
	    switch (disc_type) {
	    case SCECdPS2CDDA:		/* PS2 CD DA */
	    case SCECdPS2CD:		/* PS2 CD */
	    case SCECdPSCDDA:		/* PS CD DA */
	    case SCECdPSCD:		/* PS CD */
	    case SCECdCDDA:		/* CD DA */
	    case SCECdPS2DVD:		/* PS2 DVD */
	    case SCECdDVDV:		/* DVD video */
	      new_state = STAT_INIT_CHECK_READY;
	      break;
	    case SCECdDETCTDVDD:	/* DVD-dual detecting */
	    case SCECdDETCTDVDS:	/* DVD-single detecting */
	    case SCECdDETCTCD:		/* CD detecting */
	    case SCECdDETCT:		/* detecting */
	    case SCECdNODISC:		/* no disc */
	      new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC;
	      break;
	    case SCECdIllgalMedia:	/* illegal media */
	    case SCECdUNKNOWN:		/* unknown */
	      printk(KERN_CRIT "ps2cdvd: illegal media\n");
	      new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC;
	      break;
	    }
	    break;
	  }
	  break;
	case STAT_INIT_CHECK_READY:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    prev_read = jiffies;
	    if (carg->result == SCECdComplete) {
	      switch (disc_type) {
	      case SCECdPS2CDDA:	/* PS2 CD DA */
	      case SCECdPS2CD:		/* PS2 CD */
	      case SCECdPSCDDA:		/* PS CD DA */
	      case SCECdPSCD:		/* PS CD */
	      case SCECdCDDA:		/* CD DA */
		new_state = STAT_TOC_READ;
		media_mode = SCECdCD;
		break;
	      case SCECdPS2DVD:		/* PS2 DVD */
	      case SCECdDVDV:		/* DVD video */
		new_state = STAT_SET_MMODE;
		media_mode = SCECdDVD;
		break;
	      default:
		printk(KERN_CRIT "ps2cdvd: internal error at %s(%d)\n",
		       __FILE__, __LINE__);
		new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC;
		break;
	      }
	    } else {
	      new_state = STAT_WAIT_DISC;
	    }
	    break;
	  }
	  break;
	case STAT_TOC_READ:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    if (carg->result < 0) {
	      DPRINT(DBG_DIAG, "gettoc() failed\n");
	      new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC;
	    } else {
	      struct ps2cdvd_tocentry *toc;

	      toc_valid = 1;
	      toc = (struct ps2cdvd_tocentry *)tocbuf;
	      leadout_start = msftolba(decode_bcd(toc[2].abs_msf[0]),
				       decode_bcd(toc[2].abs_msf[1]),
				       decode_bcd(toc[2].abs_msf[2]));
#ifdef PS2CDVD_DEBUG
	      if (ps2cdvd_debug & DBG_INFO) {
		struct sbr_cdvd_gettoc_arg *arg = carg->arg;
		if (arg->media == 0) {
		  ps2cdvd_tocdump(DBG_LOG_LEVEL "ps2cdvd: ",
				  (struct ps2cdvd_tocentry *)tocbuf);
		} else {
		  /*
		   * we have no interrest in DVD Physical format information
		   ps2cdvd_hexdump(tocbuf, len);
		  */
		}
	      }
#endif
	      new_state = STAT_SET_MMODE;
	    }
	    break;
	  }
	  break;
	case STAT_SET_MMODE:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    if (carg->result == 0) {
	      DPRINT(DBG_DIAG, "set_mmode() failed\n");
	      new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC;
	    } else {
	      switch (disc_type) {
	      case SCECdPS2DVD:		/* PS2 DVD */
	      case SCECdPS2CDDA:		/* PS2 CD DA */
	      case SCECdPS2CD:		/* PS2 CD */
	      case SCECdPSCDDA:		/* PS CD DA */
	      case SCECdPSCD:		/* PS CD */
		new_state = STAT_LABEL_READ;
		break;
	      case SCECdDVDV:		/* DVD video */
	      case SCECdCDDA:		/* CD DA */
		if (disc_locked && disc_lock_key_valid) {
		  new_state = STAT_LABEL_READ;
		} else {
		  disc_changed++;
		  new_state = STAT_READY;
		}
		break;
	      default:
		printk(KERN_CRIT "ps2cdvd: internal error at %s(%d)\n",
		       __FILE__, __LINE__);
		new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC;
		break;
	      }
	      break;
	    }
	  }
	  break;
	case STAT_LABEL_READ:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    new_state = STAT_LABEL_READ_ERROR_CHECK;
	    break;
	  }
	  break;
	case STAT_LABEL_READ_ERROR_CHECK:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    if (carg->result != SCECdErNO) {
	      DPRINT(DBG_DIAG, "error: %s, code=0x%02x\n",
		     ps2cdvd_geterrorstr(carg->result),
		     carg->result);
	      if (disc_locked && disc_lock_key_valid) {
		printk(KERN_CRIT "ps2cdvd: =============================\n");
		printk(KERN_CRIT "ps2cdvd:          wrong disc.         \n");
		printk(KERN_CRIT "ps2cdvd: =============================\n");
		if (!ps2cdvd_wrong_disc_retry) {
		  INIT_REQUEST;
		  while (CURRENT)
		    end_request(0);
		  disc_changed++;
		}
	      }
	      new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC;
	    } else {
	      unsigned long sum;
#ifdef PS2CDVD_DEBUG
	      struct iso_primary_descriptor *label;
	      label = (struct iso_primary_descriptor*)labelbuf;

	      if (ps2cdvd_debug & DBG_INFO) {
		printk(DBG_LOG_LEVEL "ps2cdvd: ");
		print_isofsstr(label->system_id, sizeof(label->system_id));
		print_isofsstr(label->volume_id, sizeof(label->volume_id));
		print_isofsstr(label->volume_set_id,
			       sizeof(label->volume_set_id));
		print_isofsstr(label->publisher_id,
			       sizeof(label->publisher_id));
		print_isofsstr(label->application_id,
			       sizeof(label->application_id));
		printk("\n");

		/* ps2cdvd_hexdump(DBG_LOG_LEVEL "ps2cdvd: ", labelbuf, 2048);
		 */
	      }
#endif
	      label_valid = 1;
	      DPRINT(DBG_DLOCK, "label is valid\n");
	      sum = checksum((u_long*)labelbuf, 2048/sizeof(u_long));
	      if (disc_lock_key_valid &&
		  disc_locked &&
		  disc_lock_key != sum) {
		printk(KERN_CRIT "ps2cdvd: =============================\n");
		printk(KERN_CRIT "ps2cdvd:          wrong disc.         \n");
		printk(KERN_CRIT "ps2cdvd: =============================\n");
		if (!ps2cdvd_wrong_disc_retry) {
		  INIT_REQUEST;
		  while (CURRENT)
		    end_request(0);
		  disc_changed++;
		}
		new_state = STAT_INVALID_DISC;
	      } else {
		disc_lock_key = sum;
		if (!disc_lock_key_valid && disc_locked) {
		  DPRINT(DBG_DLOCK, "disc lock key=%lX\n", sum);
		}
		disc_lock_key_valid = 1;
		new_state = STAT_READY;
	      }
	    }
	    break;
	  }
	  break;
	case STAT_READY:
	  switch (ev->type) {
	  case EV_TICK:
	    if (CURRENT == NULL || ps2sif_iswaiting(ps2cdvd_lock)) {
	      break;
	    }
	    /* fall through */
	  case EV_START:
	  case EV_TIMEOUT:
	    if (ps2cdvd_lowlevel_lock() < 0) {
	      /* waiting for unlock... */
	      RESET_TIMER();
	      SET_TIMER(HZ * ps2cdvd_check_interval);
	      break;
	    }
	    if (CURRENT == NULL) {
	      if (ps2cdvd_spindown * HZ < jiffies - prev_read) {
		new_state = STAT_SPINDOWN;
	      } else {
		/* nothing to do */
		ps2cdvd_lowlevel_unlock();
		RESET_TIMER();
		SET_TIMER(HZ * ps2cdvd_check_interval);
	      }
	    } else {
	      prev_read = jiffies;
	      if (jiffies - prev_tray_check < HZ/2) {
		new_state = STAT_READ;
	      } else {
		prev_tray_check = jiffies;
		new_state = STAT_CHECK_TRAY;
	      }
	    }
	    break;
	  case EV_INTR:
	    break;
	  }
	  break;
	case STAT_CHECK_TRAY:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    if (carg->result < 0) {
	      new_state = STAT_ERROR;
	    } else {
	      struct sbr_cdvd_trayreq_arg *arg = carg->arg;
	      if (arg->traycount != 0) {
		if (disc_locked) {
		  printk(KERN_CRIT"ps2cdvd: =============================\n");
		  printk(KERN_CRIT"ps2cdvd: the disc is currently locked.\n");
		  printk(KERN_CRIT"ps2cdvd: please don't take it away!\n");
		  printk(KERN_CRIT"ps2cdvd: =============================\n");
		}

		invalidate_discinfo();

		new_state = STAT_CHECK_DISCTYPE;
	      } else {
		if (CURRENT) {
		  new_state = STAT_READ;
		} else {
		  new_state = STAT_READY;
		}
	      }
	    }
	    break;
	  }
	  break;
	case STAT_READ:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    new_state = STAT_READ_ERROR_CHECK;
	    break;
	  }
	  break;
	case STAT_READ_EOM_RETRY:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    new_state = STAT_READ_ERROR_CHECK;
	    break;
	  }
	  break;
	case STAT_READ_ERROR_CHECK:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    if (carg->result == SCECdErNO) {
	      /*
	       * succeeded
	       */
	      while (CURRENT != NULL &&
		     ps2cdvd_databuf_addr <= CURRENT->sector/4 &&
		     CURRENT->sector/4 < ps2cdvd_databuf_addr + ps2cdvd_databuf_size) {
		memcpy(CURRENT->buffer,
		       ps2cdvd_databuf + DATA_SECT_SIZE * (CURRENT->sector/4 - ps2cdvd_databuf_addr),
		       DATA_SECT_SIZE);
		end_request(1);
	      }
	      if (!ps2sif_iswaiting(ps2cdvd_lock) && CURRENT != NULL) {
		/* tiny acceleration */
		new_state = STAT_READ;
	      } else {
		new_state = STAT_READY;
	      }
	    } else
	    if (carg->result == 0x38) {
	      /*
	       * sector format error
	       */
	      DPRINT(DBG_DIAG,
		     "error: sector format error, code=0x38 (ignored)\n");
	      memset(CURRENT->buffer, 0, DATA_SECT_SIZE);
	      end_request(1);
	      if (!ps2sif_iswaiting(ps2cdvd_lock) && CURRENT != NULL) {
		/* tiny acceleration */
		new_state = STAT_READ;
	      } else {
		new_state = STAT_READY;
	      }
	    } else
	    if (carg->result == SCECdErEOM &&
		ps2cdvd_databuf_addr != 
			CURRENT->sector/4 - ps2cdvd_databuf_size + 1 &&
		ps2cdvd_databuf_size <= CURRENT->sector/4) {
	      /* you got End Of Media and you have not retried */
	      DPRINT(DBG_DIAG, "error: %s, code=0x%02x (retry...)\n",
		     ps2cdvd_geterrorstr(carg->result),
		     carg->result);
	      new_state = STAT_READ_EOM_RETRY;
	    } else {
	      DPRINT(DBG_DIAG, "error: %s, code=0x%02x\n",
		     ps2cdvd_geterrorstr(carg->result),
		     carg->result);
	      ps2cdvd_databuf_addr = -1;
	      end_request(0);		/* I/O error */
	      new_state = STAT_READY;
	    }
	    break;
	  }
	  break;
	case STAT_INVALID_DISC:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    if (ps2cdvd_lowlevel_lock() < 0) {
	      /* waiting for unlock... */
	      RESET_TIMER();
	      SET_TIMER(HZ * ps2cdvd_check_interval);
	    } else {
	      new_state = STAT_CHECK_DISCTYPE;
	    }
	    break;
	  case EV_INTR:
	    break;
	  }
	  break;
	case STAT_SPINDOWN:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    break;
	  case EV_INTR:
	    if (CURRENT == NULL) {
	      new_state = STAT_IDLE;
	    } else {
	      DPRINT(DBG_VERBOSE, "re-spinup...\n");
	      new_state = STAT_CHECK_DISCTYPE;
	    }
	    break;
	  }
	  break;
	case STAT_IDLE:
	  switch (ev->type) {
	  case EV_START:
	  case EV_TIMEOUT:
	    if (ps2cdvd_lowlevel_lock() < 0) {
	      /* waiting for unlock... */
	      RESET_TIMER();
	      SET_TIMER(HZ * ps2cdvd_check_interval);
	    } else {
	      new_state = STAT_CHECK_DISCTYPE;
	    }
	    break;
	  case EV_INTR:
	    break;
	  }
	  break;
	case STAT_ERROR:
	  break;
	default:
	  printk(KERN_ERR "ps2cdvd: invalid state");
	  ps2cdvd_state = STAT_WAIT_DISC;
	  break;
	}

	if (new_state != old_state) {
		struct ps2cdvd_event tick;
		tick.type = EV_TICK;
		ps2cdvd_leave(old_state);
		ps2cdvd_state = ps2cdvd_enter(new_state);
		DPRINT(DBG_STATE, "  -> new state: %s\n",
		       ps2cdvd_getstatestr(ps2cdvd_state));
		if (old_state != ps2cdvd_state &&
		    ps2cdvd_state == STAT_READY) {
			ps2cdvd_state_machine(&tick);
		}
		wake_up_interruptible(&statq);
	}

	restore_flags(flags);
}

__initfunc(int ps2cdvd_init(void))
{
	int res;

	DPRINT(DBG_VERBOSE, "init: get lock\n");
	if ((ps2cdvd_lock = ps2sif_getlock(PS2LOCK_CDVD)) == NULL) {
		printk(KERN_ERR "ps2cdvd: Can't get lock\n");
		ps2cdvd_cleanup();
		return -EINVAL;
	}
	ps2sif_lockqueueinit(&ps2cdvd_lock_qi);
	ps2cdvd_lock_qi.name = "ps2cdvd";

	DPRINT(DBG_VERBOSE, "init: initialize timer\n");
	init_timer(&io_timer);
	io_timer.function = (void(*)(u_long))ps2cdvd_timer;
	ps2cdvd_state = STAT_WAIT_DISC;

	DPRINT(DBG_VERBOSE, "init: allocate diaklabel buffer\n");
	labelbuf = kmalloc(2048, GFP_KERNEL);
	if (labelbuf == NULL) {
		printk(KERN_ERR "ps2cdvd: Can't allocate buffer\n");
		ps2cdvd_cleanup();
		return -ENOMEM;
	}
	initialized |= INIT_LABELBUF;

	DPRINT(DBG_VERBOSE, "allocate buffer\n");
	ps2cdvd_databufx = kmalloc(ps2cdvd_databuf_size * AUDIO_SECT_SIZE +
				   BUFFER_ALIGNMENT, GFP_KERNEL);
	if (ps2cdvd_databufx == NULL) {
		printk(KERN_ERR "ps2cdvd: Can't allocate buffer\n");
		ps2cdvd_cleanup();
		return -ENOMEM;
	}
	ps2cdvd_databuf = ALIGN(ps2cdvd_databufx, BUFFER_ALIGNMENT);
	initialized |= INIT_DATABUF;

	DPRINT(DBG_VERBOSE, "init: call sbios\n");
	if (ps2cdvdcall_init()) {
		printk(KERN_ERR "ps2cdvd: Can't initialize CD/DVD-ROM subsystem\n");
		ps2cdvd_cleanup();
		return -EIO;
	}
#ifdef CONFIG_PS2_SBIOS_VER_CHECK
	if (0x0201 <= sbios(SB_GETVER, NULL))
		ps2cdvdcall_reset();
#else
	ps2cdvdcall_reset();
#endif
	initialized |= INIT_IOPSIDE;

	DPRINT(DBG_VERBOSE, "init: register block device\n");
	if ((res = register_blkdev(MAJOR_NR, "ps2cdvd", &cdrom_fops)) < 0) {
		printk(KERN_ERR "ps2cdvd: Unable to get major %d for PS2 CD/DVD-ROM\n",
		       MAJOR_NR);
		ps2cdvd_cleanup();
                return -EIO;
	}
	if (MAJOR_NR == 0) MAJOR_NR = res;
	initialized |= INIT_BLKDEV;

	blksize_size[MAJOR_NR] = ps2cdvd_blocksizes;
	hardsect_size[MAJOR_NR] = ps2cdvd_hardsectsizes;
	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
	read_ahead[MAJOR_NR] = ps2cdvd_read_ahead;

	DPRINT(DBG_VERBOSE, "init: register cdrom\n");
	ps2cdvd_info.dev = MKDEV(MAJOR_NR, 0);
        if (register_cdrom(&ps2cdvd_info) != 0) {
		printk(KERN_ERR "ps2cdvd: Cannot register PS2 CD/DVD-ROM\n");
		ps2cdvd_cleanup();
		return -EIO;
        }
	initialized |= INIT_CDROM;

	printk(KERN_INFO "PS2 CD/DVD-ROM driver\n");

	if (ps2cdvd_lowlevel_lock() == 0)
	  ps2cdvd_state = ps2cdvd_enter(STAT_INIT_TRAYSTAT);
	else
	  ps2cdvd_state = ps2cdvd_enter(STAT_WAIT_DISC);

	return 0;
}
示例#21
0
static void
mcd_poll(void)
{
  int st;


  if (mcd_error) 
  {
    if (mcd_error & 0xA5) 
    {
      printk("mcd: I/O error 0x%02x", mcd_error);
      if (mcd_error & 0x80)
	printk(" (Door open)");
      if (mcd_error & 0x20)
	printk(" (Disk changed)");
      if (mcd_error & 0x04)
	{
	printk(" (Read error)"); /* Bitch about the problem. */
	
	/* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
	/* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
	/* But I find that rather HANDY!!! */
	/* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
	/* AJK [06/17/95] */
	
	/* Slap the CD down to single speed! */
	if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_2X_READ) 
		{
		MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */
		mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Beavis! */
		printk(" Speed now 1x");	 /* Pull my finger! */
		}
	}
      printk("\n");
      mcd_invalidate_buffers();
#ifdef WARN_IF_READ_FAILURE
      if (McdTries == MCD_RETRY_ATTEMPTS)
	printk("mcd: read of block %d failed\n", mcd_next_bn);
#endif
      if (!McdTries--) 
        {
	/* Nuts! This cd is ready for recycling! */
	/* When WAS the last time YOU cleaned it CORRECTLY?! */
	printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
	if (mcd_transfer_is_active) 
	{
	  McdTries = 0;
	  goto ret;
	}
	if (CURRENT_VALID)
	  end_request(0);
	McdTries = MCD_RETRY_ATTEMPTS;
      }
    }
    mcd_error = 0;
    mcd_state = MCD_S_STOP;
  }
	/* Switch back to Double speed if enough GOOD sectors were read! */
	
	/* Are we a double speed with a crappy CD?! */
    if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_PLAY_READ)
    	{
	/* We ARE a double speed and we ARE bitching! */
	if (mcd1xhold == 0) /* Okay, Like are we STILL at single speed? */
		{ /* We need to switch back to double speed now... */
		MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
		printk("mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
		}
	else mcd1xhold--; /* No?! Count down the good reads some more... */
				/* and try, try again! */
    	}



 immediately:
  switch (mcd_state) {



  case MCD_S_IDLE:
#ifdef TEST3
    printk("MCD_S_IDLE\n");
#endif
    return;



  case MCD_S_START:
#ifdef TEST3
    printk("MCD_S_START\n");
#endif

    outb(MCMD_GET_STATUS, MCDPORT(0));
    mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
    McdTimeout = 3000;
    break;



  case MCD_S_MODE:
#ifdef TEST3
    printk("MCD_S_MODE\n");
#endif

    if ((st = mcdStatus()) != -1) {

      if (st & MST_DSK_CHG) {
	mcdDiskChanged = 1;
	tocUpToDate = 0;
	mcd_invalidate_buffers();
      }

    set_mode_immediately:

      if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
	mcdDiskChanged = 1;
	tocUpToDate = 0;
	if (mcd_transfer_is_active) {
	  mcd_state = MCD_S_START;
	  goto immediately;
	}
	printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
	mcd_state = MCD_S_IDLE;
	while (CURRENT_VALID)
	  end_request(0);
	return;
      }

      outb(MCMD_SET_MODE, MCDPORT(0));
      outb(1, MCDPORT(0));
      mcd_mode = 1;
      mcd_state = MCD_S_READ;
      McdTimeout = 3000;

    }
    break;



  case MCD_S_READ:
#ifdef TEST3
    printk("MCD_S_READ\n");
#endif

    if ((st = mcdStatus()) != -1) {

      if (st & MST_DSK_CHG) {
	mcdDiskChanged = 1;
	tocUpToDate = 0;
	mcd_invalidate_buffers();
      }

    read_immediately:

      if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
	mcdDiskChanged = 1;
	tocUpToDate = 0;
	if (mcd_transfer_is_active) {
	  mcd_state = MCD_S_START;
	  goto immediately;
	}
	printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
	mcd_state = MCD_S_IDLE;
	while (CURRENT_VALID)
	  end_request(0);
	return;
      }

      if (CURRENT_VALID) {
	struct mcd_Play_msf msf;
	mcd_next_bn = CURRENT -> sector / 4;
	hsg2msf(mcd_next_bn, &msf.start);
	msf.end.min = ~0;
	msf.end.sec = ~0;
	msf.end.frame = ~0;
	sendMcdCmd(MCMD_DATA_READ, &msf);
	mcd_state = MCD_S_DATA;
	McdTimeout = READ_TIMEOUT;
      } else {
	mcd_state = MCD_S_STOP;
	goto immediately;
      }

    }
    break;


  case MCD_S_DATA:
#ifdef TEST3
    printk("MCD_S_DATA\n");
#endif

    st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
  data_immediately:
#ifdef TEST5
    printk("Status %02x\n",st);
#endif
    switch (st) {

    case MFL_DATA:
#ifdef WARN_IF_READ_FAILURE
      if (McdTries == 5)
	printk("mcd: read of block %d failed\n", mcd_next_bn);
#endif
      if (!McdTries--) {
	printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
	if (mcd_transfer_is_active) {
	  McdTries = 0;
	  break;
	}
	if (CURRENT_VALID)
	  end_request(0);
	McdTries = 5;
      }
      mcd_state = MCD_S_START;
      McdTimeout = READ_TIMEOUT;
      goto immediately;

    case MFL_STATUSorDATA:
      break;

    default:
      McdTries = 5;
      if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {
	mcd_state = MCD_S_STOP;
	goto immediately;
      }
      mcd_buf_bn[mcd_buf_in] = -1;
      READ_DATA(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in, 2048);
      mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
      if (mcd_buf_out == -1)
	mcd_buf_out = mcd_buf_in;
      mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
      if (!mcd_transfer_is_active) {
	while (CURRENT_VALID) {
	  mcd_transfer();
	  if (CURRENT -> nr_sectors == 0)
	    end_request(1);
	  else
	    break;
	}
      }

      if (CURRENT_VALID
	  && (CURRENT -> sector / 4 < mcd_next_bn || 
	      CURRENT -> sector / 4 > mcd_next_bn + 16)) {
	mcd_state = MCD_S_STOP;
	goto immediately;
      }
      McdTimeout = READ_TIMEOUT;
#ifdef DOUBLE_QUICK_ONLY
      if (MCMD_DATA_READ != MCMD_PLAY_READ)
#endif
      {
	int count= QUICK_LOOP_COUNT;
	while (count--) {
          QUICK_LOOP_DELAY;
	  if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
#   ifdef TEST4
/*	    printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */
	    printk(" %d ",QUICK_LOOP_COUNT-count);
#   endif
	    goto data_immediately;
	  }
	}
#   ifdef TEST4
/*      printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */
	printk("ended ");
#   endif
      }
      break;
    }
    break;



  case MCD_S_STOP:
#ifdef TEST3
    printk("MCD_S_STOP\n");
#endif

#ifdef WORK_AROUND_MITSUMI_BUG_93
    if (!mitsumi_bug_93_wait)
      goto do_not_work_around_mitsumi_bug_93_1;

    McdTimeout = mitsumi_bug_93_wait;
    mcd_state = 9+3+1;
    break;

  case 9+3+1:
    if (McdTimeout)
      break;

  do_not_work_around_mitsumi_bug_93_1:
#endif /* WORK_AROUND_MITSUMI_BUG_93 */

    outb(MCMD_STOP, MCDPORT(0));

#ifdef WORK_AROUND_MITSUMI_BUG_92
    if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
      int i = 4096;
      do {
	inb(MCDPORT(0));
      } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
      outb(MCMD_STOP, MCDPORT(0));
      if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
	i = 4096;
	do {
	  inb(MCDPORT(0));
	} while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
	outb(MCMD_STOP, MCDPORT(0));
      }
    }
#endif /* WORK_AROUND_MITSUMI_BUG_92 */

    mcd_state = MCD_S_STOPPING;
    McdTimeout = 1000;
    break;

  case MCD_S_STOPPING:
#ifdef TEST3
    printk("MCD_S_STOPPING\n");
#endif

    if ((st = mcdStatus()) == -1 && McdTimeout)
      break;

    if ((st != -1) && (st & MST_DSK_CHG)) {
      mcdDiskChanged = 1;
      tocUpToDate = 0;
      mcd_invalidate_buffers();
    }

#ifdef WORK_AROUND_MITSUMI_BUG_93
    if (!mitsumi_bug_93_wait)
      goto do_not_work_around_mitsumi_bug_93_2;

    McdTimeout = mitsumi_bug_93_wait;
    mcd_state = 9+3+2;
    break;

  case 9+3+2:
    if (McdTimeout)
      break;

    st = -1;

  do_not_work_around_mitsumi_bug_93_2:
#endif /* WORK_AROUND_MITSUMI_BUG_93 */

#ifdef TEST3
    printk("CURRENT_VALID %d mcd_mode %d\n",
	   CURRENT_VALID, mcd_mode);
#endif

    if (CURRENT_VALID) {
      if (st != -1) {
	if (mcd_mode == 1)
	  goto read_immediately;
	else
	  goto set_mode_immediately;
      } else {
	mcd_state = MCD_S_START;
	McdTimeout = 1;
      }
    } else {
      mcd_state = MCD_S_IDLE;
      return;
    }
    break;

  default:
    printk("mcd: invalid state %d\n", mcd_state);
    return;
  }

 ret:
  if (!McdTimeout--) {
    printk("mcd: timeout in state %d\n", mcd_state);
    mcd_state = MCD_S_STOP;
  }

  SET_TIMER(mcd_poll, 1);
}
示例#22
0
文件: route.c 项目: F0rth/pimd
/*
 * TODO: when cache miss, check the iif, because probably ASSERTS
 * shoult take place
 */
static void process_cache_miss(struct igmpmsg *igmpctl)
{
    u_int32 source, mfc_source;
    u_int32 group;
    u_int32 rp_addr;
    vifi_t iif;
    mrtentry_t *mrtentry_ptr;
    mrtentry_t *mrtentry_rp;

    /*
     * When there is a cache miss, we check only the header of the packet
     * (and only it should be sent up by the kernel.
     */

    group  = igmpctl->im_dst.s_addr;
    source = mfc_source = igmpctl->im_src.s_addr;
    iif    = igmpctl->im_vif;

    IF_DEBUG(DEBUG_MFC)
        logit(LOG_DEBUG, 0, "Cache miss, src %s, dst %s, iif %d",
              inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), iif);

    /* TODO: XXX: check whether the kernel generates cache miss for the
     * LAN scoped addresses
     */
    if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
        return; /* Don't create routing entries for the LAN scoped addresses */

    /* TODO: check if correct in case the source is one of my addresses */
    /* If I am the DR for this source, create (S,G) and add the register_vif
     * to the oifs.
     */
    if ((uvifs[iif].uv_flags & VIFF_DR)
        && (find_vif_direct_local(source) == iif)) {
        mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE);
        if (mrtentry_ptr == (mrtentry_t *)NULL)
            return;
        mrtentry_ptr->flags &= ~MRTF_NEW;
        /* set reg_vif_num as outgoing interface ONLY if I am not the RP */
        if (mrtentry_ptr->group->rpaddr != my_cand_rp_address)
            VIFM_SET(reg_vif_num, mrtentry_ptr->joined_oifs);
        change_interfaces(mrtentry_ptr,
                          mrtentry_ptr->incoming,
                          mrtentry_ptr->joined_oifs,
                          mrtentry_ptr->pruned_oifs,
                          mrtentry_ptr->leaves,
                          mrtentry_ptr->asserted_oifs, 0);
    }
    else {
        mrtentry_ptr = find_route(source, group,
                                  MRTF_SG | MRTF_WC | MRTF_PMBR,
                                  DONT_CREATE);
        if (mrtentry_ptr == (mrtentry_t *)NULL)
            return;
    }

    /* TODO: if there are too many cache miss for the same (S,G), install
     * negative cache entry in the kernel (oif==NULL) to prevent too
     * many upcalls.
     */

    if (mrtentry_ptr->incoming == iif) {
        if (!VIFM_ISEMPTY(mrtentry_ptr->oifs)) {
            if (mrtentry_ptr->flags & MRTF_SG) {
                /* TODO: check that the RPbit is not set? */
                /* TODO: XXX: TIMER implem. dependency! */
                if (mrtentry_ptr->timer < PIM_DATA_TIMEOUT)
                    SET_TIMER(mrtentry_ptr->timer, PIM_DATA_TIMEOUT);
                if (!(mrtentry_ptr->flags & MRTF_SPT)) {
                    if ((mrtentry_rp = mrtentry_ptr->group->grp_route) ==
                        (mrtentry_t *)NULL)
                        mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
                    if (mrtentry_rp != (mrtentry_t *)NULL) {
                        /* Check if the (S,G) iif is different from
                         * the (*,G) or (*,*,RP) iif
                         */
                        if ((mrtentry_ptr->incoming != mrtentry_rp->incoming)
                            || (mrtentry_ptr->upstream != mrtentry_rp->upstream)) {
                            mrtentry_ptr->flags |= MRTF_SPT;
                            mrtentry_ptr->flags &= ~MRTF_RP;
                        }
                    }
                }
            }
            if (mrtentry_ptr->flags & MRTF_PMBR)
                rp_addr = mrtentry_ptr->source->address;
            else
                rp_addr = mrtentry_ptr->group->rpaddr;
            mfc_source = source;
#ifdef KERNEL_MFC_WC_G
            if (mrtentry_ptr->flags & (MRTF_WC | MRTF_PMBR))
                if (!(mrtentry_ptr->flags & MRTF_MFC_CLONE_SG))
                    mfc_source = INADDR_ANY_N;
#endif /* KERNEL_MFC_WC_G */
            add_kernel_cache(mrtentry_ptr, mfc_source, group, MFC_MOVE_FORCE);
#ifdef SCOPED_ACL
            APPLY_SCOPE(group,mrtentry_ptr);
#endif
            k_chg_mfc(igmp_socket, mfc_source, group, iif, mrtentry_ptr->oifs,
                      rp_addr);
            /* TODO: XXX: No need for RSRR message, because nothing has
             * changed.
             */
        }

        return; /* iif match */
    }

    /* The iif doesn't match */
    if (mrtentry_ptr->flags & MRTF_SG) {
        if (mrtentry_ptr->flags & MRTF_SPT)
            /* Arrived on wrong interface */
            return;
        if ((mrtentry_rp = mrtentry_ptr->group->grp_route) ==
            (mrtentry_t *)NULL)
            mrtentry_rp =
                mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
        if (mrtentry_rp != (mrtentry_t *)NULL) {
            if (mrtentry_rp->incoming == iif) {
                /* Forward on (*,G) or (*,*,RP) */
#ifdef KERNEL_MFC_WC_G
                if (!(mrtentry_rp->flags & MRTF_MFC_CLONE_SG))
                    mfc_source = INADDR_ANY_N;
#endif /* KERNEL_MFC_WC_G */
                add_kernel_cache(mrtentry_rp, mfc_source, group, 0);
/* marian: not sure if we are going to reach here for our scoped traffic */
#ifdef SCOPED_ACL
                APPLY_SCOPE(group,mrtentry_ptr);
#endif
                k_chg_mfc(igmp_socket, mfc_source, group, iif,
                          mrtentry_rp->oifs, mrtentry_ptr->group->rpaddr);
#ifdef RSRR
                rsrr_cache_send(mrtentry_rp, RSRR_NOTIFICATION_OK);
#endif /* RSRR */
            }
        }

        return;
    }
}