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; }
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; }
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; }
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; }
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; }
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; }
/* 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; }
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; }
/* 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; }
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; }
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; }
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; }
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; }
/** * 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; }
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; }