コード例 #1
0
ファイル: tty.c プロジェクト: mikuhatsune001/linux2.6.32
static int add_tty(int j,
		    struct ipw_hardware *hardware,
		    struct ipw_network *network, int channel_idx,
		    int secondary_channel_idx, int tty_type)
{
	ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL);
	if (!ttys[j])
		return -ENOMEM;
	ttys[j]->index = j;
	ttys[j]->hardware = hardware;
	ttys[j]->channel_idx = channel_idx;
	ttys[j]->secondary_channel_idx = secondary_channel_idx;
	ttys[j]->network = network;
	ttys[j]->tty_type = tty_type;
	mutex_init(&ttys[j]->ipw_tty_mutex);
	tty_port_init(&ttys[j]->port);

	tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL);
	ipwireless_associate_network_tty(network, channel_idx, ttys[j]);

	if (secondary_channel_idx != -1)
		ipwireless_associate_network_tty(network,
						 secondary_channel_idx,
						 ttys[j]);
	/* check if we provide raw device (if loopback is enabled) */
	if (get_tty(j))
		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
		       ": registering %s device ttyIPWp%d\n",
		       tty_type_name(tty_type), j);

	return 0;
}
コード例 #2
0
ファイル: main.c プロジェクト: h-hata/htty
int create_htty(char *name,int index,BUFFER *rbuf,BUFFER *wbuf)
{
	char	ptr[120];
	struct htty_serial *htty;
	if(index<0 || index>=CMINORS){
		return -1;
	}
	/* first time accessing this device, let's create it */
	htty=htty_table[index];
	if(htty==NULL){
		htty = kmalloc(sizeof(*htty), GFP_KERNEL);
		if (!htty)
			return -ENOMEM;
		//init_MUTEX(&htty->sem);
		sema_init(&htty->sem,1);
		htty_table[index] = htty;
	}
	memcpy(&htty->termios,&tty_std_termios,sizeof(struct termios));
	htty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
	htty->open_count = 0;
	htty->minor=index;
	tty_port_init(&tty_port[index]);
	sprintf(ptr,"htty_%s",name);
	tty_driver->name=ptr;
	sprintf(htty->name,"%s",ptr);
	htty->port=&tty_port[index];
	tty_port_register_device(&tty_port[index],tty_driver,index, NULL);
	pr_info(DRIVER_DESC " create device %s minor=%d\n",ptr,index);
	return 0;
}
コード例 #3
0
static int __init citty_init(void)
{
	int retval;
	int i;

	F_ENTER();

	/* allocate the tty driver */
	citty_tty_driver = alloc_tty_driver(CITTY_TTY_MINORS);
	if (!citty_tty_driver)
		return -ENOMEM;

	/* initialize the tty driver */
	citty_tty_driver->owner = THIS_MODULE;
	citty_tty_driver->driver_name = "citty_tty";
	citty_tty_driver->name = "citty";
	citty_tty_driver->major = CITTY_TTY_MAJOR;
	citty_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	citty_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	citty_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	citty_tty_driver->init_termios = tty_std_termios;
	/* B115200 | CS8 | CREAD | HUPCL | CLOCAL; */
	citty_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
	citty_tty_driver->init_termios.c_iflag = IGNBRK | IGNCR | IGNPAR;
	citty_tty_driver->init_termios.c_oflag = 0;
	citty_tty_driver->init_termios.c_lflag = 0;

	tty_set_operations(citty_tty_driver, &serial_ops);

	/* register the tty driver */
	retval = tty_register_driver(citty_tty_driver);
	if (retval) {
		printk(KERN_ERR "failed to register citty tty driver");
		put_tty_driver(citty_tty_driver);
		citty_tty_driver = NULL;
		return retval;
	}

	/* register tty devices */
	for (i = 0; i < CITTY_TTY_MINORS; ++i) {
		/* Init buffer */
		cci_init_buffer(&txCittyBuf[i]);
		sema_init(&sem_lock_tty[i], 1);

		tty_port_init(&citty_port_table[i]);
		tty_port_register_device(&citty_port_table[i],
				citty_tty_driver, i, NULL);
	}

	printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");

	cctdev_init_module();

	F_LEAVE();
	return retval;
}
コード例 #4
0
ファイル: my_uart.c プロジェクト: aseyfi/linux_device_driver
static int __init my_uart_init(void)
{
    /* TODO Auto-generated Function Stub */

    int res;
    int i;

    my_uart_tty = alloc_tty_driver(MY_UART_N_MINORS);
    if (!my_uart_tty) {
        PERR("TTY Driver allocation failed\n");
        return -ENOMEM;
    }

    my_uart_tty_initialization();

    tty_set_operations(my_uart_tty, &my_uart_tops);

    res= tty_register_driver(my_uart_tty);
    if(res) {
        PERR("Failed to register the tty driver\n");
        return res;
    }

    for (i = 0; i < MY_UART_N_MINORS; i++) {

        init_timer(&devices[i].my_uart_timer1);
        devices[i].my_uart_timer1.data = &devices[i]; //TODO
        devices[i].my_uart_timer1.function = my_timer;
        devices[i].my_uart_timer1.expires = jiffies + MY_UART_DELAY_MS * HZ / 1000;

        tty_port_init(&devices[i].port);

#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
        tty_register_device(my_uart_tty, i, NULL);
#else
        tty_port_register_device(&devices[i].port, my_uart_tty, i, NULL);
#endif
    }

    PINFO("INIT\n");

    init_timer(&my_uart_timer);
    my_uart_timer.data = 100; //TODO
    my_uart_timer.function = my_timer;
    my_uart_timer.expires = jiffies + MY_UART_DELAY_MS * HZ / 1000;

    return 0;
}
コード例 #5
0
ファイル: gdm_tty.c プロジェクト: mikuhatsune001/linux2.6.32
int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device)
{
	struct gdm *gdm;
	int i;
	int j;

	for (i = 0; i < TTY_MAX_COUNT; i++) {

		gdm = kmalloc(sizeof(struct gdm), GFP_KERNEL);
		if (!gdm)
			return -ENOMEM;

		mutex_lock(&gdm_table_lock);
		for (j = 0; j < GDM_TTY_MINOR; j++) {
			if (!gdm_table[i][j])
				break;
		}

		if (j == GDM_TTY_MINOR) {
			kfree(gdm);
			mutex_unlock(&gdm_table_lock);
			return -EINVAL;
		}

		gdm_table[i][j] = gdm;
		mutex_unlock(&gdm_table_lock);

		tty_dev->gdm[i] = gdm;
		tty_port_init(&gdm->port);

		gdm->port.ops = &gdm_port_ops;
		gdm->index = i;
		gdm->minor = j;
		gdm->tty_dev = tty_dev;

		tty_port_register_device(&gdm->port, gdm_driver[i],
					 gdm->minor, device);
	}

	for (i = 0; i < MAX_ISSUE_NUM; i++)
		gdm_tty_recv(gdm, gdm_tty_recv_complete);

	return 0;
}
コード例 #6
0
int gserial_alloc_line(unsigned char *line_num)
{
	struct usb_cdc_line_coding	coding;
	struct device			*tty_dev;
	int				ret;
	int				port_num;

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

	for (port_num = 0; port_num < MAX_U_SERIAL_PORTS; port_num++) {
		ret = gs_port_alloc(port_num, &coding);
		if (ret == -EBUSY)
			continue;
		if (ret)
			return ret;
		break;
	}
	if (ret)
		return ret;

	/* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */

	tty_dev = tty_port_register_device(&ports[port_num].port->port,
			gs_tty_driver, port_num, NULL);

	if (IS_ERR(tty_dev)) {
		struct gs_port	*port;
		pr_err("%s: failed to register tty for port %d, err %ld\n",
				__func__, port_num, PTR_ERR(tty_dev));

		ret = PTR_ERR(tty_dev);
		port = ports[port_num].port;
		ports[port_num].port = NULL;
		gserial_free_port(port);
		goto err;
	}
	*line_num = port_num;
err:
	return ret;
}
コード例 #7
0
/* Diag char driver ready */
struct usb_diag_ch *tty_diag_channel_open(const char *name, void *priv,
		void (*notify)(void *, unsigned, struct diag_request *))
{
	int i;
	unsigned long flags;

	if (legacy_ch.priv != NULL)
		return ERR_PTR(-EBUSY);

	spin_lock_init(&diag_tty_lock);
	spin_lock_irqsave(&diag_tty_lock, flags);
	legacy_ch.priv = priv;
	legacy_ch.notify = notify;
	spin_unlock_irqrestore(&diag_tty_lock, flags);

	for (i = 0; i < DIAG_TTY_MINOR_COUNT; i++) {
		tty_port_init(&diag_tty[i].port);
		tty_port_register_device(&diag_tty[i].port, diag_tty_driver,
				i, NULL);
	}

	return &legacy_ch;
}
コード例 #8
0
ファイル: ipoctal.c プロジェクト: 03199618/linux
static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
			     unsigned int slot)
{
	int res;
	int i;
	struct tty_driver *tty;
	char name[20];
	struct ipoctal_channel *channel;
	struct ipack_region *region;
	void __iomem *addr;
	union scc2698_channel __iomem *chan_regs;
	union scc2698_block __iomem *block_regs;

	ipoctal->board_id = ipoctal->dev->id_device;

	region = &ipoctal->dev->region[IPACK_IO_SPACE];
	addr = devm_ioremap_nocache(&ipoctal->dev->dev,
				    region->start, region->size);
	if (!addr) {
		dev_err(&ipoctal->dev->dev,
			"Unable to map slot [%d:%d] IO space!\n",
			bus_nr, slot);
		return -EADDRNOTAVAIL;
	}
	/* Save the virtual address to access the registers easily */
	chan_regs =
		(union scc2698_channel __iomem *) addr;
	block_regs =
		(union scc2698_block __iomem *) addr;

	region = &ipoctal->dev->region[IPACK_INT_SPACE];
	ipoctal->int_space =
		devm_ioremap_nocache(&ipoctal->dev->dev,
				     region->start, region->size);
	if (!ipoctal->int_space) {
		dev_err(&ipoctal->dev->dev,
			"Unable to map slot [%d:%d] INT space!\n",
			bus_nr, slot);
		return -EADDRNOTAVAIL;
	}

	region = &ipoctal->dev->region[IPACK_MEM8_SPACE];
	ipoctal->mem8_space =
		devm_ioremap_nocache(&ipoctal->dev->dev,
				     region->start, 0x8000);
	if (!ipoctal->mem8_space) {
		dev_err(&ipoctal->dev->dev,
			"Unable to map slot [%d:%d] MEM8 space!\n",
			bus_nr, slot);
		return -EADDRNOTAVAIL;
	}


	/* Disable RX and TX before touching anything */
	for (i = 0; i < NR_CHANNELS ; i++) {
		struct ipoctal_channel *channel = &ipoctal->channel[i];
		channel->regs = chan_regs + i;
		channel->block_regs = block_regs + (i >> 1);
		channel->board_id = ipoctal->board_id;
		if (i & 1) {
			channel->isr_tx_rdy_mask = ISR_TxRDY_B;
			channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_B;
		} else {
			channel->isr_tx_rdy_mask = ISR_TxRDY_A;
			channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_A;
		}

		iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr);
		channel->rx_enable = 0;
		iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr);
		iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr);
		iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY,
			 &channel->regs->w.mr); /* mr1 */
		iowrite8(0, &channel->regs->w.mr); /* mr2 */
		iowrite8(TX_CLK_9600  | RX_CLK_9600, &channel->regs->w.csr);
	}

	for (i = 0; i < IP_OCTAL_NB_BLOCKS; i++) {
		iowrite8(ACR_BRG_SET2, &block_regs[i].w.acr);
		iowrite8(OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN | OPCR_MPOb_RTSN,
			 &block_regs[i].w.opcr);
		iowrite8(IMR_TxRDY_A | IMR_RxRDY_FFULL_A | IMR_DELTA_BREAK_A |
			 IMR_TxRDY_B | IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B,
			 &block_regs[i].w.imr);
	}

	/*
	 * IP-OCTAL has different addresses to copy its IRQ vector.
	 * Depending of the carrier these addresses are accesible or not.
	 * More info in the datasheet.
	 */
	ipoctal->dev->bus->ops->request_irq(ipoctal->dev,
				       ipoctal_irq_handler, ipoctal);
	/* Dummy write */
	iowrite8(1, ipoctal->mem8_space + 1);

	/* Register the TTY device */

	/* Each IP-OCTAL channel is a TTY port */
	tty = alloc_tty_driver(NR_CHANNELS);

	if (!tty)
		return -ENOMEM;

	/* Fill struct tty_driver with ipoctal data */
	tty->owner = THIS_MODULE;
	tty->driver_name = KBUILD_MODNAME;
	sprintf(name, KBUILD_MODNAME ".%d.%d.", bus_nr, slot);
	tty->name = name;
	tty->major = 0;

	tty->minor_start = 0;
	tty->type = TTY_DRIVER_TYPE_SERIAL;
	tty->subtype = SERIAL_TYPE_NORMAL;
	tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	tty->init_termios = tty_std_termios;
	tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
	tty->init_termios.c_ispeed = 9600;
	tty->init_termios.c_ospeed = 9600;

	tty_set_operations(tty, &ipoctal_fops);
	res = tty_register_driver(tty);
	if (res) {
		dev_err(&ipoctal->dev->dev, "Can't register tty driver.\n");
		put_tty_driver(tty);
		return res;
	}

	/* Save struct tty_driver for use it when uninstalling the device */
	ipoctal->tty_drv = tty;

	for (i = 0; i < NR_CHANNELS; i++) {
		struct device *tty_dev;

		channel = &ipoctal->channel[i];
		tty_port_init(&channel->tty_port);
		tty_port_alloc_xmit_buf(&channel->tty_port);
		channel->tty_port.ops = &ipoctal_tty_port_ops;

		ipoctal_reset_stats(&channel->stats);
		channel->nb_bytes = 0;
		spin_lock_init(&channel->lock);
		channel->pointer_read = 0;
		channel->pointer_write = 0;
		tty_dev = tty_port_register_device(&channel->tty_port, tty, i, NULL);
		if (IS_ERR(tty_dev)) {
			dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n");
			tty_port_destroy(&channel->tty_port);
			continue;
		}
		dev_set_drvdata(tty_dev, channel);
	}

	return 0;
}
コード例 #9
0
ファイル: nozomi.c プロジェクト: ReneNyffenegger/linux
/* Allocate memory for one device */
static int nozomi_card_init(struct pci_dev *pdev,
				      const struct pci_device_id *ent)
{
	resource_size_t start;
	int ret;
	struct nozomi *dc = NULL;
	int ndev_idx;
	int i;

	dev_dbg(&pdev->dev, "Init, new card found\n");

	for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++)
		if (!ndevs[ndev_idx])
			break;

	if (ndev_idx >= ARRAY_SIZE(ndevs)) {
		dev_err(&pdev->dev, "no free tty range for this card left\n");
		ret = -EIO;
		goto err;
	}

	dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL);
	if (unlikely(!dc)) {
		dev_err(&pdev->dev, "Could not allocate memory\n");
		ret = -ENOMEM;
		goto err_free;
	}

	dc->pdev = pdev;

	ret = pci_enable_device(dc->pdev);
	if (ret) {
		dev_err(&pdev->dev, "Failed to enable PCI Device\n");
		goto err_free;
	}

	ret = pci_request_regions(dc->pdev, NOZOMI_NAME);
	if (ret) {
		dev_err(&pdev->dev, "I/O address 0x%04x already in use\n",
			(int) /* nozomi_private.io_addr */ 0);
		goto err_disable_device;
	}

	start = pci_resource_start(dc->pdev, 0);
	if (start == 0) {
		dev_err(&pdev->dev, "No I/O address for card detected\n");
		ret = -ENODEV;
		goto err_rel_regs;
	}

	/* Find out what card type it is */
	nozomi_get_card_type(dc);

	dc->base_addr = ioremap_nocache(start, dc->card_type);
	if (!dc->base_addr) {
		dev_err(&pdev->dev, "Unable to map card MMIO\n");
		ret = -ENODEV;
		goto err_rel_regs;
	}

	dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL);
	if (!dc->send_buf) {
		dev_err(&pdev->dev, "Could not allocate send buffer?\n");
		ret = -ENOMEM;
		goto err_free_sbuf;
	}

	for (i = PORT_MDM; i < MAX_PORT; i++) {
		if (kfifo_alloc(&dc->port[i].fifo_ul, FIFO_BUFFER_SIZE_UL,
					GFP_KERNEL)) {
			dev_err(&pdev->dev,
					"Could not allocate kfifo buffer\n");
			ret = -ENOMEM;
			goto err_free_kfifo;
		}
	}

	spin_lock_init(&dc->spin_mutex);

	nozomi_setup_private_data(dc);

	/* Disable all interrupts */
	dc->last_ier = 0;
	writew(dc->last_ier, dc->reg_ier);

	ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED,
			NOZOMI_NAME, dc);
	if (unlikely(ret)) {
		dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq);
		goto err_free_kfifo;
	}

	DBG1("base_addr: %p", dc->base_addr);

	make_sysfs_files(dc);

	dc->index_start = ndev_idx * MAX_PORT;
	ndevs[ndev_idx] = dc;

	pci_set_drvdata(pdev, dc);

	/* Enable RESET interrupt */
	dc->last_ier = RESET;
	iowrite16(dc->last_ier, dc->reg_ier);

	dc->state = NOZOMI_STATE_ENABLED;

	for (i = 0; i < MAX_PORT; i++) {
		struct device *tty_dev;
		struct port *port = &dc->port[i];
		port->dc = dc;
		tty_port_init(&port->port);
		port->port.ops = &noz_tty_port_ops;
		tty_dev = tty_port_register_device(&port->port, ntty_driver,
				dc->index_start + i, &pdev->dev);

		if (IS_ERR(tty_dev)) {
			ret = PTR_ERR(tty_dev);
			dev_err(&pdev->dev, "Could not allocate tty?\n");
			tty_port_destroy(&port->port);
			goto err_free_tty;
		}
	}

	return 0;

err_free_tty:
	for (i = 0; i < MAX_PORT; ++i) {
		tty_unregister_device(ntty_driver, dc->index_start + i);
		tty_port_destroy(&dc->port[i].port);
	}
err_free_kfifo:
	for (i = 0; i < MAX_PORT; i++)
		kfifo_free(&dc->port[i].fifo_ul);
err_free_sbuf:
	kfree(dc->send_buf);
	iounmap(dc->base_addr);
err_rel_regs:
	pci_release_regions(pdev);
err_disable_device:
	pci_disable_device(pdev);
err_free:
	kfree(dc);
err:
	return ret;
}
コード例 #10
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;
	struct device *tty_dev;
	int rv = -ENOMEM;

	/* 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 &&
				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 ((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:
			/* 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");
			/* quirks for Droids MuIn LCD */
			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) {
		/* 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 ||
	    control_interface->cur_altsetting->desc.bNumEndpoints == 0)
		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:
	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_sndintpipe(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) { /* 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);
			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,
			 /* 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_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,
			&control_interface->dev);
	if (IS_ERR(tty_dev)) {
		rv = PTR_ERR(tty_dev);
		goto alloc_fail8;
	}

	return 0;
alloc_fail8:
	if (acm->country_codes) {
		device_remove_file(&acm->control->dev,
				&dev_attr_wCountryCodes);
		device_remove_file(&acm->control->dev,
				&dev_attr_iCountryCodeRelDate);
	}
	device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
alloc_fail7:
	usb_set_intfdata(intf, NULL);
	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 rv;
}
コード例 #11
0
ファイル: goldfish.c プロジェクト: SantoshShilimkar/linux
static int goldfish_tty_probe(struct platform_device *pdev)
{
	struct goldfish_tty *qtty;
	int ret = -ENODEV;
	struct resource *r;
	struct device *ttydev;
	void __iomem *base;
	u32 irq;
	unsigned int line;

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!r) {
		pr_err("goldfish_tty: No MEM resource available!\n");
		return -ENOMEM;
	}

	base = ioremap(r->start, 0x1000);
	if (!base) {
		pr_err("goldfish_tty: Unable to ioremap base!\n");
		return -ENOMEM;
	}

	r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!r) {
		pr_err("goldfish_tty: No IRQ resource available!\n");
		goto err_unmap;
	}

	irq = r->start;

	mutex_lock(&goldfish_tty_lock);

	if (pdev->id == PLATFORM_DEVID_NONE)
		line = goldfish_tty_current_line_count;
	else
		line = pdev->id;

	if (line >= goldfish_tty_line_count) {
		pr_err("goldfish_tty: Reached maximum tty number of %d.\n",
		       goldfish_tty_current_line_count);
		ret = -ENOMEM;
		goto err_unlock;
	}

	if (goldfish_tty_current_line_count == 0) {
		ret = goldfish_tty_create_driver();
		if (ret)
			goto err_unlock;
	}
	goldfish_tty_current_line_count++;

	qtty = &goldfish_ttys[line];
	spin_lock_init(&qtty->lock);
	tty_port_init(&qtty->port);
	qtty->port.ops = &goldfish_port_ops;
	qtty->base = base;
	qtty->irq = irq;
	qtty->dev = &pdev->dev;

	/*
	 * Goldfish TTY device used by the Goldfish emulator
	 * should identify itself with 0, forcing the driver
	 * to use virtual addresses. Goldfish TTY device
	 * on Ranchu emulator (qemu2) returns 1 here and
	 * driver will use physical addresses.
	 */
	qtty->version = readl(base + GOLDFISH_TTY_REG_VERSION);

	/*
	 * Goldfish TTY device on Ranchu emulator (qemu2)
	 * will use DMA for read/write IO operations.
	 */
	if (qtty->version > 0) {
		/*
		 * Initialize dma_mask to 32-bits.
		 */
		if (!pdev->dev.dma_mask)
			pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
		ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
		if (ret) {
			dev_err(&pdev->dev, "No suitable DMA available.\n");
			goto err_dec_line_count;
		}
	}

	writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD);

	ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED,
			  "goldfish_tty", qtty);
	if (ret) {
		pr_err("goldfish_tty: No IRQ available!\n");
		goto err_dec_line_count;
	}

	ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
					  line, &pdev->dev);
	if (IS_ERR(ttydev)) {
		ret = PTR_ERR(ttydev);
		goto err_tty_register_device_failed;
	}

	strcpy(qtty->console.name, "ttyGF");
	qtty->console.write = goldfish_tty_console_write;
	qtty->console.device = goldfish_tty_console_device;
	qtty->console.setup = goldfish_tty_console_setup;
	qtty->console.flags = CON_PRINTBUFFER;
	qtty->console.index = line;
	register_console(&qtty->console);
	platform_set_drvdata(pdev, qtty);

	mutex_unlock(&goldfish_tty_lock);
	return 0;

err_tty_register_device_failed:
	free_irq(irq, qtty);
err_dec_line_count:
	goldfish_tty_current_line_count--;
	if (goldfish_tty_current_line_count == 0)
		goldfish_tty_delete_driver();
err_unlock:
	mutex_unlock(&goldfish_tty_lock);
err_unmap:
	iounmap(base);
	return ret;
}
コード例 #12
0
ファイル: ehv_bytechan.c プロジェクト: realmz/blackfin-linux
static int ehv_bc_tty_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct ehv_bc_data *bc;
	const uint32_t *iprop;
	unsigned int handle;
	int ret;
	static unsigned int index = 1;
	unsigned int i;

	iprop = of_get_property(np, "hv-handle", NULL);
	if (!iprop) {
		dev_err(&pdev->dev, "no 'hv-handle' property in %s node\n",
			np->name);
		return -ENODEV;
	}

	/* We already told the console layer that the index for the console
	 * device is zero, so we need to make sure that we use that index when
	 * we probe the console byte channel node.
	 */
	handle = be32_to_cpu(*iprop);
	i = (handle == stdout_bc) ? 0 : index++;
	bc = &bcs[i];

	bc->handle = handle;
	bc->head = 0;
	bc->tail = 0;
	spin_lock_init(&bc->lock);

	bc->rx_irq = irq_of_parse_and_map(np, 0);
	bc->tx_irq = irq_of_parse_and_map(np, 1);
	if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) {
		dev_err(&pdev->dev, "no 'interrupts' property in %s node\n",
			np->name);
		ret = -ENODEV;
		goto error;
	}

	tty_port_init(&bc->port);
	bc->port.ops = &ehv_bc_tty_port_ops;

	bc->dev = tty_port_register_device(&bc->port, ehv_bc_driver, i,
			&pdev->dev);
	if (IS_ERR(bc->dev)) {
		ret = PTR_ERR(bc->dev);
		dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret);
		goto error;
	}

	dev_set_drvdata(&pdev->dev, bc);

	dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n",
		ehv_bc_driver->name, i, bc->handle);

	return 0;

error:
	tty_port_destroy(&bc->port);
	irq_dispose_mapping(bc->tx_irq);
	irq_dispose_mapping(bc->rx_irq);

	memset(bc, 0, sizeof(struct ehv_bc_data));
	return ret;
}
コード例 #13
0
static int mcu_platform_probe(struct platform_device *pdev)
{
	int ret, i;
	struct mcu_data *data;
	struct mcu *mcu;
	u8 *base;

	mcu = platform_get_drvdata(pdev);
	intel_mcu_tty_driver = alloc_tty_driver(INTEL_MCU_TTY_MINORS);
	if (!intel_mcu_tty_driver) {
		dev_err(&pdev->dev, "fail to alloc tty driver\n");
		return -ENODEV;
	}

	intel_mcu_tty_driver->name = "ttymcu";
	intel_mcu_tty_driver->major = INTEL_MCU_TTY_MAJOR;
	intel_mcu_tty_driver->minor_start = 0;
	intel_mcu_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	intel_mcu_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	intel_mcu_tty_driver->flags = TTY_DRIVER_REAL_RAW
		| TTY_DRIVER_DYNAMIC_DEV;
	intel_mcu_tty_driver->init_termios = tty_std_termios;
	intel_mcu_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
		HUPCL | CLOCAL;
	intel_mcu_tty_driver->init_termios.c_ispeed = 38400;
	intel_mcu_tty_driver->init_termios.c_ospeed = 38400;
	intel_mcu_tty_driver->init_termios.c_iflag = 0;
	intel_mcu_tty_driver->init_termios.c_oflag = 0;
	intel_mcu_tty_driver->init_termios.c_lflag = 0;
	tty_set_operations(intel_mcu_tty_driver, &intel_mcu_ops);

	ret = tty_register_driver(intel_mcu_tty_driver);
	if (ret) {
		dev_err(&pdev->dev, "fail to register tty driver\n");
		goto tty_reg_fail;
	}

	base = (u8 *)mcu->ddr[1];
	for (i = INTEL_MCU_TTY_MINORS - 1; i >= 0; i--) {
		data = kzalloc(sizeof(struct mcu_data), GFP_KERNEL);
		if (data == NULL) {
			dev_err(&pdev->dev, "fail to alloc mcu data\n");
			goto data_alloc_fail;
		}

		data->index = i;
		tty_port_init(&data->port);
		data->dev = tty_port_register_device(&data->port,
				intel_mcu_tty_driver, i, &pdev->dev);
		mcu_table[i] = data;
		data->mcu = mcu;
		init_completion(&data->cmp);
		data->lbuf.addr = base;
		data->lbuf.length = BUF_IA_DDR_SIZE;
		lbuf_read_reset(&data->lbuf);
		base += BUF_IA_DDR_SIZE;
	}
	ret = sysfs_create_group(&pdev->dev.kobj,
			&intel_mcu_tty_attribute_group);
	if (ret) {
		pr_err("failed to create the mdbg sysfs attributes\n");
		sysfs_remove_group(&pdev->dev.kobj,
				&intel_mcu_tty_attribute_group);
		goto data_alloc_fail;
	}

	intel_psh_ipc_bind(PSH_RECV_CH0, raw_data_handler, mcu_table[0]);
	intel_psh_ipc_bind(PSH_RECV_CH1, raw_data_handler, mcu_table[1]);
	intel_psh_ipc_bind(PSH_RECV_CH2, cmd_handler, mcu_table[2]);

	pr_info("MCU detected and ready to used!\n");

	return 0;

data_alloc_fail:
	for (i = 0; i < INTEL_MCU_TTY_MINORS; i++)
		kfree(mcu_table[i]);
tty_reg_fail:
	put_tty_driver(intel_mcu_tty_driver);
	return ret;
}
コード例 #14
0
ファイル: u_serial.c プロジェクト: AdrianHuang/linux-3.8.13
/**
 * 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->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;

	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);

	/* 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) {
		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_port_register_device(&ports[i].port->port,
				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--) {
		tty_port_destroy(&ports[count].port->port);
		kfree(ports[count].port);
	}
	put_tty_driver(gs_tty_driver);
	gs_tty_driver = NULL;
	return status;
}
コード例 #15
0
static int __init cidatatty_init(void)
{
	int retval;
	int i;

	F_ENTER();

	/* allocate the tty driver */
	cidatatty_tty_driver = alloc_tty_driver(CIDATATTY_TTY_MINORS);
	if (!cidatatty_tty_driver)
		return -ENOMEM;

	/* initialize the tty driver */
	cidatatty_tty_driver->owner = THIS_MODULE;
	cidatatty_tty_driver->driver_name = "cidatatty_tty";
	cidatatty_tty_driver->name = "cidatatty";
	cidatatty_tty_driver->major = CIDATATTY_TTY_MAJOR;
	cidatatty_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	cidatatty_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	cidatatty_tty_driver->flags =
	    TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	cidatatty_tty_driver->init_termios = tty_std_termios;
	/* B115200 | CS8 | CREAD | HUPCL | CLOCAL; */
	cidatatty_tty_driver->init_termios.c_cflag =
	    B9600 | CS8 | CREAD | CLOCAL;
	cidatatty_tty_driver->init_termios.c_iflag = IGNBRK | IGNPAR;
	cidatatty_tty_driver->init_termios.c_oflag = 0;
	cidatatty_tty_driver->init_termios.c_lflag = 0;

	tty_set_operations(cidatatty_tty_driver, &serial_ops);

	for (i = 0; i < CIDATATTY_TTY_MINORS; i++) {
		mutex_init(&cidatatty_table[i].lock);
		cidatatty_port_alloc(i); /* need defence code */
	}

	/* register the tty driver */
	retval = tty_register_driver(cidatatty_tty_driver);
	if (retval) {
		printk(KERN_ERR "failed to register cidatatty tty driver");
		put_tty_driver(cidatatty_tty_driver);
		cidatatty_tty_driver = NULL;
		return retval;
	}

	/* register tty devices */
	for (i = 0; i < CIDATATTY_TTY_MINORS; ++i) {
		struct device *tty_dev;

		tty_dev = tty_port_register_device(
				&cidatatty_table[i].data_port->port,
				cidatatty_tty_driver,
				i,
				NULL);
		if (IS_ERR(tty_dev)) {
			struct cidatatty_port *cidatatty;
			pr_err("%s: failed to register tty for port %d, err %ld",
					__func__, i, PTR_ERR(tty_dev));
			retval = PTR_ERR(tty_dev);
			cidatatty = cidatatty_table[i].data_port;
			cidatatty_table[i].data_port = NULL;
			tty_port_destroy(&cidatatty->port);
			kfree(cidatatty);
		}
	}

	printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");
	cctdatadev_init_module();
	F_LEAVE();
	return retval;
}