Пример #1
0
static int acm_probe(struct usb_interface *intf,
		     const struct usb_device_id *id)
{
	struct usb_cdc_union_desc *union_header = NULL;
	struct usb_cdc_country_functional_desc *cfd = NULL;
	unsigned char *buffer = intf->altsetting->extra;
	int buflen = intf->altsetting->extralen;
	struct usb_interface *control_interface;
	struct usb_interface *data_interface;
	struct usb_endpoint_descriptor *epctrl = NULL;
	struct usb_endpoint_descriptor *epread = NULL;
	struct usb_endpoint_descriptor *epwrite = NULL;
	struct usb_device *usb_dev = interface_to_usbdev(intf);
	struct acm *acm;
	int minor;
	int ctrlsize, readsize;
	u8 *buf;
	u8 ac_management_function = 0;
	u8 call_management_function = 0;
	int call_interface_num = -1;
	int data_interface_num = -1;
	unsigned long quirks;
	int num_rx_buf;
	int i;
	int combined_interfaces = 0;

	
	quirks = (unsigned long)id->driver_info;
	num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;

	
	if (quirks == NO_UNION_NORMAL) {
		data_interface = usb_ifnum_to_if(usb_dev, 1);
		control_interface = usb_ifnum_to_if(usb_dev, 0);
		goto skip_normal_probe;
	}

	
	if (!buffer) {
		dev_err(&intf->dev, "Weird descriptor references\n");
		return -EINVAL;
	}

	if (!buflen) {
		if (intf->cur_altsetting->endpoint &&
				intf->cur_altsetting->endpoint->extralen &&
				intf->cur_altsetting->endpoint->extra) {
			dev_dbg(&intf->dev,
				"Seeking extra descriptors on endpoint\n");
			buflen = intf->cur_altsetting->endpoint->extralen;
			buffer = intf->cur_altsetting->endpoint->extra;
		} else {
			dev_err(&intf->dev,
				"Zero length descriptor references\n");
			return -EINVAL;
		}
	}

	while (buflen > 0) {
		if (buffer[1] != USB_DT_CS_INTERFACE) {
			dev_err(&intf->dev, "skipping garbage\n");
			goto next_desc;
		}

		switch (buffer[2]) {
		case USB_CDC_UNION_TYPE: 
			if (union_header) {
				dev_err(&intf->dev, "More than one "
					"union descriptor, skipping ...\n");
				goto next_desc;
			}
			union_header = (struct usb_cdc_union_desc *)buffer;
			break;
		case USB_CDC_COUNTRY_TYPE: 
			cfd = (struct usb_cdc_country_functional_desc *)buffer;
			break;
		case USB_CDC_HEADER_TYPE: 
			break; 
		case USB_CDC_ACM_TYPE:
			ac_management_function = buffer[3];
			break;
		case USB_CDC_CALL_MANAGEMENT_TYPE:
			call_management_function = buffer[3];
			call_interface_num = buffer[4];
			if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
				dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
			break;
		default:
			dev_dbg(&intf->dev, "Ignoring descriptor: "
					"type %02x, length %d\n",
					buffer[2], buffer[0]);
			break;
		}
next_desc:
		buflen -= buffer[0];
		buffer += buffer[0];
	}

	if (!union_header) {
		if (call_interface_num > 0) {
			dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
			
			if (quirks & NO_DATA_INTERFACE)
				data_interface = usb_ifnum_to_if(usb_dev, 0);
			else
				data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
			control_interface = intf;
		} else {
			if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
				dev_dbg(&intf->dev,"No union descriptor, giving up\n");
				return -ENODEV;
			} else {
				dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
				combined_interfaces = 1;
				control_interface = data_interface = intf;
				goto look_for_collapsed_interface;
			}
		}
	} else {
		control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
		data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
		if (!control_interface || !data_interface) {
			dev_dbg(&intf->dev, "no interfaces\n");
			return -ENODEV;
		}
	}

	if (data_interface_num != call_interface_num)
		dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");

	if (control_interface == data_interface) {
		
		dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
		combined_interfaces = 1;
		
		quirks |= NO_CAP_LINE;
		if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
			dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
			return -EINVAL;
		}
look_for_collapsed_interface:
		for (i = 0; i < 3; i++) {
			struct usb_endpoint_descriptor *ep;
			ep = &data_interface->cur_altsetting->endpoint[i].desc;

			if (usb_endpoint_is_int_in(ep))
				epctrl = ep;
			else if (usb_endpoint_is_bulk_out(ep))
				epwrite = ep;
			else if (usb_endpoint_is_bulk_in(ep))
				epread = ep;
			else
				return -EINVAL;
		}
		if (!epctrl || !epread || !epwrite)
			return -ENODEV;
		else
			goto made_compressed_probe;
	}

skip_normal_probe:

	
	if (data_interface->cur_altsetting->desc.bInterfaceClass
						!= CDC_DATA_INTERFACE_TYPE) {
		if (control_interface->cur_altsetting->desc.bInterfaceClass
						== CDC_DATA_INTERFACE_TYPE) {
			struct usb_interface *t;
			dev_dbg(&intf->dev,
				"Your device has switched interfaces.\n");
			t = control_interface;
			control_interface = data_interface;
			data_interface = t;
		} else {
			return -EINVAL;
		}
	}

	
	if (!combined_interfaces && intf != control_interface)
		return -ENODEV;

	if (!combined_interfaces && usb_interface_claimed(data_interface)) {
		
		dev_dbg(&intf->dev, "The data interface isn't available\n");
		return -EBUSY;
	}


	if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
		return -EINVAL;

	epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
	epread = &data_interface->cur_altsetting->endpoint[0].desc;
	epwrite = &data_interface->cur_altsetting->endpoint[1].desc;


	
	if (!usb_endpoint_dir_in(epread)) {
		
		struct usb_endpoint_descriptor *t;
		dev_dbg(&intf->dev,
			"The data interface has switched endpoints\n");
		t = epread;
		epread = epwrite;
		epwrite = t;
	}
made_compressed_probe:
	dev_dbg(&intf->dev, "interfaces are valid\n");

	acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
	if (acm == NULL) {
		dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
		goto alloc_fail;
	}

	minor = acm_alloc_minor(acm);
	if (minor == ACM_TTY_MINORS) {
		dev_err(&intf->dev, "no more free acm devices\n");
		kfree(acm);
		return -ENODEV;
	}

	ctrlsize = usb_endpoint_maxp(epctrl);
	readsize = usb_endpoint_maxp(epread) *
				(quirks == SINGLE_RX_URB ? 1 : 2);
	acm->combined_interfaces = combined_interfaces;
	acm->writesize = usb_endpoint_maxp(epwrite) * 20;
	acm->control = control_interface;
	acm->data = data_interface;
	acm->minor = minor;
	acm->dev = usb_dev;
	acm->ctrl_caps = ac_management_function;
	if (quirks & NO_CAP_LINE)
		acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
	acm->ctrlsize = ctrlsize;
	acm->readsize = readsize;
	acm->rx_buflimit = num_rx_buf;
	INIT_WORK(&acm->work, acm_softint);
	spin_lock_init(&acm->write_lock);
	spin_lock_init(&acm->read_lock);
	mutex_init(&acm->mutex);
	acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
	acm->is_int_ep = usb_endpoint_xfer_int(epread);
	if (acm->is_int_ep)
		acm->bInterval = epread->bInterval;
	tty_port_init(&acm->port);
	acm->port.ops = &acm_port_ops;

	buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
	if (!buf) {
		dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
		goto alloc_fail2;
	}
	acm->ctrl_buffer = buf;

	if (acm_write_buffers_alloc(acm) < 0) {
		dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
		goto alloc_fail4;
	}

	acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
	if (!acm->ctrlurb) {
		dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
		goto alloc_fail5;
	}
	for (i = 0; i < num_rx_buf; i++) {
		struct acm_rb *rb = &(acm->read_buffers[i]);
		struct urb *urb;

		rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
								&rb->dma);
		if (!rb->base) {
			dev_err(&intf->dev, "out of memory "
					"(read bufs usb_alloc_coherent)\n");
			goto alloc_fail6;
		}
		rb->index = i;
		rb->instance = acm;

		urb = usb_alloc_urb(0, GFP_KERNEL);
		if (!urb) {
			dev_err(&intf->dev,
				"out of memory (read urbs usb_alloc_urb)\n");
			goto alloc_fail6;
		}
		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
		urb->transfer_dma = rb->dma;
		if (acm->is_int_ep) {
			usb_fill_int_urb(urb, acm->dev,
					 acm->rx_endpoint,
					 rb->base,
					 acm->readsize,
					 acm_read_bulk_callback, rb,
					 acm->bInterval);
		} else {
			usb_fill_bulk_urb(urb, acm->dev,
					  acm->rx_endpoint,
					  rb->base,
					  acm->readsize,
					  acm_read_bulk_callback, rb);
		}

		acm->read_urbs[i] = urb;
		__set_bit(i, &acm->read_urbs_free);
	}
	for (i = 0; i < ACM_NW; i++) {
		struct acm_wb *snd = &(acm->wb[i]);

		snd->urb = usb_alloc_urb(0, GFP_KERNEL);
		if (snd->urb == NULL) {
			dev_err(&intf->dev,
				"out of memory (write urbs usb_alloc_urb)\n");
			goto alloc_fail7;
		}

		if (usb_endpoint_xfer_int(epwrite))
			usb_fill_int_urb(snd->urb, usb_dev,
				usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
				NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
		else
			usb_fill_bulk_urb(snd->urb, usb_dev,
				usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
				NULL, acm->writesize, acm_write_bulk, snd);
		snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
		snd->instance = acm;
	}

	usb_set_intfdata(intf, acm);

	i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
	if (i < 0)
		goto alloc_fail7;

	if (cfd) { 
		acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
		if (!acm->country_codes)
			goto skip_countries;
		acm->country_code_size = cfd->bLength - 4;
		memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
							cfd->bLength - 4);
		acm->country_rel_date = cfd->iCountryCodeRelDate;

		i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
		if (i < 0) {
			kfree(acm->country_codes);
			acm->country_codes = NULL;
			acm->country_code_size = 0;
			goto skip_countries;
		}

		i = device_create_file(&intf->dev,
						&dev_attr_iCountryCodeRelDate);
		if (i < 0) {
			device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
			kfree(acm->country_codes);
			acm->country_codes = NULL;
			acm->country_code_size = 0;
			goto skip_countries;
		}
	}

skip_countries:
	usb_fill_int_urb(acm->ctrlurb, usb_dev,
			 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
			 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
			 
			 epctrl->bInterval ? epctrl->bInterval : 0xff);
	acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	acm->ctrlurb->transfer_dma = acm->ctrl_dma;

	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);

	acm_set_control(acm, acm->ctrlout);

	acm->line.dwDTERate = cpu_to_le32(9600);
	acm->line.bDataBits = 8;
	acm_set_line(acm, &acm->line);

	usb_driver_claim_interface(&acm_driver, data_interface, acm);
	usb_set_intfdata(data_interface, acm);

	usb_get_intf(control_interface);
	tty_register_device(acm_tty_driver, minor, &control_interface->dev);

	return 0;
alloc_fail7:
	for (i = 0; i < ACM_NW; i++)
		usb_free_urb(acm->wb[i].urb);
alloc_fail6:
	for (i = 0; i < num_rx_buf; i++)
		usb_free_urb(acm->read_urbs[i]);
	acm_read_buffers_free(acm);
	usb_free_urb(acm->ctrlurb);
alloc_fail5:
	acm_write_buffers_free(acm);
alloc_fail4:
	usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
alloc_fail2:
	acm_release_minor(acm);
	kfree(acm);
alloc_fail:
	return -ENOMEM;
}
Пример #2
0
/**
 * gserial_setup - initialize TTY driver for one or more ports
 * @g: gadget to associate with these ports
 * @count: how many ports to support
 * Context: may sleep
 *
 * The TTY stack needs to know in advance how many devices it should
 * plan to manage.  Use this call to set up the ports you will be
 * exporting through USB.  Later, connect them to functions based
 * on what configuration is activated by the USB host; and disconnect
 * them as appropriate.
 *
 * An example would be a two-configuration device in which both
 * configurations expose port 0, but through different functions.
 * One configuration could even expose port 1 while the other
 * one doesn't.
 *
 * Returns negative errno or zero.
 */
int gserial_setup(struct usb_gadget *g, unsigned count)
{
	unsigned			i;
	struct usb_cdc_line_coding	coding;
	int				status;

	if (count == 0 || count > N_PORTS)
		return -EINVAL;

	gs_tty_driver = alloc_tty_driver(count);
	if (!gs_tty_driver)
		return -ENOMEM;

	gs_tty_driver->owner = THIS_MODULE;
	gs_tty_driver->driver_name = "g_serial";
	gs_tty_driver->name = PREFIX;
	/* uses dynamically assigned dev_t values */

	gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
				| TTY_DRIVER_RESET_TERMIOS;
	gs_tty_driver->init_termios = tty_std_termios;

	/* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on
	 * MS-Windows.  Otherwise, most of these flags shouldn't affect
	 * anything unless we were to actually hook up to a serial line.
	 */
	gs_tty_driver->init_termios.c_cflag =
			B9600 | CS8 | CREAD | HUPCL | CLOCAL;
	gs_tty_driver->init_termios.c_ispeed = 9600;
	gs_tty_driver->init_termios.c_ospeed = 9600;

	coding.dwDTERate = cpu_to_le32(9600);
	coding.bCharFormat = 8;
	coding.bParityType = USB_CDC_NO_PARITY;
	coding.bDataBits = USB_CDC_1_STOP_BITS;

	tty_set_operations(gs_tty_driver, &gs_tty_ops);

	gserial_wq = create_singlethread_workqueue("k_gserial");
	if (!gserial_wq) {
		status = -ENOMEM;
		goto fail;
	}

	/* make devices be openable */
	for (i = 0; i < count; i++) {
		mutex_init(&ports[i].lock);
		status = gs_port_alloc(i, &coding);
		if (status) {
			count = i;
			goto fail;
		}
	}
	n_ports = count;

	/* export the driver ... */
	status = tty_register_driver(gs_tty_driver);
	if (status) {
		put_tty_driver(gs_tty_driver);
		pr_err("%s: cannot register, err %d\n",
				__func__, status);
		goto fail;
	}

	/* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */
	for (i = 0; i < count; i++) {
		struct device	*tty_dev;

		tty_dev = tty_register_device(gs_tty_driver, i, &g->dev);
		if (IS_ERR(tty_dev))
			pr_warning("%s: no classdev for port %d, err %ld\n",
				__func__, i, PTR_ERR(tty_dev));
	}

	pr_debug("%s: registered %d ttyGS* device%s\n", __func__,
			count, (count == 1) ? "" : "s");

	return status;
fail:
	while (count--)
		kfree(ports[count].port);
	destroy_workqueue(gserial_wq);
	put_tty_driver(gs_tty_driver);
	gs_tty_driver = NULL;
	return status;
}
/**
 * gserial_setup - initialize TTY driver for one or more ports
 * @g: gadget to associate with these ports
 * @count: how many ports to support
 * Context: may sleep
 *
 * The TTY stack needs to know in advance how many devices it should
 * plan to manage.  Use this call to set up the ports you will be
 * exporting through USB.  Later, connect them to functions based
 * on what configuration is activated by the USB host; and disconnect
 * them as appropriate.
 *
 * An example would be a two-configuration device in which both
 * configurations expose port 0, but through different functions.
 * One configuration could even expose port 1 while the other
 * one doesn't.
 *
 * Returns negative errno or zero.
 */
int gserial_setup(struct usb_gadget *g, unsigned count)
{
	unsigned			i;
	struct usb_cdc_line_coding	coding;
	int				status;
	struct device	*tty_dev;

	if (count == 0 || count > ACM_TTY_COUNT)
		return -EINVAL;

    /* count:0 is init in the bsp_usb_console_init */
    if (count > 1) {
        gs_tty_driver = alloc_tty_driver(count-1);
    	if (!gs_tty_driver)
    		return -ENOMEM;

    	gs_tty_driver->driver_name = "g_serial";
    	gs_tty_driver->name = PREFIX;

    	/* uses dynamically assigned dev_t values */

    	gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
    	gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
    	gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
    	gs_tty_driver->init_termios = tty_std_termios;

    	/* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on
    	 * MS-Windows.  Otherwise, most of these flags shouldn't affect
    	 * anything unless we were to actually hook up to a serial line.
    	 */
    	gs_tty_driver->init_termios.c_cflag =
    			B9600 | CS8 | CREAD | HUPCL | CLOCAL;
    	gs_tty_driver->init_termios.c_ispeed = 9600;
    	gs_tty_driver->init_termios.c_ospeed = 9600;
    	gs_tty_driver->num = 1;

    	coding.dwDTERate = cpu_to_le32(9600);
    	coding.bCharFormat = 8;
    	coding.bParityType = USB_CDC_NO_PARITY;
    	coding.bDataBits = USB_CDC_1_STOP_BITS;

    	tty_set_operations(gs_tty_driver, &gs_tty_ops);

    	/* export the driver ... */
    	status = tty_register_driver(gs_tty_driver);
    	if (status) {
    		pr_err("%s: cannot register, err %d\n",
    				__func__, status);
    		goto fail;
    	}
    }

	/* make devices be openable */
	for (i = 1; i < count; i++) {
		mutex_init(&ports[i].lock);
		status = gs_port_alloc(i, &coding);
		if (status) {
			count = i;
			goto fail;
		}
	}
	n_ports = count;

    /* 1. reg tty device for console tty */
    tty_dev = tty_register_device(gs_console_tty_driver, 0, &g->dev);
    if (IS_ERR(tty_dev))
			pr_warning("%s: no classdev for port %d, err %ld\n",
				__func__, 0, PTR_ERR(tty_dev));

    /* 2. reg other tty ... */
	/* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */
	for (i = 1; i < count; i++) {
		//struct device	*tty_dev;

        /* i-1 means index start from 0 */
		tty_dev = tty_register_device(gs_tty_driver, i-1, &g->dev);
		if (IS_ERR(tty_dev))
			pr_warning("%s: no classdev for port %d, err %ld\n",
				__func__, i, PTR_ERR(tty_dev));
	}

	pr_vdebug("%s: registered %d ttyGS* device%s\n", __func__,
			count, (count == 1) ? "" : "s");

	return status;/* [false alarm]:fortify disable */
fail:
    /* never free console tty port */
	while (count-- > 1)
		kfree(ports[count].port);
	put_tty_driver(gs_tty_driver);
	gs_tty_driver = NULL;
	return status;
}
Пример #4
0
static int acm_probe (struct usb_interface *intf,
		      const struct usb_device_id *id)
{
	struct usb_cdc_union_desc *union_header = NULL;
	struct usb_cdc_country_functional_desc *cfd = NULL;
	char *buffer = intf->altsetting->extra;
	int buflen = intf->altsetting->extralen;
	struct usb_interface *control_interface;
	struct usb_interface *data_interface;
	struct usb_endpoint_descriptor *epctrl;
	struct usb_endpoint_descriptor *epread;
	struct usb_endpoint_descriptor *epwrite;
	struct usb_device *usb_dev = interface_to_usbdev(intf);
	struct acm *acm;
	int minor;
	int ctrlsize,readsize;
	u8 *buf;
	u8 ac_management_function = 0;
	u8 call_management_function = 0;
	int call_interface_num = -1;
	int data_interface_num;
	unsigned long quirks;
	int num_rx_buf;
	int i;

	/* normal quirks */
	quirks = (unsigned long)id->driver_info;
	num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;

	/* handle quirks deadly to normal probing*/
	if (quirks == NO_UNION_NORMAL) {
		data_interface = usb_ifnum_to_if(usb_dev, 1);
		control_interface = usb_ifnum_to_if(usb_dev, 0);
		goto skip_normal_probe;
	}
	
	/* normal probing*/
	if (!buffer) {
		err("Wierd descriptor references\n");
		return -EINVAL;
	}

	if (!buflen) {
		if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
			dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint");
			buflen = intf->cur_altsetting->endpoint->extralen;
			buffer = intf->cur_altsetting->endpoint->extra;
		} else {
			err("Zero length descriptor references\n");
			return -EINVAL;
		}
	}

	while (buflen > 0) {
		if (buffer [1] != USB_DT_CS_INTERFACE) {
			err("skipping garbage\n");
			goto next_desc;
		}

		switch (buffer [2]) {
			case USB_CDC_UNION_TYPE: /* we've found it */
				if (union_header) {
					err("More than one union descriptor, skipping ...");
					goto next_desc;
				}
				union_header = (struct usb_cdc_union_desc *)
							buffer;
				break;
			case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
				cfd = (struct usb_cdc_country_functional_desc *)buffer;
				break;
			case USB_CDC_HEADER_TYPE: /* maybe check version */ 
				break; /* for now we ignore it */ 
			case USB_CDC_ACM_TYPE:
				ac_management_function = buffer[3];
				break;
			case USB_CDC_CALL_MANAGEMENT_TYPE:
				call_management_function = buffer[3];
				call_interface_num = buffer[4];
				if ((call_management_function & 3) != 3)
					err("This device cannot do calls on its own. It is no modem.");
				break;
				
			default:
				err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);
				break;
			}
next_desc:
		buflen -= buffer[0];
		buffer += buffer[0];
	}

	if (!union_header) {
		if (call_interface_num > 0) {
			dev_dbg(&intf->dev,"No union descriptor, using call management descriptor");
			data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
			control_interface = intf;
		} else {
			dev_dbg(&intf->dev,"No union descriptor, giving up");
			return -ENODEV;
		}
	} else {
		control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
		data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
		if (!control_interface || !data_interface) {
			dev_dbg(&intf->dev,"no interfaces");
			return -ENODEV;
		}
	}
	
	if (data_interface_num != call_interface_num)
		dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.");

skip_normal_probe:

	/*workaround for switched interfaces */
	if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
		if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
			struct usb_interface *t;
			dev_dbg(&intf->dev,"Your device has switched interfaces.");

			t = control_interface;
			control_interface = data_interface;
			data_interface = t;
		} else {
			return -EINVAL;
		}
	}

	/* Accept probe requests only for the control interface */
	if (intf != control_interface)
		return -ENODEV;
	
	if (usb_interface_claimed(data_interface)) { /* valid in this context */
		dev_dbg(&intf->dev,"The data interface isn't available");
		return -EBUSY;
	}


	if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
		return -EINVAL;

	epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
	epread = &data_interface->cur_altsetting->endpoint[0].desc;
	epwrite = &data_interface->cur_altsetting->endpoint[1].desc;


	/* workaround for switched endpoints */
	if (!usb_endpoint_dir_in(epread)) {
		/* descriptors are swapped */
		struct usb_endpoint_descriptor *t;
		dev_dbg(&intf->dev,"The data interface has switched endpoints");
		
		t = epread;
		epread = epwrite;
		epwrite = t;
	}
	dbg("interfaces are valid");
	for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);

	if (minor == ACM_TTY_MINORS) {
		err("no more free acm devices");
		return -ENODEV;
	}

	if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
		dev_dbg(&intf->dev, "out of memory (acm kzalloc)");
		goto alloc_fail;
	}

	ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
	readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
	acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
	acm->control = control_interface;
	acm->data = data_interface;
	acm->minor = minor;
	acm->dev = usb_dev;
	acm->ctrl_caps = ac_management_function;
	acm->ctrlsize = ctrlsize;
	acm->readsize = readsize;
	acm->rx_buflimit = num_rx_buf;
	acm->urb_task.func = acm_rx_tasklet;
	acm->urb_task.data = (unsigned long) acm;
	INIT_WORK(&acm->work, acm_softint);
	spin_lock_init(&acm->throttle_lock);
	spin_lock_init(&acm->write_lock);
	spin_lock_init(&acm->read_lock);
	acm->write_ready = 1;
	acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);

	buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
	if (!buf) {
		dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)");
		goto alloc_fail2;
	}
	acm->ctrl_buffer = buf;

	if (acm_write_buffers_alloc(acm) < 0) {
		dev_dbg(&intf->dev, "out of memory (write buffer alloc)");
		goto alloc_fail4;
	}

	acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
	if (!acm->ctrlurb) {
		dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)");
		goto alloc_fail5;
	}
	for (i = 0; i < num_rx_buf; i++) {
		struct acm_ru *rcv = &(acm->ru[i]);

		if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
			dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)");
			goto alloc_fail7;
		}

		rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
		rcv->instance = acm;
	}
	for (i = 0; i < num_rx_buf; i++) {
		struct acm_rb *buf = &(acm->rb[i]);

		if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
			dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)");
			goto alloc_fail7;
		}
	}
	acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
	if (!acm->writeurb) {
		dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)");
		goto alloc_fail7;
	}

	usb_set_intfdata (intf, acm);

	i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
	if (i < 0)
		goto alloc_fail8;

	if (cfd) { /* export the country data */
		acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
		if (!acm->country_codes)
			goto skip_countries;
		acm->country_code_size = cfd->bLength - 4;
		memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
		acm->country_rel_date = cfd->iCountryCodeRelDate;

		i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
		if (i < 0) {
			kfree(acm->country_codes);
			goto skip_countries;
		}

		i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
		if (i < 0) {
			kfree(acm->country_codes);
			goto skip_countries;
		}
	}

skip_countries:
	usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
			 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
	acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	acm->ctrlurb->transfer_dma = acm->ctrl_dma;

	usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
			  NULL, acm->writesize, acm_write_bulk, acm);
	acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;

	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);

	acm_set_control(acm, acm->ctrlout);

	acm->line.dwDTERate = cpu_to_le32(9600);
	acm->line.bDataBits = 8;
	acm_set_line(acm, &acm->line);

	usb_driver_claim_interface(&acm_driver, data_interface, acm);

	usb_get_intf(control_interface);
	tty_register_device(acm_tty_driver, minor, &control_interface->dev);

	acm_table[minor] = acm;

	return 0;
alloc_fail8:
	usb_free_urb(acm->writeurb);
alloc_fail7:
	for (i = 0; i < num_rx_buf; i++)
		usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
	for (i = 0; i < num_rx_buf; i++)
		usb_free_urb(acm->ru[i].urb);
	usb_free_urb(acm->ctrlurb);
alloc_fail5:
	acm_write_buffers_free(acm);
alloc_fail4:
	usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
alloc_fail2:
	kfree(acm);
alloc_fail:
	return -ENOMEM;
}
static int __init smd_tty_init(void)
{
	int ret;
	int n;
	int idx;

	smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
	if (smd_tty_driver == 0)
		return -ENOMEM;

	smd_tty_driver->owner = THIS_MODULE;
	smd_tty_driver->driver_name = "smd_tty_driver";
	smd_tty_driver->name = "smd";
	smd_tty_driver->major = 0;
	smd_tty_driver->minor_start = 0;
	smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	smd_tty_driver->init_termios = tty_std_termios;
	smd_tty_driver->init_termios.c_iflag = 0;
	smd_tty_driver->init_termios.c_oflag = 0;
	smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
	smd_tty_driver->init_termios.c_lflag = 0;
	smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	tty_set_operations(smd_tty_driver, &smd_tty_ops);

	ret = tty_register_driver(smd_tty_driver);
	if (ret) {
		put_tty_driver(smd_tty_driver);
		pr_err("%s: driver registration failed %d\n", __func__, ret);
		return ret;
	}

	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
		idx = smd_configs[n].tty_dev_index;

		if (smd_configs[n].dev_name == NULL)
			smd_configs[n].dev_name = smd_configs[n].port_name;
#if 0
		if (idx == DS_IDX) {
			/*
			 * DS port uses the kernel API starting with
			 * 8660 Fusion.  Only register the userspace
			 * platform device for older targets.
			 */
			int legacy_ds = 0;

			legacy_ds |= cpu_is_msm7x01() || cpu_is_msm7x25();
			legacy_ds |= cpu_is_msm7x27() || cpu_is_msm7x30();
			legacy_ds |= cpu_is_qsd8x50() || cpu_is_msm8x55();
			/*
			 * use legacy mode for 8660 Standalone (subtype 0)
			 */
			legacy_ds |= cpu_is_msm8x60() &&
					(socinfo_get_platform_subtype() == 0x0);

			if (!legacy_ds)
				continue;
		}
#endif
		tty_register_device(smd_tty_driver, idx, 0);
		init_completion(&smd_tty[idx].ch_allocated);

		/* register platform device */
		smd_tty[idx].driver.probe = smd_tty_dummy_probe;
		smd_tty[idx].driver.driver.name = smd_configs[n].dev_name;
		smd_tty[idx].driver.driver.owner = THIS_MODULE;
		spin_lock_init(&smd_tty[idx].reset_lock);
		smd_tty[idx].is_open = 0;
		setup_timer(&smd_tty[idx].buf_req_timer, buf_req_retry,
				(unsigned long)&smd_tty[idx]);
		init_waitqueue_head(&smd_tty[idx].ch_opened_wait_queue);
		ret = platform_driver_register(&smd_tty[idx].driver);

		if (ret) {
			pr_err("%s: init failed %d (%d)\n", __func__, idx, ret);
			smd_tty[idx].driver.probe = NULL;
			goto out;
		}
		smd_tty[idx].smd = &smd_configs[n];
	}
	INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
	return 0;

out:
	/* unregister platform devices */
	for (n = 0; n < ARRAY_SIZE(smd_configs); ++n) {
		idx = smd_configs[n].tty_dev_index;

		if (smd_tty[idx].driver.probe) {
			platform_driver_unregister(&smd_tty[idx].driver);
			tty_unregister_device(smd_tty_driver, idx);
		}
	}

	tty_unregister_driver(smd_tty_driver);
	put_tty_driver(smd_tty_driver);
	return ret;
}
static int __init lge_dm_tty_init(void)
{
    int ret = 0;
    struct device *tty_dev;
    struct dm_tty *lge_dm_tty_drv;
#ifdef CONFIG_TTY_PORT
    tty_port_init(&dm_tty_port);
#endif /* CONFIG_TTY_PORT */
    pr_info(DM_TTY_MODULE_NAME ": %s\n", __func__);

    if(lge_dm_tty != NULL)
    {
        lge_dm_tty_drv = lge_dm_tty;
    }
    else
    {
        lge_dm_tty_drv = kzalloc(sizeof(struct dm_tty), GFP_KERNEL);
        if (lge_dm_tty_drv == NULL) {
            pr_info(DM_TTY_MODULE_NAME "%s:"
            "failed to allocate lge_dm_tty", __func__);
            return 0;
        }

        lge_dm_tty = lge_dm_tty_drv;
    }

    lge_dm_tty_drv->tty_drv = alloc_tty_driver(MAX_DM_TTY_DRV);

    if (!lge_dm_tty_drv->tty_drv) {
        pr_info(DM_TTY_MODULE_NAME ": %s - tty_drv is NULL", __func__);
        kfree(lge_dm_tty_drv);
        return 0;
    }

    lge_dm_tty_drv->tty_drv->name = "lge_dm_tty";
    lge_dm_tty_drv->tty_drv->owner = THIS_MODULE;
    lge_dm_tty_drv->tty_drv->driver_name = "lge_dm_tty";
    /* uses dynamically assigned dev_t values */
    lge_dm_tty_drv->tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
    lge_dm_tty_drv->tty_drv->subtype = SERIAL_TYPE_NORMAL;
    lge_dm_tty_drv->tty_drv->flags = TTY_DRIVER_REAL_RAW
        | TTY_DRIVER_DYNAMIC_DEV
        | TTY_DRIVER_RESET_TERMIOS;

    /* initializing the tty driver */
    lge_dm_tty_drv->tty_drv->init_termios = tty_std_termios;
    lge_dm_tty_drv->tty_drv->init_termios.c_iflag = IGNBRK | IGNPAR;
    lge_dm_tty_drv->tty_drv->init_termios.c_oflag = 0;
    lge_dm_tty_drv->tty_drv->init_termios.c_cflag =
        B9600 | CS8 | CREAD | HUPCL | CLOCAL;
    lge_dm_tty_drv->tty_drv->init_termios.c_lflag = 0;

    tty_set_operations(lge_dm_tty_drv->tty_drv, &lge_dm_tty_ops);

#ifdef CONFIG_TTY_PORT
    tty_port_link_device(&dm_tty_port, lge_dm_tty_drv->tty_drv, 0);
#endif /* CONFIG_TTY_PORT */
    ret = tty_register_driver(lge_dm_tty_drv->tty_drv);

    if (ret) {
        put_tty_driver(lge_dm_tty_drv->tty_drv);
#ifdef CONFIG_TTY_PORT
        tty_port_destroy(&dm_tty_port);
#endif /* CONFIG_TTY_PORT */
        pr_info(DM_TTY_MODULE_NAME ": %s:"
        "tty_register_driver() ""failed\n",
            __func__);

        lge_dm_tty_drv->tty_drv = NULL;
        kfree(lge_dm_tty_drv);
        return 0;
    }

    tty_dev = tty_register_device(lge_dm_tty_drv->tty_drv, 0, NULL);

    if (IS_ERR(tty_dev)) {
        pr_info(DM_TTY_MODULE_NAME ": %s:"
        "tty_register_device() " "failed\n",
            __func__);
        tty_unregister_driver(lge_dm_tty_drv->tty_drv);
        put_tty_driver(lge_dm_tty_drv->tty_drv);
#ifdef CONFIG_TTY_PORT
        tty_port_destroy(&dm_tty_port);
#endif /* CONFIG_TTY_PORT */
        kfree(lge_dm_tty_drv);
        return 0;
    }

    init_waitqueue_head(&lge_dm_tty_drv->waitq);

    lge_dm_tty_drv->tty_state = DM_TTY_REGISTERED;

    /* data initialization */
    dm_modem_response = kzalloc(DM_TTY_TX_MAX_PACKET_SIZE, GFP_KERNEL);
    if (dm_modem_response == NULL)
        pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_response ""failed\n",
            __func__);

    dm_modem_request = kzalloc(DM_TTY_RX_MAX_PACKET_SIZE, GFP_KERNEL);
    if (dm_modem_request == NULL)
        pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_request ""failed\n",
            __func__);

    dm_modem_response_header_length = sizeof(struct dm_router_header);
    dm_modem_response_header = kzalloc(dm_modem_response_header_length,
        GFP_KERNEL);
    if (dm_modem_response_header == NULL)
        pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_response_header "
            "failed\n", __func__);

    dm_modem_request_header_length = sizeof(struct dm_router_header);
    dm_modem_request_header = kzalloc(dm_modem_request_header_length,
        GFP_KERNEL);
    if (dm_modem_request_header == NULL)
        pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_request_header "
            "failed\n", __func__);

    dm_modem_response_body_length =
        sizeof(struct dm_router_modem_response_body);
    dm_modem_response_body = kzalloc(dm_modem_response_body_length,
        GFP_KERNEL);
    if (dm_modem_response_body == NULL)
        pr_info(DM_TTY_MODULE_NAME ": %s: dm_modem_response_body "
            "failed\n", __func__);

    return 0;

}
Пример #7
0
static int acm_probe(struct usb_interface *intf,
                     const struct usb_device_id *id)
{
    struct usb_cdc_union_desc *union_header = NULL;
    struct usb_cdc_country_functional_desc *cfd = NULL;
    unsigned char *buffer = intf->altsetting->extra;
    int buflen = intf->altsetting->extralen;
    struct usb_interface *control_interface;
    struct usb_interface *data_interface;
    struct usb_endpoint_descriptor *epctrl = NULL;
    struct usb_endpoint_descriptor *epread = NULL;
    struct usb_endpoint_descriptor *epwrite = NULL;
    struct usb_device *usb_dev = interface_to_usbdev(intf);
    struct acm *acm;
    int minor;
    int ctrlsize, readsize;
    u8 *buf;
    u8 ac_management_function = 0;
    u8 call_management_function = 0;
    int call_interface_num = -1;
    int data_interface_num;
    unsigned long quirks;
    int num_rx_buf;
    int i;
    int combined_interfaces = 0;

    /* normal quirks */
    quirks = (unsigned long)id->driver_info;
    num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;

    /* handle quirks deadly to normal probing*/
    if (quirks == NO_UNION_NORMAL) {
        data_interface = usb_ifnum_to_if(usb_dev, 1);
        control_interface = usb_ifnum_to_if(usb_dev, 0);
        goto skip_normal_probe;
    }

    /* normal probing*/
    if (!buffer) {
        dev_err(&intf->dev, "Weird descriptor references\n");
        return -EINVAL;
    }

    if (!buflen) {
        if (intf->cur_altsetting->endpoint->extralen &&
                intf->cur_altsetting->endpoint->extra) {
            dev_dbg(&intf->dev,
                    "Seeking extra descriptors on endpoint\n");
            buflen = intf->cur_altsetting->endpoint->extralen;
            buffer = intf->cur_altsetting->endpoint->extra;
        } else {
            dev_err(&intf->dev,
                    "Zero length descriptor references\n");
            return -EINVAL;
        }
    }

    while (buflen > 0) {
        if (buffer[1] != USB_DT_CS_INTERFACE) {
            dev_err(&intf->dev, "skipping garbage\n");
            goto next_desc;
        }

        switch (buffer[2]) {
        case USB_CDC_UNION_TYPE: /* we've found it */
            if (union_header) {
                dev_err(&intf->dev, "More than one "
                        "union descriptor, skipping ...\n");
                goto next_desc;
            }
            union_header = (struct usb_cdc_union_desc *)buffer;
            break;
        case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
            cfd = (struct usb_cdc_country_functional_desc *)buffer;
            break;
        case USB_CDC_HEADER_TYPE: /* maybe check version */
            break; /* for now we ignore it */
        case USB_CDC_ACM_TYPE:
            ac_management_function = buffer[3];
            break;
        case USB_CDC_CALL_MANAGEMENT_TYPE:
            call_management_function = buffer[3];
            call_interface_num = buffer[4];
            if ((call_management_function & 3) != 3)
                dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
            break;
        default:
            /* there are LOTS more CDC descriptors that
             * could legitimately be found here.
             */
            dev_dbg(&intf->dev, "Ignoring descriptor: "
                    "type %02x, length %d\n",
                    buffer[2], buffer[0]);
            break;
        }
next_desc:
        buflen -= buffer[0];
        buffer += buffer[0];
    }

    if (!union_header) {
        if (call_interface_num > 0) {
            dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
            data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
            control_interface = intf;
        } else {
            if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
                dev_dbg(&intf->dev,"No union descriptor, giving up\n");
                return -ENODEV;
            } else {
                dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
                combined_interfaces = 1;
                control_interface = data_interface = intf;
                goto look_for_collapsed_interface;
            }
        }
    } else {
        control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
        data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
        if (!control_interface || !data_interface) {
            dev_dbg(&intf->dev, "no interfaces\n");
            return -ENODEV;
        }
    }

    if (data_interface_num != call_interface_num)
        dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");

    if (control_interface == data_interface) {
        /* some broken devices designed for windows work this way */
        dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
        combined_interfaces = 1;
        /* a popular other OS doesn't use it */
        quirks |= NO_CAP_LINE;
        if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
            dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
            return -EINVAL;
        }
look_for_collapsed_interface:
        for (i = 0; i < 3; i++) {
            struct usb_endpoint_descriptor *ep;
            ep = &data_interface->cur_altsetting->endpoint[i].desc;

            if (usb_endpoint_is_int_in(ep))
                epctrl = ep;
            else if (usb_endpoint_is_bulk_out(ep))
                epwrite = ep;
            else if (usb_endpoint_is_bulk_in(ep))
                epread = ep;
            else
                return -EINVAL;
        }
        if (!epctrl || !epread || !epwrite)
            return -ENODEV;
        else
            goto made_compressed_probe;
    }

skip_normal_probe:

    /*workaround for switched interfaces */
    if (data_interface->cur_altsetting->desc.bInterfaceClass
            != CDC_DATA_INTERFACE_TYPE) {
        if (control_interface->cur_altsetting->desc.bInterfaceClass
                == CDC_DATA_INTERFACE_TYPE) {
            struct usb_interface *t;
            dev_dbg(&intf->dev,
                    "Your device has switched interfaces.\n");
            t = control_interface;
            control_interface = data_interface;
            data_interface = t;
        } else {
            return -EINVAL;
        }
    }

    /* Accept probe requests only for the control interface */
    if (!combined_interfaces && intf != control_interface)
        return -ENODEV;

    if (!combined_interfaces && usb_interface_claimed(data_interface)) {
        /* valid in this context */
        dev_dbg(&intf->dev, "The data interface isn't available\n");
        return -EBUSY;
    }


    if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
        return -EINVAL;

    epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
    epread = &data_interface->cur_altsetting->endpoint[0].desc;
    epwrite = &data_interface->cur_altsetting->endpoint[1].desc;


    /* workaround for switched endpoints */
    if (!usb_endpoint_dir_in(epread)) {
        /* descriptors are swapped */
        struct usb_endpoint_descriptor *t;
        dev_dbg(&intf->dev,
                "The data interface has switched endpoints\n");
        t = epread;
        epread = epwrite;
        epwrite = t;
    }
made_compressed_probe:
    dbg("interfaces are valid");
    for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);

    if (minor == ACM_TTY_MINORS) {
        dev_err(&intf->dev, "no more free acm devices\n");
        return -ENODEV;
    }

    acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
    if (acm == NULL) {
        dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
        goto alloc_fail;
    }

    ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
    readsize = le16_to_cpu(epread->wMaxPacketSize) *
               (quirks == SINGLE_RX_URB ? 1 : 2);
    acm->combined_interfaces = combined_interfaces;
    acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
    acm->control = control_interface;
    acm->data = data_interface;
    acm->minor = minor;
    acm->dev = usb_dev;
    acm->ctrl_caps = ac_management_function;
    if (quirks & NO_CAP_LINE)
        acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
    acm->ctrlsize = ctrlsize;
    acm->readsize = readsize;
    acm->rx_buflimit = num_rx_buf;
    acm->urb_task.func = acm_rx_tasklet;
    acm->urb_task.data = (unsigned long) acm;
    INIT_WORK(&acm->work, acm_softint);
    INIT_WORK(&acm->waker, acm_waker);
    init_waitqueue_head(&acm->drain_wait);
    spin_lock_init(&acm->throttle_lock);
    spin_lock_init(&acm->write_lock);
    spin_lock_init(&acm->read_lock);
    mutex_init(&acm->mutex);
    acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
    acm->is_int_ep = usb_endpoint_xfer_int(epread);
    if (acm->is_int_ep)
        acm->bInterval = epread->bInterval;
    tty_port_init(&acm->port);
    acm->port.ops = &acm_port_ops;

    buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
    if (!buf) {
        dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
        goto alloc_fail2;
    }
    acm->ctrl_buffer = buf;

    if (acm_write_buffers_alloc(acm) < 0) {
        dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
        goto alloc_fail4;
    }

    acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
    if (!acm->ctrlurb) {
        dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
        goto alloc_fail5;
    }
    for (i = 0; i < num_rx_buf; i++) {
        struct acm_ru *rcv = &(acm->ru[i]);

        rcv->urb = usb_alloc_urb(0, GFP_KERNEL);
        if (rcv->urb == NULL) {
            dev_dbg(&intf->dev,
                    "out of memory (read urbs usb_alloc_urb)\n");
            goto alloc_fail7;
        }

        rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        rcv->instance = acm;
    }
    for (i = 0; i < num_rx_buf; i++) {
        struct acm_rb *rb = &(acm->rb[i]);

        rb->base = usb_buffer_alloc(acm->dev, readsize,
                                    GFP_KERNEL, &rb->dma);
        if (!rb->base) {
            dev_dbg(&intf->dev,
                    "out of memory (read bufs usb_buffer_alloc)\n");
            goto alloc_fail7;
        }
    }
    for (i = 0; i < ACM_NW; i++) {
        struct acm_wb *snd = &(acm->wb[i]);

        snd->urb = usb_alloc_urb(0, GFP_KERNEL);
        if (snd->urb == NULL) {
            dev_dbg(&intf->dev,
                    "out of memory (write urbs usb_alloc_urb)");
            goto alloc_fail7;
        }

        if (usb_endpoint_xfer_int(epwrite))
            usb_fill_int_urb(snd->urb, usb_dev,
                             usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
                             NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);
        else
            usb_fill_bulk_urb(snd->urb, usb_dev,
                              usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
                              NULL, acm->writesize, acm_write_bulk, snd);
        snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        snd->instance = acm;
    }

    usb_set_intfdata(intf, acm);

    i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
    if (i < 0)
        goto alloc_fail8;

    if (cfd) { /* export the country data */
        acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
        if (!acm->country_codes)
            goto skip_countries;
        acm->country_code_size = cfd->bLength - 4;
        memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
               cfd->bLength - 4);
        acm->country_rel_date = cfd->iCountryCodeRelDate;

        i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
        if (i < 0) {
            kfree(acm->country_codes);
            goto skip_countries;
        }

        i = device_create_file(&intf->dev,
                               &dev_attr_iCountryCodeRelDate);
        if (i < 0) {
            kfree(acm->country_codes);
            goto skip_countries;
        }
    }

skip_countries:
    usb_fill_int_urb(acm->ctrlurb, usb_dev,
                     usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
                     acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
                     /* works around buggy devices */
                     epctrl->bInterval ? epctrl->bInterval : 0xff);
    acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    acm->ctrlurb->transfer_dma = acm->ctrl_dma;

    dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);

    acm_set_control(acm, acm->ctrlout);

    acm->line.dwDTERate = cpu_to_le32(9600);
    acm->line.bDataBits = 8;
    acm_set_line(acm, &acm->line);

    usb_driver_claim_interface(&acm_driver, data_interface, acm);
    usb_set_intfdata(data_interface, acm);

    usb_get_intf(control_interface);
    tty_register_device(acm_tty_driver, minor, &control_interface->dev);

    acm_table[minor] = acm;

    return 0;
alloc_fail8:
    for (i = 0; i < ACM_NW; i++)
        usb_free_urb(acm->wb[i].urb);
alloc_fail7:
    acm_read_buffers_free(acm);
    for (i = 0; i < num_rx_buf; i++)
        usb_free_urb(acm->ru[i].urb);
    usb_free_urb(acm->ctrlurb);
alloc_fail5:
    acm_write_buffers_free(acm);
alloc_fail4:
    usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
alloc_fail2:
    kfree(acm);
alloc_fail:
    return -ENOMEM;
}
Пример #8
0
static int __init spi_tty_init(void)
{
	int retval;
	struct spi_tty_s *spi_tty;

	SPI_IPC_INFO("%s\n", __func__);

	tx_size = 0L;
	tx_time = 0L;
	tx_count = 0L;
	write_count = 0L;

	spi_tty_gbl = kmalloc(sizeof(*spi_tty), GFP_KERNEL);
	if (spi_tty_gbl == NULL) {
		pr_err("%s: Cannot malloc mem!\n", __func__);
		return -ENOMEM;
	}

	memset(spi_tty_gbl, 0x0, sizeof(*spi_tty));
	spi_tty = spi_tty_gbl;

	spi_tty->write_buf = spi_tty_buf_alloc();
	if (!spi_tty->write_buf) {
		kfree(spi_tty_gbl);
		pr_err("failed to malloc spi_tty write buf!\n");
		return -ENOMEM;
	}

	spi_tty->throttle = 0;
	spi_tty->open_count = 0;
	spi_tty->tx_null = 0;
	spin_lock_init(&spi_tty->port_lock);
	mutex_init(&spi_tty->work_lock);
	INIT_WORK(&spi_tty->write_work, spi_tty_write_worker);
	wake_lock_init(&spi_tty->wakelock, WAKE_LOCK_SUSPEND, "spi_tty_wakelock");

	init_waitqueue_head(&spi_tty->write_wait);
	spi_tty->write_buf_full = 0;

	spi_tty->work_queue = create_singlethread_workqueue("spi_tty_wq");
	if (spi_tty->work_queue  == NULL) {
		kfree(spi_tty);
		kfree(spi_big_trans.tx_buf);
		pr_err("Failed to create work queue\n");
		return -ESRCH;
	}

	spi_message_init(&spi_big_msg);

	spi_big_trans.tx_buf = kmalloc(SPI_TRANSACTION_LEN*2, GFP_KERNEL);
	if (!spi_big_trans.tx_buf) {
		kfree(spi_tty);
		pr_err("%s: Cannot malloc mem!\n", __func__);
		return -ENOMEM;
	}

	spi_big_trans.rx_buf =
			(char*)spi_big_trans.tx_buf + SPI_TRANSACTION_LEN;
	spi_message_add_tail(&spi_big_trans, &spi_big_msg);

	spi_tty_driver = alloc_tty_driver(SPI_TTY_MINORS);
	if (!spi_tty_driver)
		return -ENOMEM;

	spi_tty_driver->owner = THIS_MODULE;
	spi_tty_driver->driver_name = "spi_modem";
	spi_tty_driver->name = "ttySPI";
	spi_tty_driver->major = SPI_TTY_MAJOR;
	spi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	spi_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	spi_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	spi_tty_driver->init_termios = tty_std_termios;
	spi_tty_driver->init_termios.c_cflag =
		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
	tty_set_operations(spi_tty_driver, &serial_ops);

	retval = tty_register_driver(spi_tty_driver);
	if (retval) {
		pr_err("failed to register spi_tty tty driver");
		put_tty_driver(spi_tty_driver);
		return retval;
	}

	tty_register_device(spi_tty_driver, 0, NULL);

	/* 
	 * If spi_tty_register_device() was called before spi_tty_init(), fill
	 * in the blanks.  Yeah, it's ugly.
	 */
	if (spi_tty_dev)
		spi_tty_dev->callback_context = spi_tty;

	return retval;
}
Пример #9
0
static int __init lge_tty_atcmd_init(void)
{
	int ret;

	printk(KERN_INFO"%s: initialize atcmd-ttys\n", __func__);

	/* allocate and initialize downstream buffers */
	down_stream_buffer.buf_addr = kmalloc(BUF_SIZE, GFP_KERNEL);
	if (down_stream_buffer.buf_addr == NULL)
		goto down_stream_buf_alloc_error;
	down_stream_buffer.head = 0;
	down_stream_buffer.tail = 0;
	down_stream_buffer.fifo_mask = BUF_SIZE - 1;
	down_stream_buffer.size = BUF_SIZE;
	down_stream_buffer.count = 0;
	down_stream_buffer.lock = &atcmd_ds_buf_lock;
	
	/* allocate and initialize upstream buffers */
	up_stream_buffer.buf_addr = kmalloc(BUF_SIZE, GFP_KERNEL);
	if (up_stream_buffer.buf_addr == NULL)
		goto up_stream_buf_alloc_error;
	up_stream_buffer.head = 0;
	up_stream_buffer.tail = 0;
	up_stream_buffer.fifo_mask = BUF_SIZE - 1;
	up_stream_buffer.size = BUF_SIZE;
	up_stream_buffer.count = 0;
	up_stream_buffer.lock = &atcmd_us_buf_lock;

	/* allocate tty driver */
	atcmd_tty_driver = alloc_tty_driver(MAX_ATCMD_TTYS);
	if (atcmd_tty_driver == 0)
		goto tty_alloc_error;
	
	/* setting tty */
	atcmd_tty_driver->owner = THIS_MODULE;
	atcmd_tty_driver->driver_name = "atcmd-tty-driver";
	atcmd_tty_driver->name = "atcmd-tty";
	atcmd_tty_driver->major = 0;
	atcmd_tty_driver->minor_start = 0;
	atcmd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	atcmd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	atcmd_tty_driver->init_termios = tty_std_termios;
	atcmd_tty_driver->init_termios.c_iflag = 0;
	atcmd_tty_driver->init_termios.c_oflag = 0;
	atcmd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
	atcmd_tty_driver->init_termios.c_lflag = 0;
	atcmd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	tty_set_operations(atcmd_tty_driver, &atcmd_tty_ops);
	ret = tty_register_driver(atcmd_tty_driver);
	if (ret)
		return ret;

	/* this should be dynamic */
	tty_register_device(atcmd_tty_driver, 0, 0);
	tty_register_device(atcmd_tty_driver, 1, 0);

	return 0;

tty_alloc_error:
	kfree(up_stream_buffer.buf_addr);
up_stream_buf_alloc_error:
	kfree(down_stream_buffer.buf_addr);
down_stream_buf_alloc_error:
	return -ENOMEM;
}
static int __init hsic_tty_init(void)
{
    int ret;
    int n;
    unsigned port_num;

    pr_debug("%s\n", __func__);

    hsic_tty_driver = alloc_tty_driver(MAX_HSIC_TTYS);
    if (hsic_tty_driver == 0)
        return -ENOMEM;

    hsic_tty_driver->owner = THIS_MODULE;
    hsic_tty_driver->driver_name = "hsic_tty_driver";
    hsic_tty_driver->name = "hsic";
    hsic_tty_driver->major = 0;
    hsic_tty_driver->minor_start = 0;
    hsic_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
    hsic_tty_driver->subtype = SERIAL_TYPE_NORMAL;
    hsic_tty_driver->init_termios = tty_std_termios;
    hsic_tty_driver->init_termios.c_iflag = 0;
    hsic_tty_driver->init_termios.c_oflag = 0;
    hsic_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
    hsic_tty_driver->init_termios.c_lflag = 0;
    hsic_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
        TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
    tty_set_operations(hsic_tty_driver, &hsic_tty_ops);

    ret = tty_register_driver(hsic_tty_driver);
    if (ret) {
        put_tty_driver(hsic_tty_driver);
        pr_err("%s: driver registration failed %d\n", __func__, ret);
        return ret;
    }

    port_num = hsic_tty_data_setup(1, HSIC_TTY_SERIAL);
    if (port_num < 0)
    {
        pr_err("%s: hsic_tty_data_setup failed\n", __func__);
        goto out;
    }

    ret = hsic_tty_ctrl_setup(1, HSIC_TTY_SERIAL);
    if (ret < 0)
    {
        pr_err("%s: hsic_tty_ctrl_setup failed\n", __func__);
        goto out;
    }

    hsic_tty.client_port_num = port_num;
#ifdef CONFIG_MODEM_SUPPORT
    spin_lock_init(&hsic_tty.lock);
    spin_lock_init(&hsic_tty.reset_lock);
    hsic_tty.connect = hsic_tty_connect;
    hsic_tty.get_dtr = hsic_tty_get_dtr;
    hsic_tty.get_rts = hsic_tty_get_rts;
    hsic_tty.send_carrier_detect = hsic_tty_send_carrier_detect;
    hsic_tty.send_ring_indicator = hsic_tty_send_ring_indicator;
    hsic_tty.send_modem_ctrl_bits = hsic_tty_send_modem_ctrl_bits;
    hsic_tty.disconnect = hsic_tty_disconnect;
    hsic_tty.send_break = hsic_tty_send_break;;
#endif
    hsic_tty.tty = NULL;

    ret = hsic_tty_ctrl_connect(&hsic_tty, port_num);
    if (ret) {
        pr_err("%s: hsic_tty_ctrl_connect failed: err:%d\n",
                __func__, ret);
        goto out;
    }

    ret = hsic_tty_data_connect(&hsic_tty, port_num);
    if (ret) {
        pr_err("%s: hsic_tty_data_connect failed: err:%d\n",
                __func__, ret);
        hsic_tty_ctrl_disconnect(&hsic_tty, port_num);
        goto out;
    }

    for (n = 0; n < MAX_HSIC_TTYS; ++n)
    {
        pr_info("%s: %d\n", __func__, n);
        tty_register_device(hsic_tty_driver, n, 0);
    }
    return 0;

out:
    tty_unregister_driver(hsic_tty_driver);
    put_tty_driver(hsic_tty_driver);
    return ret;
}