Example #1
0
void alsa_cleanup() {
	dev_stop();
	if (hparams != NULL) snd_pcm_hw_params_free(hparams);
	free_ringbuf(rbuf);
	rbuf = NULL;
	return;
	}
Example #2
0
SANE_Status ret_cancel(struct device *dev, SANE_Status ret)
{
  dev_cmd(dev, CMD_ABORT);
  if (dev->scanning) {
    dev_stop(dev);
    dev->state = SANE_STATUS_CANCELLED;
  }
  return ret;
}
Example #3
0
static int new_obj(lua_State *lstate) {
	dev_stop();
	lua_newtable(lstate);
	set_value(lstate, "card");
	set_userdata(lstate, "intern", (void *)&unit);
	add_method(lstate, "capture", capture);
	add_method(lstate, "stop", lua_stop);
	add_fader_methods(lstate);
	return 1;
	}
Example #4
0
static void close_card(ALSA_CARD *card) {
	dev_stop(card);
	if (card->handle != NULL) {
		snd_pcm_hw_params_free(card->hparams);
		snd_pcm_close(card->handle);
		card->handle = NULL;
		}
	if (card->ringbuf != NULL) jack_ringbuffer_free(card->ringbuf);
	shutdown_source(&card->base);
	log_msg("ALSA: close card %s '%s'\n", card->device, card->name);
	free(card->device);
	free(card->name);
	free(card);
	return;
	}
Example #5
0
static void
cleanup(void)
{
#ifdef DEBUG_MEMORY
	struct interface *ifp;
	int i;

	free(duid);
	free_options(if_options);

	if (ifaces) {
		while ((ifp = TAILQ_FIRST(ifaces))) {
			TAILQ_REMOVE(ifaces, ifp, next);
			free_interface(ifp);
		}
		free(ifaces);
	}

	for (i = 0; i < ifac; i++)
		free(ifav[i]);
	free(ifav);
	for (i = 0; i < ifdc; i++)
		free(ifdv[i]);
	free(ifdv);
#endif

	if (!(options & DHCPCD_FORKED))
		dev_stop();
	if (linkfd != -1)
		close(linkfd);
	if (pidfd > -1) {
		if (options & DHCPCD_MASTER) {
			if (control_stop() == -1)
				syslog(LOG_ERR, "control_stop: %m");
		}
		close(pidfd);
		unlink(pidfile);
	}
#ifdef DEBUG_MEMORY
	free(pidfile);
#endif

	if (options & DHCPCD_STARTED && !(options & DHCPCD_FORKED))
		syslog(LOG_INFO, "exited");
}
Example #6
0
static int lua_stop(lua_State *lstate) {
	lua_pop(lstate, 1);
	dev_stop();
	return 0;
	}
Example #7
0
int loop_socket_handle(int socket, int tt_ms)
{
	unsigned char outhexbuf[ONE_TCP_MAX_LEN] = {0};
	PRO *pro = (PRO*)malloc(sizeof(PRO));
	memset(pro, 0, sizeof(PRO));
	pro->payload = (unsigned char*)malloc(ONLINE_MAX_LEN);
	memset(pro->payload, 0, (ONLINE_MAX_LEN));
	
	int ret = 0;
	int login_ok = 0;
	unsigned int sendseq = 0;
	int outinx = 0;
	int hexlen = 0;
	MACH_STAT stat = IDLE;
	
	while(1) {
		debug(LOG_NOTICE, "stat=%d,login_flag=%d,outinx=%d,last_cmd=%04x,last_recv_ret=%d,dev_work_status=%d\n",
							stat,login_ok,outinx,pro->hd.cmd,ret,dev_work_status);
		switch(stat) {
			case IDLE:
				//sleep_intp_s(5); //will block tcp recving
				break;
				
			case TO_LOGIN:
				memset(&pro->hd, 0, sizeof(PRO_HD));
				memset(pro->payload, 0, (ONLINE_MAX_LEN));
				send_login_info(socket, pro, sendseq++);
				break;
				
			case TO_DEVSTATUS:
				//recv_uart();
				//send_dev_data();
				if(glb_cfg.glb_sock != socket)
					glb_cfg.glb_sock = socket; // uart thread will write glb_sock directly.
				break;
				
			case TO_WORKSTATUS:
				memset(pro->payload, 0, (ONLINE_MAX_LEN));
				if(dev_work_status == E_DEV_TAKEUP) {
					send_busy_info(socket, pro, dev_work_status, sendseq++);
				} else {
					send_status_info(socket, pro, dev_work_status, sendseq++);
				}
				stat = IDLE;
				break;

			case TO_RESPSTATUS:
				memset(pro->payload, 0, (ONLINE_MAX_LEN));
				response_status_info(socket, pro, dev_work_status, sendseq++);
				stat = IDLE;
				break;
			
			case TO_HEART:
				memset(&pro->hd, 0, sizeof(PRO_HD));
				send_heart_info(socket, &pro->hd, sendseq++);
				if(outinx++ > HEART_EXIT_COUNT)
					goto EXIT_ERR;
				else
					stat = IDLE;
				break;
				
			case TO_RESP:
				//for testing;all back
				pro->hd.stat = PRO_RSP;
				memset(outhexbuf, 0, sizeof(outhexbuf));
				hexlen = 0;
				pro_pro2hexbuf(pro,outhexbuf,&hexlen);
				send(socket, outhexbuf, hexlen, sendseq++);
				debug(LOG_DEBUG, "Send Resp Len:%d\n",hexlen);
				stat = IDLE;
				break;
				
			case NET_DISCONN:
				goto EXIT_ERR;
				break;
			
			default:
				break;
		}
		
		//memset(pro, 0, sizeof(PRO)); //NOTE***: will init payload as NULL; this will cause crash!!!
		memset(&pro->hd, 0, sizeof(PRO_HD));
		memset(pro->payload, 0, (ONLINE_MAX_LEN));
		ret = socket_recv_tt(socket, pro, tt_ms);
		if(ret == 0) {
			// timeout
			if(!login_ok) {
				stat = TO_LOGIN;
			} else {
				stat = TO_HEART;
			}
		} else if(ret < 0) {
			// socket error
			goto EXIT_ERR;
			
		} else if( (ret != sizeof(PRO_HD)) && 
				   (ret != sizeof(PRO_HD)+pro->hd.len) ) {
			debug(LOG_NOTICE, "Recv Length %d Error!\n",ret);
			continue;
		} else {
			// handle data...
			switch(pro->hd.cmd) {
				case IDM_DEV_LOGIN:
					debug(LOG_NOTICE, "---< server back: login\n");
					login_ok = 1;
					if(dev_work_status != E_DEV_TAKEUP)
						dev_work_status = E_DEV_ONLINE;
					stat = TO_DEVSTATUS;
					break;
					
				case IDM_DEV_HEART:
					debug(LOG_NOTICE, "---< server back: heart\n");
					outinx = 0;
					break;
				
				case IDM_GETDEV:
					debug(LOG_NOTICE, "---< server cmd: get dev\n");
					stat = TO_RESPSTATUS;
					break;

				/* for response testing */
				case 0xfffe:
					debug(LOG_NOTICE, "---< server cmd: test response\n");
					stat = TO_RESP;
					break;
					
				case IDM_TAKEUPDEV:
				case IDM_RELEASEDEV:
				case IDM_RESET:
				case IDM_DOSTART:
				case IDM_DOSTOP:
				case IDM_SETPARS:
				case IDM_DELPARS:
					if(0 == memcmp(taskid, pro->payload+32, 32)) {
						break;
					} else {
						if(dev_work_status == E_DEV_TAKEUP) {
							debug(LOG_WARNING, "---< server taskid is not correct!\n");
							stat = TO_WORKSTATUS;
							continue;
						} else {
							/* Firstly takeup device */
							break;
						}
					}
				default:
					debug(LOG_ERR, "==== Handle: Unknow Server CMD 0x%02x\n", pro->hd.cmd);
					continue;
			}
			
			switch(pro->hd.cmd) {
				/* handle at local */
				case IDM_TAKEUPDEV:
					debug(LOG_NOTICE, "---< server cmd: takeup dev\n");
					dev_work_status = E_DEV_TAKEUP;
					stat = TO_WORKSTATUS;
					memcpy(taskid, pro->payload+32, sizeof(taskid)); /* skip devid 32*/
					break;

				case IDM_RELEASEDEV:
					debug(LOG_NOTICE, "---< server cmd: release dev\n");
					dev_work_status = E_DEV_ONLINE;
					stat = TO_WORKSTATUS;
					memset(taskid, 0, sizeof(taskid));
					break;
				
				/* send to uart */
				case IDM_RESET:
					debug(LOG_NOTICE, "---< server cmd: reset dev\n");
					dev_work_status = E_DEV_ONLINE;
					stat = TO_WORKSTATUS;
					/* stop and clear */
					dev_reset(pro->payload, pro->hd.len);
					break;

				case IDM_DOSTART:
					debug(LOG_NOTICE, "---< server cmd: start dev\n");
					glb_cfg.rsp_cmd_type = SVR_NEED_TASK_RET;
					glb_cfg.rsp_cmd_type |= SVR_NEED_TASK_PERCT;
					/* only send payload to uart */
					ret = dev_start(pro->payload, pro->hd.len);
					debug(LOG_DEBUG, "---Send To Com ret %d\n",ret);
					break;

				case IDM_DOSTOP:
					debug(LOG_NOTICE, "---< server cmd: stop dev\n");
					glb_cfg.rsp_cmd_type = SVR_NEED_TASK_RET;
					/* only send payload to uart */
					ret = dev_stop(pro->payload, pro->hd.len);
					debug(LOG_DEBUG, "---Send To Com ret %d\n",ret);
					break;

				case IDM_SETPARS:
					debug(LOG_NOTICE, "---< server cmd: set params dev\n");
					/* only send params to uart */
					ret = dev_setpar(pro->payload+64+2, (pro->hd.len-66)>0?(pro->hd.len-66):0);
					debug(LOG_DEBUG, "---Send To Com ret %d\n",ret);
					break;

				case IDM_DELPARS:
					debug(LOG_NOTICE, "---< server cmd: del params\n");
					/* only send payload to uart */
					ret = dev_clrpar(pro->payload, pro->hd.len);
					debug(LOG_DEBUG, "---Send To Com ret %d\n",ret);
					break;
			}
		}
		
		continue;
	} /* end while(1) */
	
EXIT_ERR:
	debug(LOG_NOTICE, "<--- Socket recv out!\n");
	glb_cfg.glb_sock = -1;
	glb_cfg.rsp_cmd_type = 0;
	if(socket > 0) close(socket);
	if(pro && pro->payload) {
		free(pro->payload);
		free(pro);
	}
	return -1;
}
Example #8
0
static SCM capture_stop(SCM card) {
	dev_stop((ALSA_CARD *)((SOURCE_HANDLE *)SCM_SMOB_DATA(card))->body);
	return SCM_UNSPECIFIED;
	}
Example #9
0
SANE_Status
sane_start (SANE_Handle h)
{
  struct device *dev = h;

  DBG (3, "%s: %p\n", __FUNCTION__, h);

  dev->cancel = 0;
  dev->scanning = 0;
  dev->total_img_size = 0;
  dev->total_out_size = 0;
  dev->total_data_size = 0;
  dev->blocks = 0;

  if (!dev->reserved) {
    if (!dev_cmd_wait(dev, CMD_RESERVE_UNIT))
      return dev->state;
    dev->reserved++;
  }

  if (!dev_set_window(dev) ||
      (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY))
    return dev_stop(dev);

  if (!dev_cmd_wait(dev, CMD_OBJECT_POSITION))
    return dev_stop(dev);

  if (!dev_cmd(dev, CMD_READ) ||
      (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY))
    return dev_stop(dev);

  dev->scanning = 1;
  dev->final_block = 0;
  dev->blocklen = 0;
  dev->pixels_per_line = 0;
  dev->bytes_per_line = 0;
  dev->ulines = 0;

  set_parameters(dev);

  if (!dev->data && !(dev->data = malloc(DATASIZE)))
    return ret_cancel(dev, SANE_STATUS_NO_MEM);

  if (!dev_acquire(dev))
    return dev->state;

  /* make sure to have dev->para <= of real size */
  if (dev->para.pixels_per_line > dev->pixels_per_line) {
    dev->para.pixels_per_line = dev->pixels_per_line;
    dev->para.bytes_per_line = dev->pixels_per_line;
  }

  if (dev->composition == MODE_RGB24)
    dev->para.bytes_per_line = dev->para.pixels_per_line * 3;
  else if (dev->composition == MODE_LINEART ||
	   dev->composition == MODE_HALFTONE) {
    dev->para.bytes_per_line = (dev->para.pixels_per_line + 7) / 8;
    dev->para.pixels_per_line = dev->para.bytes_per_line * 8;
  } else {
    dev->para.bytes_per_line = dev->para.pixels_per_line;
  }

  dev->total_img_size = dev->para.bytes_per_line * dev->para.lines;

  return SANE_STATUS_GOOD;
}
Example #10
0
SANE_Status
sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * lenp)
{
  SANE_Status status;
  struct device *dev = h;

  DBG (3, "%s: %p, %p, %d, %p\n", __FUNCTION__, h, buf, maxlen, (void *)lenp);

  if (lenp)
    *lenp = 0;
  if (!dev)
    return SANE_STATUS_INVAL;

  if (!dev->scanning)
    return SANE_STATUS_EOF;

  /* if there is no data to read or output from buffer */
  if (!dev->blocklen && dev->datalen <= PADDING_SIZE) {

    /* and we don't need to acquire next block */
    if (dev->final_block) {
      int slack = dev->total_img_size - dev->total_out_size;

      /* but we may need to fill slack */
      if (buf && lenp && slack > 0) {
	*lenp = fill_slack(dev, buf, maxlen);
	dev->total_out_size += *lenp;
	DBG (9, "<> slack: %d, filled: %d, maxlen %d\n",
	     slack, *lenp, maxlen);
	return SANE_STATUS_GOOD;
      } else if (slack < 0) {
	/* this will never happen */
	DBG(1, "image overflow %d bytes\n", dev->total_img_size - dev->total_out_size);
      }

      /* that's all */
      dev_stop(dev);
      return SANE_STATUS_EOF;
    }

    /* queue next image block */
    if (!dev_acquire(dev))
      return dev->state;
  }

  if (!dev->reading) {
    if (cancelled(dev))
      return dev->state;
    DBG (5, "READ_IMAGE\n");
    if (!dev_cmd(dev, CMD_READ_IMAGE))
      return SANE_STATUS_IO_ERROR;
    dev->reading++;
    dev->ulines += dev->vertical;
    dev->y_off = dev->ulines - dev->vertical;
    dev->total_data_size += dev->blocklen;
    dev->blocks++;
  }

  do {
    size_t datalen;
    int clrlen; /* cleared lines len */
    int olen; /* output len */

    /* read as much data into the buffer */
    datalen = DATAROOM(dev) & USB_BLOCK_MASK;
    while (datalen && dev->blocklen) {
      SANE_Byte *rbuf = dev->data + DATATAIL(dev);

      DBG (9, "<> request len: %lu, [%d, %d; %d]\n",
	   (u_long)datalen, dev->dataoff, DATATAIL(dev), dev->datalen);
      if ((status = dev->io->dev_request(dev, NULL, 0, rbuf, &datalen)) !=
	  SANE_STATUS_GOOD)
	return status;
      dev->datalen += datalen;
      dev->blocklen -= datalen;
      DBG (9, "<> got %lu, [%d, %d; %d]\n",
	   (u_long)datalen, dev->dataoff, DATATAIL(dev), dev->datalen);
      if (dev->blocklen < 0)
	return ret_cancel(dev, SANE_STATUS_IO_ERROR);

      datalen = DATAROOM(dev) & USB_BLOCK_MASK;
    }

    if (buf && lenp) { /* read mode */
      /* copy will do minimal of valid data */
      if (dev->para.format == SANE_FRAME_RGB && dev->line_order)
	clrlen = copy_mix_bands_trim(dev, buf, maxlen, &olen);
      else
	clrlen = copy_plain_trim(dev, buf, maxlen, &olen);

      dev->datalen -= clrlen;
      dev->dataoff = (dev->dataoff + clrlen) & DATAMASK;
      buf += olen;
      maxlen -= olen;
      *lenp += olen;
      dev->total_out_size += olen;

      DBG (9, "<> olen: %d, clrlen: %d, blocklen: %d/%d, maxlen %d (%d %d %d)\n",
	   olen, clrlen, dev->blocklen, dev->datalen, maxlen,
	   dev->dataindex / dev->bytes_per_line + dev->y_off,
	   dev->y_off, dev->para.lines);

      /* slack beyond last line */
      if (dev->dataindex / dev->bytes_per_line + dev->y_off >= dev->para.lines) {
	dev->datalen = 0;
	dev->dataoff = 0;
      }

      if (!clrlen || maxlen <= 0)
	break;
    } else { /* flush mode */
      dev->datalen = 0;
      dev->dataoff = 0;
    }

  } while (dev->blocklen);

  if (lenp)
    DBG (9, " ==> %d\n", *lenp);

  return SANE_STATUS_GOOD;
}
Example #11
0
int main(int argc, char **argv)
{
#define IOCTL_ERROR(__str) \
	do { \
		msg(MSG_ERR, "%s: Error during ioctl call\n", __str);\
		dev_close();\
		cd_device = NULL;\
		is_error = TRUE;\
	} while (0)

	int opt;
	int opt_index;
	int tracklist = -1;
	static struct option options[] = {
		{"help", 0, 0, 'h'},
		{"version", 0, 0, 'V'},
		{"device", 1, 0, 'd'},
		{"noscan", 0, 0, 'n'},
		{"slave", 0, 0, 's'},
		{0, 0, 0, 0}
	};
	char *cmd_str = NULL;
	size_t line_len;
	char *cmd_ptr = NULL;
	command_t cmd;
	char *cd_device = NULL;
	char *tmp_device = NULL;
	char **device_list = NULL;
	int num_devices = 0;
	unsigned short slave = 0;
	int arg_val;
	int noscan = 0;
	int i;
	int is_error = FALSE;
	dev_status_t status;
	
	while ((opt = getopt_long(argc, argv, "hvVd:ns",
			options, &opt_index)) != -1) {
		switch (opt) {
			case 'h':
				msg(MSG_STD, "help not implemented yet... sorry\n");
				exit(0);
				break;
			case 'V':
				msg(MSG_STD, "Maja's CD player, version " VERSION "\n");
				exit(0);
				break;
			case 'd':
				cd_device = optarg;
				break;
			case 'n':
				noscan = 1;
				break;
			case 's':
				slave = 1;
				break;
			default:
				break;
		}
	}
	if ((!cd_device) && (noscan) && (!slave)) {
		msg(MSG_ERR, "No device specified and scanning prohibited. "
				"Don't know what to do.\nExiting.\n\n");
		return EXIT_FAILURE;
	}
	if (cd_device) {
		if (dev_open(cd_device) < 0) {
			msg(MSG_ERR, "Error opening device %s\n", cd_device);
			return EXIT_FAILURE;
		}
		dev_prepare();
		if (!dev_isaudio()) {
			msg(MSG_STD, "%s: no audio disc\n", cd_device);
			dev_close();
			cd_device = NULL;
			is_error = TRUE;
		}
	}
	
	num_devices = get_cd_devices(&device_list);
	if (!cd_device && !noscan && !is_error) {
		msg(MSG_STD, "Scanning devices...\n");
		for (i = 0; i < num_devices; i++) {
			cd_device = device_list[i];
			if (dev_open(cd_device) < 0)
				msg(MSG_STD, "%s: could not open", cd_device);
			dev_prepare();
			if (dev_isaudio()) {
				msg(MSG_STD, "%s: OK\n", cd_device);
				break;
			} else
				msg(MSG_STD, "%s: no audio disc\n", cd_device);
			dev_close();
			cd_device = NULL;
		}
	}
	if ((!cd_device) && (!slave)) {
		msg(MSG_ERR, "No usable CD device found.\n");
		free_list(&device_list, num_devices);
		return EXIT_FAILURE;
	}
	if (slave) {
		msg(MSG_STD, is_error ? "ERROR\n" : "OK\n");
	}
	if (optind == argc) {
		if (!slave) {
			msg(MSG_STD, "No command given\n");
			free_list(&device_list, num_devices);
			return EXIT_FAILURE;
		}
	} else if (argv[optind])
		cmd_str = strdup(argv[optind]);
	
	do {
		is_error = FALSE;
		if ((!cmd_str) && (slave)) {
			if (getline(&cmd_str, &line_len, stdin) < 0) {
				free(cmd_str);
				cmd_str = strdup("quit");
			}
			if ((cmd_ptr = strrchr(cmd_str, '\n')))
				*cmd_ptr = '\0';
		}
		if ((!cd_device)
				&& (strncmp(cmd_str, "device", 6) != 0)
				&& (strcmp(cmd_str, "scan") != 0)
				&& (strcmp(cmd_str, "quit") != 0)) {
			msg(MSG_STD, "No device opened. "
					"Only 'scan', 'device' and 'quit' commands are allowed\n");
			msg(MSG_STD, "ERROR\n");
			free(cmd_str);
			cmd_str = NULL;
			continue;
		}
		switch (cmd = get_cmd_num(cmd_str)) {
			case CMD_PLAY:
				arg_val = -1;
				if (++optind < argc)
					arg_val = atoi(argv[optind]);
				cmd_ptr = &(cmd_str[4]);
				while (*cmd_ptr == ' ')
					cmd_ptr++;
				if ((arg_val < 0) && (*cmd_ptr != '\0'))
					arg_val = atoi(cmd_ptr);
				if (arg_val <= 0)
					arg_val = 1;
				if (dev_query_status(&status, &tracklist, NULL, NULL) < 0)
					IOCTL_ERROR("Play");
				else {
					if ((status != ST_PLAYING) || (arg_val != tracklist)) {
						STATUS_OUT(cd_device, arg_val, "Playing", 0U, 0U);
						if (dev_play(arg_val) < 0)
							IOCTL_ERROR("Play");
					} else
						if (print_status(cd_device) < 0)
							IOCTL_ERROR("Play");
					tracklist = -1;
				}
				break;
			case CMD_STOP:
				if (dev_stop() < 0)
					IOCTL_ERROR("Stop");
				break;
			case CMD_PAUSE:
				if (dev_pause() < 0)
					IOCTL_ERROR("Pause");
				break;
			case CMD_NEXT:
				if ((dev_query_status(NULL, &tracklist, NULL, NULL) < 0) ||
						(dev_stop < 0) || (dev_play(tracklist + 1) < 0))
					IOCTL_ERROR("Next");
				break;
			case CMD_PREV:
				if ((dev_query_status(NULL, &tracklist, NULL, NULL) < 0) ||
						(dev_stop < 0) || (dev_play(tracklist - 1) < 0))
					IOCTL_ERROR("Prev");
				break;
			case CMD_TOGGLE:
				if ((dev_query_status(&status, NULL, NULL, NULL) < 0) ||
						((status == ST_PLAYING) && (dev_pause() < 0)) ||
						((status == ST_PAUSED) && (dev_resume() < 0)))
					IOCTL_ERROR("Toggle");
				break;
			case CMD_EJECT:
				if (dev_eject() < 0)
					IOCTL_ERROR("Eject");
				break;
			case CMD_CLOSE:
				if (dev_close_tray() < 0)
					IOCTL_ERROR("Close");
				break;
			case CMD_STATUS:
				if (print_status(cd_device) < 0)
					IOCTL_ERROR("Status");
				break;
			case CMD_INFO:
				if (print_info(cd_device) < 0)
					is_error = TRUE;
				break;
			case CMD_SCAN:
				dev_close();
				for (i = 0; i < num_devices; i++) {
					tmp_device = device_list[i];
					if (dev_open(tmp_device) < 0) {
						msg(MSG_STD, "%s: could not open\n", tmp_device);
						msg(MSG_STD, "ERROR\n");
						is_error = TRUE;
						continue;
					}
					dev_prepare();
					if (dev_isaudio())
						msg(MSG_STD, "%s: OK\n", tmp_device);
					else
						msg(MSG_STD, "%s: no audio disc\n", tmp_device);
					dev_close();
				}
				if (cd_device) {
					if (dev_open(cd_device) < 0) {
						msg(MSG_STD, "%s: error reopening\n", cd_device);
						is_error = TRUE;
					} else
						dev_prepare();
				}
				break;
			case CMD_DEVICE:
				cmd_ptr = &(cmd_str[6]);
				while (*cmd_ptr == ' ')
					++cmd_ptr;
				is_error = TRUE;
				if (*cmd_ptr == '\0') {
					for(i = 0; i < num_devices; i++)
						msg(MSG_STD, "%s\n", device_list[i]);
					is_error = FALSE;
				} else {
					dev_close();
					for (i = 0; i < num_devices; i++) {
						if(strcmp(cmd_ptr, device_list[i]) != 0)
							continue;
						tmp_device = device_list[i];
						if (dev_open(tmp_device) < 0) {
							msg(MSG_STD, "%s: could not open\n", tmp_device);
							msg(MSG_STD, "ERROR\n");
						} else {
							dev_prepare();
							if (!dev_isaudio())
								msg(MSG_STD, "%s: no audio disc\n",
										tmp_device);
							else {
								msg(MSG_STD, "%s: OK\n", tmp_device);
								cd_device = device_list[i];
								is_error = FALSE;
							}
						}
						break;
					}
					if ((is_error) && (cd_device)) {
						if (dev_open(cd_device) < 0)
							msg(MSG_STD, "%s: error reopening\n", tmp_device);
						else
							dev_prepare();
					}
				}
				break;
			case CMD_VOLUME:
				cmd_ptr = &(cmd_str[6]);
				while (*cmd_ptr == ' ')
					cmd_ptr++;
				switch (*cmd_ptr) {
					case '+':
						arg_val = dev_get_volume();
						cmd_ptr++;
						arg_val = CLAMP(arg_val + atoi(cmd_ptr), VOL_MIN, VOL_MAX);
						break;
					case '-':
						arg_val = dev_get_volume();
						cmd_ptr++;
						arg_val = CLAMP(arg_val - atoi(cmd_ptr), VOL_MIN, VOL_MAX);
						break;
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						arg_val = CLAMP(atoi(cmd_ptr), VOL_MIN, VOL_MAX);
						break;
					default:
						arg_val = -1;
						break;
				}
				if ((arg_val >= 0) && (dev_set_volume(arg_val) < 0))
					IOCTL_ERROR("Volume");
				else {
					arg_val = dev_get_volume();
					msg(MSG_STD, "Volume %d\n", arg_val);
				}
				break;
			case CMD_SEEK: {
				unsigned min, sec, st_min, st_sec;
				int trk;

				is_error = (dev_query_status(NULL, &trk, &min, &sec) < 0);
				if (!is_error)
					is_error =
						(dev_get_track_time(trk, &st_min, &st_sec, NULL, NULL) < 0);
				if (is_error) {
					msg(MSG_ERR, "Error querying current position\n");
					break;
				}
				if (!slave && ++optind < argc)
					cmd_ptr = argv[optind];
				else {
					cmd_ptr = &(cmd_str[4]);
					while (*cmd_ptr == ' ')
						cmd_ptr++;
				}
				/* Current position from beginning of the CD in seconds */
				arg_val = (int)((min + st_min) * 60 + st_sec + sec);
				switch (*cmd_ptr) {
					case '+':
						cmd_ptr++;
						arg_val += atoi(cmd_ptr);
						break;
					case '-':
						cmd_ptr++;
						arg_val -= atoi(cmd_ptr);
						break;
					case '0':
					case '1':
					case '2':
					case '3':
					case '4':
					case '5':
					case '6':
					case '7':
					case '8':
					case '9':
						arg_val = atoi(cmd_ptr);
						break;
					default:
						arg_val = -1;
						break;
				}
				msg(MSG_STD, "Seeking to: %d\n", arg_val);
				if (dev_seek(arg_val) < 0) {
					msg(MSG_ERR, "Error seeking to %d sec\n", arg_val);
					is_error = TRUE;
				}
				break;
			}
			case CMD_QUIT:
				noscan = 1;
				slave = 0;
				if ((cd_device) && (dev_close() < 0)) {
					msg(MSG_ERR, "Error closing device %s\n", cd_device);
					is_error = TRUE;
				}
				break;
			default:
				if (cmd_str) {
					msg(MSG_ERR, "Unknown command: %s\n", cmd_str);
					is_error = TRUE;
				} else {
					msg(MSG_ERR, "Nothing to do\n");
					is_error = TRUE;
				}
		} /* switch */
		msg(MSG_STD, is_error ? "ERROR\n" : "OK\n");
		fflush(stderr);
		
		free(cmd_str);
		cmd_str = NULL;
	} while (slave);
	
	free_list(&device_list, num_devices);

	return EXIT_SUCCESS;
}