Esempio n. 1
0
static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
				unsigned count)
{
	struct redrat3_dev *rr3 = rcdev->priv;
	struct device *dev = rr3->dev;
	struct redrat3_signal_header header;
	int i, j, ret, ret_len, offset;
	int lencheck, cur_sample_len, pipe;
	char *buffer = NULL, *sigdata = NULL;
	int *sample_lens = NULL;
	u32 tmpi;
	u16 tmps;
	u8 *datap;
	u8 curlencheck = 0;
	u16 *lengths_ptr;
	int sendbuf_len;

	rr3_ftr(dev, "Entering %s\n", __func__);

	if (rr3->transmitting) {
		dev_warn(dev, "%s: transmitter already in use\n", __func__);
		return -EAGAIN;
	}

	if (count > (RR3_DRIVER_MAXLENS * 2))
		return -EINVAL;

	/*                                          */
	rr3->det_enabled = false;
	rr3->transmitting = true;

	sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
	if (!sample_lens) {
		ret = -ENOMEM;
		goto out;
	}

	for (i = 0; i < count; i++) {
		for (lencheck = 0; lencheck < curlencheck; lencheck++) {
			cur_sample_len = redrat3_us_to_len(txbuf[i]);
			if (sample_lens[lencheck] == cur_sample_len)
				break;
		}
		if (lencheck == curlencheck) {
			cur_sample_len = redrat3_us_to_len(txbuf[i]);
			rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n",
				i, txbuf[i], curlencheck, cur_sample_len);
			if (curlencheck < 255) {
				/*                                  
                   */
				sample_lens[curlencheck] = cur_sample_len;
				curlencheck++;
			} else {
				dev_err(dev, "signal too long\n");
				ret = -EINVAL;
				goto out;
			}
		}
	}

	sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL);
	if (!sigdata) {
		ret = -ENOMEM;
		goto out;
	}

	sigdata[count] = RR3_END_OF_SIGNAL;
	sigdata[count + 1] = RR3_END_OF_SIGNAL;
	for (i = 0; i < count; i++) {
		for (j = 0; j < curlencheck; j++) {
			if (sample_lens[j] == redrat3_us_to_len(txbuf[i]))
				sigdata[i] = j;
		}
	}

	offset = RR3_TX_HEADER_OFFSET;
	sendbuf_len = RR3_HEADER_LENGTH + (sizeof(u16) * RR3_DRIVER_MAXLENS)
			+ count + RR3_TX_TRAILER_LEN + offset;

	buffer = kzalloc(sendbuf_len, GFP_KERNEL);
	if (!buffer) {
		ret = -ENOMEM;
		goto out;
	}

	/*                           */
	header.length = sendbuf_len - offset;
	header.transfer_type = RR3_MOD_SIGNAL_OUT;
	header.pause = redrat3_len_to_us(100);
	header.mod_freq_count = mod_freq_to_val(rr3->carrier);
	header.no_periods = 0; /*                 */
	header.max_lengths = RR3_DRIVER_MAXLENS;
	header.no_lengths = curlencheck;
	header.max_sig_size = RR3_MAX_SIG_SIZE;
	header.sig_size = count + RR3_TX_TRAILER_LEN;
	/*                                                                */
	header.no_repeats = 0;

	tmps = cpu_to_be16(header.length);
	memcpy(buffer, &tmps, 2);

	tmps = cpu_to_be16(header.transfer_type);
	memcpy(buffer + 2, &tmps, 2);

	tmpi = cpu_to_be32(header.pause);
	memcpy(buffer + offset, &tmpi, sizeof(tmpi));

	tmps = cpu_to_be16(header.mod_freq_count);
	memcpy(buffer + offset + RR3_FREQ_COUNT_OFFSET, &tmps, 2);

	buffer[offset + RR3_NUM_LENGTHS_OFFSET] = header.no_lengths;

	tmps = cpu_to_be16(header.sig_size);
	memcpy(buffer + offset + RR3_NUM_SIGS_OFFSET, &tmps, 2);

	buffer[offset + RR3_REPEATS_OFFSET] = header.no_repeats;

	lengths_ptr = (u16 *)(buffer + offset + RR3_HEADER_LENGTH);
	for (i = 0; i < curlencheck; ++i)
		lengths_ptr[i] = cpu_to_be16(sample_lens[i]);

	datap = (u8 *)(buffer + offset + RR3_HEADER_LENGTH +
			    (sizeof(u16) * RR3_DRIVER_MAXLENS));
	memcpy(datap, sigdata, (count + RR3_TX_TRAILER_LEN));

	if (debug) {
		redrat3_dump_signal_header(&header);
		redrat3_dump_signal_data(buffer, header.sig_size);
	}

	pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress);
	tmps = usb_bulk_msg(rr3->udev, pipe, buffer,
			    sendbuf_len, &ret_len, 10 * HZ);
	rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, tmps);

	/*                                                   */
	pipe = usb_rcvctrlpipe(rr3->udev, 0);
	ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL,
			      USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
			      0, 0, buffer, 2, HZ * 10);

	if (ret < 0)
		dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
	else
		ret = count;

out:
	kfree(sample_lens);
	kfree(buffer);
	kfree(sigdata);

	rr3->transmitting = false;
	/*                                                          */
	rr3->det_enabled = true;

	return ret;
}
static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
                               unsigned count)
{
    struct redrat3_dev *rr3 = rcdev->priv;
    struct device *dev = rr3->dev;
    struct redrat3_irdata *irdata = NULL;
    int ret, ret_len;
    int lencheck, cur_sample_len, pipe;
    int *sample_lens = NULL;
    u8 curlencheck = 0;
    unsigned i, sendbuf_len;

    rr3_ftr(dev, "Entering %s\n", __func__);

    if (rr3->transmitting) {
        dev_warn(dev, "%s: transmitter already in use\n", __func__);
        return -EAGAIN;
    }

    if (count > RR3_MAX_SIG_SIZE - RR3_TX_TRAILER_LEN)
        return -EINVAL;

    /* rr3 will disable rc detector on transmit */
    rr3->transmitting = true;

    sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
    if (!sample_lens) {
        ret = -ENOMEM;
        goto out;
    }

    irdata = kzalloc(sizeof(*irdata), GFP_KERNEL);
    if (!irdata) {
        ret = -ENOMEM;
        goto out;
    }

    for (i = 0; i < count; i++) {
        cur_sample_len = redrat3_us_to_len(txbuf[i]);
        if (cur_sample_len > 0xffff) {
            dev_warn(dev, "transmit period of %uus truncated to %uus\n",
                     txbuf[i], redrat3_len_to_us(0xffff));
            cur_sample_len = 0xffff;
        }
        for (lencheck = 0; lencheck < curlencheck; lencheck++) {
            if (sample_lens[lencheck] == cur_sample_len)
                break;
        }
        if (lencheck == curlencheck) {
            rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n",
                    i, txbuf[i], curlencheck, cur_sample_len);
            if (curlencheck < RR3_DRIVER_MAXLENS) {
                /* now convert the value to a proper
                 * rr3 value.. */
                sample_lens[curlencheck] = cur_sample_len;
                put_unaligned_be16(cur_sample_len,
                                   &irdata->lens[curlencheck]);
                curlencheck++;
            } else {
                ret = -EINVAL;
                goto out;
            }
        }
        irdata->sigdata[i] = lencheck;
    }

    irdata->sigdata[count] = RR3_END_OF_SIGNAL;
    irdata->sigdata[count + 1] = RR3_END_OF_SIGNAL;

    sendbuf_len = offsetof(struct redrat3_irdata,
                           sigdata[count + RR3_TX_TRAILER_LEN]);
    /* fill in our packet header */
    irdata->header.length = cpu_to_be16(sendbuf_len -
                                        sizeof(struct redrat3_header));
    irdata->header.transfer_type = cpu_to_be16(RR3_MOD_SIGNAL_OUT);
    irdata->pause = cpu_to_be32(redrat3_len_to_us(100));
    irdata->mod_freq_count = cpu_to_be16(mod_freq_to_val(rr3->carrier));
    irdata->no_lengths = curlencheck;
    irdata->sig_size = cpu_to_be16(count + RR3_TX_TRAILER_LEN);

    pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress);
    ret = usb_bulk_msg(rr3->udev, pipe, irdata,
                       sendbuf_len, &ret_len, 10 * HZ);
    rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, ret);

    /* now tell the hardware to transmit what we sent it */
    pipe = usb_rcvctrlpipe(rr3->udev, 0);
    ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL,
                          USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                          0, 0, irdata, 2, HZ * 10);

    if (ret < 0)
        dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
    else
        ret = count;

out:
    kfree(sample_lens);
    kfree(irdata);

    rr3->transmitting = false;
    /* rr3 re-enables rc detector because it was enabled before */

    return ret;
}