diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2002-03-17 18:47:47 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-03-17 18:47:47 -0800 |
| commit | 5326862d17d4ff78c79fbe72df50b16f37812782 (patch) | |
| tree | c2ae5e215c153e486c0da99f4242f0863c2dd606 | |
| parent | a2f1b7bc189cb5fc32a76dfe89d160849a1b600a (diff) | |
| parent | cfc632c815d9fab4c0f9f22487bbb6da38da6d3a (diff) | |
Automerge
44 files changed, 1310 insertions, 751 deletions
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index 0f8dbd1cb585..ed023aace203 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -28,7 +28,7 @@ struct aligninfo { #define OPCD(inst) (((inst) & 0xFC000000) >> 26) #define RS(inst) (((inst) & 0x03E00000) >> 21) #define RA(inst) (((inst) & 0x001F0000) >> 16) -#define IS_DFORM(code) ((code) >= 32 && (code) <= 47) +#define IS_DFORM(code) ((code) >= 32 && (code) <= 55) #endif #define INVALID { 0, 0 } diff --git a/arch/ppc/kernel/prom_init.c b/arch/ppc/kernel/prom_init.c index fea41427aa29..96f43675dae8 100644 --- a/arch/ppc/kernel/prom_init.c +++ b/arch/ppc/kernel/prom_init.c @@ -50,7 +50,7 @@ #define FB_MAX 8 #endif -#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) +#define ALIGNUL(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) struct prom_args { const char *service; @@ -376,7 +376,7 @@ try_again: } } - return ALIGN(mem); + return ALIGNUL(mem); } /* This function will enable the early boot text when doing OF booting. This @@ -457,7 +457,7 @@ copy_device_tree(unsigned long mem_start, unsigned long mem_end) prom_exit(); } allnextp = &allnodes; - mem_start = ALIGN(mem_start); + mem_start = ALIGNUL(mem_start); new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); *allnextp = 0; return new_start; @@ -501,7 +501,7 @@ inspect_node(phandle node, struct device_node *dad, if ((int) call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) break; - mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); + mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1); prev_name = namep; valp = (unsigned char *) mem_start; pp->value = PTRUNRELOC(valp); @@ -514,7 +514,7 @@ inspect_node(phandle node, struct device_node *dad, if (pp->length > MAX_PROPERTY_LENGTH) continue; /* ignore this property */ #endif - mem_start = ALIGN(mem_start + pp->length); + mem_start = ALIGNUL(mem_start + pp->length); *prev_propp = PTRUNRELOC(pp); prev_propp = &pp->next; } @@ -526,7 +526,7 @@ inspect_node(phandle node, struct device_node *dad, namep = (char *) (pp + 1); pp->name = PTRUNRELOC(namep); strcpy(namep, "linux,phandle"); - mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); + mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1); pp->value = (unsigned char *) PTRUNRELOC(&np->node); pp->length = sizeof(np->node); } @@ -538,7 +538,7 @@ inspect_node(phandle node, struct device_node *dad, if (l >= 0) { np->full_name = PTRUNRELOC((char *) mem_start); *(char *)(mem_start + l) = 0; - mem_start = ALIGN(mem_start + l + 1); + mem_start = ALIGNUL(mem_start + l + 1); } /* do all our children */ @@ -741,7 +741,7 @@ prom_init(int r3, int r4, prom_entry pp) *d = 0; call_prom("canon", 3, 1, p, d, 1<<20); bootdevice = PTRUNRELOC(d); - mem = ALIGN(mem + strlen(d) + 1); + mem = ALIGNUL(mem + strlen(d) + 1); } prom_instantiate_rtas(); diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c index 3a930be3e77d..ee134a1b84cf 100644 --- a/arch/ppc/platforms/pmac_feature.c +++ b/arch/ppc/platforms/pmac_feature.c @@ -400,13 +400,17 @@ heathrow_modem_enable(struct device_node* node, int param, int value) LOCK(flags); MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1); (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); + UNLOCK(flags); + mdelay(250); + LOCK(flags); MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio); (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); + UNLOCK(flags); + mdelay(250); + LOCK(flags); MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1); (void)MACIO_IN8(HRW_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); + UNLOCK(flags); } return 0; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 890ca713c999..a8fa051737f8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1710,7 +1710,6 @@ struct pci_pool { /* the pool */ spinlock_t lock; size_t blocks_per_page; size_t size; - int flags; struct pci_dev *dev; size_t allocation; char name [32]; @@ -1727,8 +1726,6 @@ struct pci_page { /* cacheable header for 'allocation' bytes */ #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) #define POOL_POISON_BYTE 0xa7 -// #define CONFIG_PCIPOOL_DEBUG - /** * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma. @@ -1737,7 +1734,7 @@ struct pci_page { /* cacheable header for 'allocation' bytes */ * @size: size of the blocks in this pool. * @align: alignment requirement for blocks; must be a power of two * @allocation: returned blocks won't cross this boundary (or zero) - * @flags: SLAB_* flags (not all are supported). + * @mem_flags: SLAB_* flags. * * Returns a pci allocation pool with the requested characteristics, or * null if one can't be created. Given one of these pools, pci_pool_alloc() @@ -1753,7 +1750,7 @@ struct pci_page { /* cacheable header for 'allocation' bytes */ */ struct pci_pool * pci_pool_create (const char *name, struct pci_dev *pdev, - size_t size, size_t align, size_t allocation, int flags) + size_t size, size_t align, size_t allocation, int mem_flags) { struct pci_pool *retval; @@ -1777,13 +1774,9 @@ pci_pool_create (const char *name, struct pci_dev *pdev, } else if (allocation < size) return 0; - if (!(retval = kmalloc (sizeof *retval, flags))) + if (!(retval = kmalloc (sizeof *retval, mem_flags))) return retval; -#ifdef CONFIG_PCIPOOL_DEBUG - flags |= SLAB_POISON; -#endif - strncpy (retval->name, name, sizeof retval->name); retval->name [sizeof retval->name - 1] = 0; @@ -1791,17 +1784,10 @@ pci_pool_create (const char *name, struct pci_dev *pdev, INIT_LIST_HEAD (&retval->page_list); spin_lock_init (&retval->lock); retval->size = size; - retval->flags = flags; retval->allocation = allocation; retval->blocks_per_page = allocation / size; init_waitqueue_head (&retval->waitq); -#ifdef CONFIG_PCIPOOL_DEBUG - printk (KERN_DEBUG "pcipool create %s/%s size %d, %d/page (%d alloc)\n", - pdev ? pdev->slot_name : NULL, retval->name, size, - retval->blocks_per_page, allocation); -#endif - return retval; } @@ -1824,8 +1810,9 @@ pool_alloc_page (struct pci_pool *pool, int mem_flags) &page->dma); if (page->vaddr) { memset (page->bitmap, 0xff, mapsize); // bit set == free - if (pool->flags & SLAB_POISON) - memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#ifdef CONFIG_DEBUG_SLAB + memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#endif list_add (&page->page_list, &pool->page_list); } else { kfree (page); @@ -1851,8 +1838,9 @@ pool_free_page (struct pci_pool *pool, struct pci_page *page) { dma_addr_t dma = page->dma; - if (pool->flags & SLAB_POISON) - memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#ifdef CONFIG_DEBUG_SLAB + memset (page->vaddr, POOL_POISON_BYTE, pool->allocation); +#endif pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma); list_del (&page->page_list); kfree (page); @@ -1871,12 +1859,6 @@ pci_pool_destroy (struct pci_pool *pool) { unsigned long flags; -#ifdef CONFIG_PCIPOOL_DEBUG - printk (KERN_DEBUG "pcipool destroy %s/%s\n", - pool->dev ? pool->dev->slot_name : NULL, - pool->name); -#endif - spin_lock_irqsave (&pool->lock, flags); while (!list_empty (&pool->page_list)) { struct pci_page *page; @@ -2010,30 +1992,27 @@ pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma) pool->name, vaddr, (unsigned long) dma); return; } -#ifdef CONFIG_PCIPOOL_DEBUG - if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { - printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n", - pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (unsigned long) dma); - return; - } -#endif block = dma - page->dma; block /= pool->size; map = block / BITS_PER_LONG; block %= BITS_PER_LONG; -#ifdef CONFIG_PCIPOOL_DEBUG +#ifdef CONFIG_DEBUG_SLAB + if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { + printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n", + pool->dev ? pool->dev->slot_name : NULL, + pool->name, vaddr, (unsigned long) dma); + return; + } if (page->bitmap [map] & (1UL << block)) { printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n", pool->dev ? pool->dev->slot_name : NULL, pool->name, dma); return; } + memset (vaddr, POOL_POISON_BYTE, pool->size); #endif - if (pool->flags & SLAB_POISON) - memset (vaddr, POOL_POISON_BYTE, pool->size); spin_lock_irqsave (&pool->lock, flags); set_bit (block, &page->bitmap [map]); diff --git a/drivers/usb/Config.help b/drivers/usb/Config.help index f76202f07b7a..28a88d96a72c 100644 --- a/drivers/usb/Config.help +++ b/drivers/usb/Config.help @@ -382,6 +382,7 @@ CONFIG_USB_KAWETH CONFIG_USB_CATC Say Y if you want to use one of the following 10Mbps USB Ethernet device based on the EL1210A chip. Supported devices are: + Belkin F5U011 Belkin F5U111 CATC NetMate CATC NetMate II diff --git a/drivers/usb/catc.c b/drivers/usb/catc.c index 3bea97a3c04e..37a300d9e2d0 100644 --- a/drivers/usb/catc.c +++ b/drivers/usb/catc.c @@ -7,6 +7,9 @@ * * Based on the work of * Donald Becker + * + * Old chipset support added by Simon Evans <spse@secret.org.uk> 2002 + * - adds support for Belkin F5U011 */ /* @@ -70,6 +73,7 @@ MODULE_LICENSE("GPL"); #define RX_MAX_BURST 15 /* Max packets per rx buffer (> 0, < 16) */ #define TX_MAX_BURST 15 /* Max full sized packets per tx buffer (> 0) */ #define CTRL_QUEUE 16 /* Max control requests in flight (power of two) */ +#define RX_PKT_SZ 1600 /* Max size of receive packet for F5U011 */ /* * Control requests. @@ -80,6 +84,7 @@ enum control_requests { GetMac = 0xf2, Reset = 0xf4, SetMac = 0xf5, + SetRxMode = 0xf5, /* F5U011 only */ WriteROM = 0xf8, SetReg = 0xfa, GetReg = 0xfb, @@ -127,6 +132,7 @@ enum rx_filter_bits { RxForceOK = 0x04, RxMultiCast = 0x08, RxPromisc = 0x10, + AltRxPromisc = 0x20, /* F5U011 uses different bit */ }; enum led_values { @@ -137,6 +143,12 @@ enum led_values { LEDLink = 0x08, }; +enum link_status { + LinkNoChange = 0, + LinkGood = 1, + LinkBad = 2 +}; + /* * The catc struct. */ @@ -180,6 +192,10 @@ struct catc { } ctrl_queue[CTRL_QUEUE]; struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb; + + u8 is_f5u011; /* Set if device is an F5U011 */ + u8 rxmode[2]; /* Used for F5U011 */ + atomic_t recq_sz; /* Used for F5U011 - counter of waiting rx packets */ }; /* @@ -193,6 +209,10 @@ struct catc { #define catc_write_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size) #define catc_read_mem(catc, addr, buf, size) catc_ctrl_msg(catc, USB_DIR_IN, ReadMem, 0, addr, buf, size) +#define f5u011_rxmode(catc, rxmode) catc_ctrl_msg(catc, USB_DIR_OUT, SetRxMode, 0, 1, rxmode, 2) +#define f5u011_rxmode_async(catc, rxmode) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 1, &rxmode, 2, NULL) +#define f5u011_mchash_async(catc, hash) catc_ctrl_async(catc, USB_DIR_OUT, SetRxMode, 0, 2, &hash, 8, NULL) + #define catc_set_reg_async(catc, reg, val) catc_ctrl_async(catc, USB_DIR_OUT, SetReg, val, reg, NULL, 0, NULL) #define catc_get_reg_async(catc, reg, cb) catc_ctrl_async(catc, USB_DIR_IN, GetReg, 0, reg, NULL, 1, cb) #define catc_write_mem_async(catc, addr, buf, size) catc_ctrl_async(catc, USB_DIR_OUT, WriteMem, 0, addr, buf, size, NULL) @@ -206,9 +226,12 @@ static void catc_rx_done(struct urb *urb) struct catc *catc = urb->context; u8 *pkt_start = urb->transfer_buffer; struct sk_buff *skb; - int pkt_len; + int pkt_len, pkt_offset = 0; - clear_bit(RX_RUNNING, &catc->flags); + if (!catc->is_f5u011) { + clear_bit(RX_RUNNING, &catc->flags); + pkt_offset = 2; + } if (urb->status) { dbg("rx_done, status %d, length %d", urb->status, urb->actual_length); @@ -216,19 +239,22 @@ static void catc_rx_done(struct urb *urb) } do { - pkt_len = le16_to_cpup((u16*)pkt_start); - - if (pkt_len > urb->actual_length) { - catc->stats.rx_length_errors++; - catc->stats.rx_errors++; - break; + if(!catc->is_f5u011) { + pkt_len = le16_to_cpup((u16*)pkt_start); + if (pkt_len > urb->actual_length) { + catc->stats.rx_length_errors++; + catc->stats.rx_errors++; + break; + } + } else { + pkt_len = urb->actual_length; } if (!(skb = dev_alloc_skb(pkt_len))) return; skb->dev = catc->netdev; - eth_copy_and_sum(skb, pkt_start + 2, pkt_len, 0); + eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, catc->netdev); @@ -237,11 +263,28 @@ static void catc_rx_done(struct urb *urb) catc->stats.rx_packets++; catc->stats.rx_bytes += pkt_len; + /* F5U011 only does one packet per RX */ + if (catc->is_f5u011) + break; pkt_start += (((pkt_len + 1) >> 6) + 1) << 6; } while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length); catc->netdev->last_rx = jiffies; + + if (catc->is_f5u011) { + if (atomic_read(&catc->recq_sz)) { + int status; + atomic_dec(&catc->recq_sz); + dbg("getting extra packet"); + urb->dev = catc->usbdev; + if ((status = usb_submit_urb(urb, GFP_KERNEL)) < 0) { + dbg("submit(rx_urb) status %d", status); + } + } else { + clear_bit(RX_RUNNING, &catc->flags); + } + } } static void catc_irq_done(struct urb *urb) @@ -249,29 +292,48 @@ static void catc_irq_done(struct urb *urb) struct catc *catc = urb->context; u8 *data = urb->transfer_buffer; int status; + unsigned int hasdata = 0, linksts = LinkNoChange; + + if (!catc->is_f5u011) { + hasdata = data[1] & 0x80; + if (data[1] & 0x40) + linksts = LinkGood; + else if (data[1] & 0x20) + linksts = LinkBad; + } else { + hasdata = (unsigned int)(be16_to_cpup((u16*)data) & 0x0fff); + if (data[0] == 0x90) + linksts = LinkGood; + else if (data[0] == 0xA0) + linksts = LinkBad; + } if (urb->status) { dbg("irq_done, status %d, data %02x %02x.", urb->status, data[0], data[1]); return; } - if ((data[1] & 0x80) && !test_and_set_bit(RX_RUNNING, &catc->flags)) { - catc->rx_urb->dev = catc->usbdev; - if ((status = usb_submit_urb(catc->rx_urb, GFP_KERNEL)) < 0) { - err("submit(rx_urb) status %d", status); - return; - } - } - - if (data[1] & 0x40) { + if (linksts == LinkGood) { netif_carrier_on(catc->netdev); dbg("link ok"); } - if (data[1] & 0x20) { + if (linksts == LinkBad) { netif_carrier_off(catc->netdev); dbg("link bad"); } + + if (hasdata) { + if (test_and_set_bit(RX_RUNNING, &catc->flags)) { + if (catc->is_f5u011) + atomic_inc(&catc->recq_sz); + } else { + catc->rx_urb->dev = catc->usbdev; + if ((status = usb_submit_urb(catc->rx_urb, GFP_KERNEL)) < 0) { + err("submit(rx_urb) status %d", status); + } + } + } } /* @@ -282,6 +344,9 @@ static void catc_tx_run(struct catc *catc) { int status; + if (catc->is_f5u011) + catc->tx_ptr = (catc->tx_ptr + 63) & ~63; + catc->tx_urb->transfer_buffer_length = catc->tx_ptr; catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx]; catc->tx_urb->dev = catc->usbdev; @@ -338,14 +403,15 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6; tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr; - *((u16*)tx_buf) = cpu_to_le16((u16)skb->len); + *((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len); memcpy(tx_buf + 2, skb->data, skb->len); catc->tx_ptr += skb->len + 2; if (!test_and_set_bit(TX_RUNNING, &catc->flags)) catc_tx_run(catc); - if (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2))) + if ((catc->is_f5u011 && catc->tx_ptr) + || (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))) netif_stop_queue(netdev); spin_unlock_irqrestore(&catc->tx_lock, flags); @@ -554,17 +620,32 @@ static void catc_set_multicast_list(struct net_device *netdev) if (netdev->flags & IFF_PROMISC) { memset(catc->multicast, 0xff, 64); - rx |= RxPromisc; + rx |= (!catc->is_f5u011) ? RxPromisc : AltRxPromisc; } - if (netdev->flags & IFF_ALLMULTI) + if (netdev->flags & IFF_ALLMULTI) { memset(catc->multicast, 0xff, 64); - - for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) - catc_multicast(mc->dmi_addr, catc->multicast); - - catc_set_reg_async(catc, RxUnit, rx); - catc_write_mem_async(catc, 0xfa80, catc->multicast, 64); + } else { + for (i = 0, mc = netdev->mc_list; mc && i < netdev->mc_count; i++, mc = mc->next) { + u32 crc = ether_crc_le(6, mc->dmi_addr); + if (!catc->is_f5u011) { + catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7); + } else { + catc->multicast[7-(crc >> 29)] |= 1 << ((crc >> 26) & 7); + } + } + } + if (!catc->is_f5u011) { + catc_set_reg_async(catc, RxUnit, rx); + catc_write_mem_async(catc, 0xfa80, catc->multicast, 64); + } else { + f5u011_mchash_async(catc, catc->multicast); + if (catc->rxmode[0] != rx) { + catc->rxmode[0] = rx; + dbg("Setting RX mode to %2.2X %2.2X", catc->rxmode[0], catc->rxmode[1]); + f5u011_rxmode_async(catc, catc->rxmode); + } + } } /* @@ -591,6 +672,29 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) return -EFAULT; return 0; } + + /* get settings */ + case ETHTOOL_GSET: + if (catc->is_f5u011) { + struct ethtool_cmd ecmd = { ETHTOOL_GSET, + SUPPORTED_10baseT_Half | SUPPORTED_TP, + ADVERTISED_10baseT_Half | ADVERTISED_TP, + SPEED_10, + DUPLEX_HALF, + PORT_TP, + 0, + XCVR_INTERNAL, + AUTONEG_DISABLE, + 1, + 1 + }; + if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } else { + return -EOPNOTSUPP; + } + /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; @@ -632,7 +736,8 @@ static int catc_open(struct net_device *netdev) netif_start_queue(netdev); - mod_timer(&catc->timer, jiffies + STATS_UPDATE); + if (!catc->is_f5u011) + mod_timer(&catc->timer, jiffies + STATS_UPDATE); return 0; } @@ -643,7 +748,8 @@ static int catc_stop(struct net_device *netdev) netif_stop_queue(netdev); - del_timer_sync(&catc->timer); + if (!catc->is_f5u011) + del_timer_sync(&catc->timer); usb_unlink_urb(catc->rx_urb); usb_unlink_urb(catc->tx_urb); @@ -662,7 +768,7 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str struct net_device *netdev; struct catc *catc; u8 broadcast[6]; - int i; + int i, pktsz; if (usb_set_interface(usbdev, ifnum, 1)) { err("Can't set altsetting 1."); @@ -670,9 +776,16 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str } catc = kmalloc(sizeof(struct catc), GFP_KERNEL); + if (!catc) + return NULL; + memset(catc, 0, sizeof(struct catc)); netdev = init_etherdev(0, 0); + if (!netdev) { + kfree(catc); + return NULL; + } netdev->open = catc_open; netdev->hard_start_xmit = catc_hard_start_xmit; @@ -701,9 +814,26 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str if ((!catc->ctrl_urb) || (!catc->tx_urb) || (!catc->rx_urb) || (!catc->irq_urb)) { err("No free urbs available."); + if (catc->ctrl_urb) usb_free_urb(catc->ctrl_urb); + if (catc->tx_urb) usb_free_urb(catc->tx_urb); + if (catc->rx_urb) usb_free_urb(catc->rx_urb); + if (catc->irq_urb) usb_free_urb(catc->irq_urb); + kfree(netdev); + kfree(catc); return NULL; } + /* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */ + if (usbdev->descriptor.idVendor == 0x0423 && usbdev->descriptor.idProduct == 0xa && + catc->usbdev->descriptor.bcdDevice == 0x0130 ) { + dbg("Testing for f5u011"); + catc->is_f5u011 = 1; + atomic_set(&catc->recq_sz, 0); + pktsz = RX_PKT_SZ; + } else { + pktsz = RX_MAX_BURST * (PKT_SZ + 2); + } + FILL_CONTROL_URB(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0), NULL, NULL, 0, catc_ctrl_done, catc); @@ -711,20 +841,21 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str NULL, 0, catc_tx_done, catc); FILL_BULK_URB(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1), - catc->rx_buf, RX_MAX_BURST * (PKT_SZ + 2), catc_rx_done, catc); + catc->rx_buf, pktsz, catc_rx_done, catc); FILL_INT_URB(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2), catc->irq_buf, 2, catc_irq_done, catc, 1); - dbg("Checking memory size\n"); - - i = 0x12345678; - catc_write_mem(catc, 0x7a80, &i, 4); - i = 0x87654321; - catc_write_mem(catc, 0xfa80, &i, 4); - catc_read_mem(catc, 0x7a80, &i, 4); + if (!catc->is_f5u011) { + dbg("Checking memory size\n"); - switch (i) { + i = 0x12345678; + catc_write_mem(catc, 0x7a80, &i, 4); + i = 0x87654321; + catc_write_mem(catc, 0xfa80, &i, 4); + catc_read_mem(catc, 0x7a80, &i, 4); + + switch (i) { case 0x12345678: catc_set_reg(catc, TxBufCount, 8); catc_set_reg(catc, RxBufCount, 32); @@ -737,44 +868,52 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str catc_set_reg(catc, RxBufCount, 16); dbg("32k Memory\n"); break; + } + + dbg("Getting MAC from SEEROM."); + + catc_get_mac(catc, netdev->dev_addr); + + dbg("Setting MAC into registers."); + + for (i = 0; i < 6; i++) + catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]); + + dbg("Filling the multicast list."); + + memset(broadcast, 0xff, 6); + catc_multicast(broadcast, catc->multicast); + catc_multicast(netdev->dev_addr, catc->multicast); + catc_write_mem(catc, 0xfa80, catc->multicast, 64); + + dbg("Clearing error counters."); + + for (i = 0; i < 8; i++) + catc_set_reg(catc, EthStats + i, 0); + catc->last_stats = jiffies; + + dbg("Enabling."); + + catc_set_reg(catc, MaxBurst, RX_MAX_BURST); + catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits); + catc_set_reg(catc, LEDCtrl, LEDLink); + catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast); + } else { + dbg("Performing reset\n"); + catc_reset(catc); + catc_get_mac(catc, netdev->dev_addr); + + dbg("Setting RX Mode"); + catc->rxmode[0] = RxEnable | RxPolarity | RxMultiCast; + catc->rxmode[1] = 0; + f5u011_rxmode(catc, catc->rxmode); } - - dbg("Getting MAC from SEEROM."); - - catc_get_mac(catc, netdev->dev_addr); - - dbg("Setting MAC into registers."); - - for (i = 0; i < 6; i++) - catc_set_reg(catc, StationAddr0 - i, netdev->dev_addr[i]); - - dbg("Filling the multicast list."); - - memset(broadcast, 0xff, 8); - catc_multicast(broadcast, catc->multicast); - catc_multicast(netdev->dev_addr, catc->multicast); - catc_write_mem(catc, 0xfa80, catc->multicast, 64); - - dbg("Clearing error counters."); - - for (i = 0; i < 8; i++) - catc_set_reg(catc, EthStats + i, 0); - catc->last_stats = jiffies; - - dbg("Enabling."); - - catc_set_reg(catc, MaxBurst, RX_MAX_BURST); - catc_set_reg(catc, OpModes, OpTxMerge | OpRxMerge | OpLenInclude | Op3MemWaits); - catc_set_reg(catc, LEDCtrl, LEDLink); - catc_set_reg(catc, RxUnit, RxEnable | RxPolarity | RxMultiCast); - dbg("Init done."); - - printk(KERN_INFO "%s: CATC EL1210A NetMate USB Ethernet at usb%d:%d.%d, ", - netdev->name, usbdev->bus->busnum, usbdev->devnum, ifnum); + printk(KERN_INFO "%s: %s USB Ethernet at usb%d:%d.%d, ", + netdev->name, (catc->is_f5u011) ? "Belkin F5U011" : "CATC EL1210A NetMate", + usbdev->bus->busnum, usbdev->devnum, ifnum); for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]); printk("%2.2x.\n", netdev->dev_addr[i]); - return catc; } @@ -795,7 +934,7 @@ static void catc_disconnect(struct usb_device *usbdev, void *dev_ptr) */ static struct usb_device_id catc_id_table [] = { - { USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate */ + { USB_DEVICE(0x0423, 0xa) }, /* CATC Netmate, Belkin F5U011 */ { USB_DEVICE(0x0423, 0xc) }, /* CATC Netmate II, Belkin F5U111 */ { USB_DEVICE(0x08d1, 0x1) }, /* smartBridges smartNIC */ { } diff --git a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c index 5b3f0c64273e..0bb17425bc39 100644 --- a/drivers/usb/hid-core.c +++ b/drivers/usb/hid-core.c @@ -110,10 +110,11 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + values * sizeof(unsigned)); - report->field[report->maxfield++] = field; + report->field[report->maxfield] = field; field->usage = (struct hid_usage *)(field + 1); field->value = (unsigned *)(field->usage + usages); field->report = report; + field->index = report->maxfield++; return field; } @@ -741,8 +742,20 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s if (hid->claimed & HID_CLAIMED_INPUT) hidinput_hid_event(hid, field, usage, value); #ifdef CONFIG_USB_HIDDEV - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_hid_event(hid, usage->hid, value); + if (hid->claimed & HID_CLAIMED_HIDDEV) { + struct hiddev_usage_ref uref; + unsigned type = field->report_type; + uref.report_type = + (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + uref.report_id = field->report->id; + uref.field_index = field->index; + uref.usage_index = (usage - field->usage); + uref.usage_code = usage->hid; + uref.value = value; + hiddev_hid_event(hid, &uref); + } #endif } @@ -839,6 +852,21 @@ static int hid_input_report(int type, struct urb *urb) return -1; } +#ifdef CONFIG_USB_HIDDEV + /* Notify listeners that a report has been received */ + if (hid->claimed & HID_CLAIMED_HIDDEV) { + struct hiddev_usage_ref uref; + memset(&uref, 0, sizeof(uref)); + uref.report_type = + (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); + uref.report_id = report->id; + uref.field_index = HID_FIELD_INDEX_NONE; + hiddev_hid_event(hid, &uref); + } +#endif + size = ((report->size - 1) >> 3) + 1; if (len < size) { @@ -1096,6 +1124,9 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign int head; unsigned long flags; + if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) + return; + if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { spin_lock_irqsave(&hid->outlock, flags); @@ -1238,18 +1269,27 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_POWERMATE 0x0410 #define USB_DEVICE_ID_SOUNDKNOB 0x04AA +#define USB_VENDOR_ID_ATEN 0x0557 +#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 +#define USB_DEVICE_ID_ATEN_CS124U 0x2202 +#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 + struct hid_blacklist { __u16 idVendor; __u16 idProduct; + unsigned quirks; } hid_blacklist[] = { - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1}, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2}, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3}, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4}, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE }, - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { 0, 0 } }; @@ -1258,13 +1298,17 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; struct hid_descriptor *hdesc; struct hid_device *hid; - unsigned rsize = 0; + unsigned quirks = 0, rsize = 0; char *buf; int n; for (n = 0; hid_blacklist[n].idVendor; n++) if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) && - (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL; + (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) + quirks = hid_blacklist[n].quirks; + + if (quirks & HID_QUIRK_IGNORE) + return NULL; if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && ((!interface->bNumEndpoints) || usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { @@ -1302,6 +1346,8 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum) } } + hid->quirks = quirks; + for (n = 0; n < interface->bNumEndpoints; n++) { struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h index 77a656f2bcc9..ed72dc6acfd1 100644 --- a/drivers/usb/hid.h +++ b/drivers/usb/hid.h @@ -203,6 +203,8 @@ struct hid_item { #define HID_QUIRK_INVERT 0x01 #define HID_QUIRK_NOTOUCH 0x02 +#define HID_QUIRK_IGNORE 0x04 +#define HID_QUIRK_NOGET 0x08 /* * This is the global enviroment of the parser. This information is @@ -276,6 +278,7 @@ struct hid_field { __s32 unit_exponent; unsigned unit; struct hid_report *report; /* associated report */ + unsigned index; /* index into report->field[] */ }; #define HID_MAX_FIELDS 64 diff --git a/drivers/usb/hiddev.c b/drivers/usb/hiddev.c index 886a30825a92..5d4029259899 100644 --- a/drivers/usb/hiddev.c +++ b/drivers/usb/hiddev.c @@ -50,9 +50,10 @@ struct hiddev { }; struct hiddev_list { - struct hiddev_event buffer[HIDDEV_BUFFER_SIZE]; + struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE]; int head; int tail; + unsigned flags; struct fasync_struct *fasync; struct hiddev *hiddev; struct hiddev_list *next; @@ -146,17 +147,19 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) * This is where hid.c calls into hiddev to pass an event that occurred over * the interrupt pipe */ -void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value) +void hiddev_hid_event(struct hid_device *hid, struct hiddev_usage_ref *uref) { struct hiddev *hiddev = hid->hiddev; struct hiddev_list *list = hiddev->list; while (list) { - list->buffer[list->head].hid = usage; - list->buffer[list->head].value = value; - list->head = (list->head + 1) & (HIDDEV_BUFFER_SIZE - 1); - - kill_fasync(&list->fasync, SIGIO, POLL_IN); + if (uref->field_index != HID_FIELD_INDEX_NONE || + (list->flags & HIDDEV_FLAG_REPORT) != 0) { + list->buffer[list->head] = *uref; + list->head = (list->head + 1) & + (HIDDEV_BUFFER_SIZE - 1); + kill_fasync(&list->fasync, SIGIO, POLL_IN); + } list = list->next; } @@ -257,43 +260,67 @@ static ssize_t hiddev_read(struct file * file, char * buffer, size_t count, { DECLARE_WAITQUEUE(wait, current); struct hiddev_list *list = file->private_data; + int event_size; int retval = 0; - if (list->head == list->tail) { - - add_wait_queue(&list->hiddev->wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); + event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ? + sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event); - while (list->head == list->tail) { + if (count < event_size) return 0; - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - if (!list->hiddev->exist) { - retval = -EIO; - break; + while (retval == 0) { + if (list->head == list->tail) { + add_wait_queue(&list->hiddev->wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (list->head == list->tail) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + if (!list->hiddev->exist) { + retval = -EIO; + break; + } + + schedule(); } - schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&list->hiddev->wait, &wait); } - set_current_state(TASK_RUNNING); - remove_wait_queue(&list->hiddev->wait, &wait); - } - - if (retval) - return retval; + if (retval) + return retval; + + + while (list->head != list->tail && + retval + event_size <= count) { + if ((list->flags & HIDDEV_FLAG_UREF) == 0) { + if (list->buffer[list->tail].field_index != + HID_FIELD_INDEX_NONE) { + struct hiddev_event event; + event.hid = list->buffer[list->tail].usage_code; + event.value = list->buffer[list->tail].value; + if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) + return -EFAULT; + retval += sizeof(struct hiddev_event); + } + } else { + if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE || + (list->flags & HIDDEV_FLAG_REPORT) != 0) { + if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) + return -EFAULT; + retval += sizeof(struct hiddev_usage_ref); + } + } + list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); + } - while (list->head != list->tail && retval + sizeof(struct hiddev_event) <= count) { - if (copy_to_user(buffer + retval, list->buffer + list->tail, - sizeof(struct hiddev_event))) return -EFAULT; - list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); - retval += sizeof(struct hiddev_event); } return retval; @@ -358,6 +385,25 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, return copy_to_user((void *) arg, &dinfo, sizeof(dinfo)); } + case HIDIOCGFLAG: + return put_user(list->flags, (int *) arg); + + case HIDIOCSFLAG: + { + int newflags; + if (get_user(newflags, (int *) arg)) + return -EFAULT; + + if ((newflags & ~HIDDEV_FLAGS) != 0 || + ((newflags & HIDDEV_FLAG_REPORT) != 0 && + (newflags & HIDDEV_FLAG_UREF) == 0)) + return -EINVAL; + + list->flags = newflags; + + return 0; + } + case HIDIOCGSTRING: { int idx, len; diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 6025a0176103..00ea80dfca00 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -1,10 +1,12 @@ /* - * printer.c Version 0.8 + * printer.c Version 0.12 * * Copyright (c) 1999 Michael Gee <michael@linuxspecific.com> * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> * Copyright (c) 2000 Randy Dunlap <randy.dunlap@intel.com> * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz> + # Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com> + # Copyright (c) 2001 David Paschal <paschal@rcsis.com> * * USB Printer Device Class driver for USB printers and printer cables * @@ -17,10 +19,12 @@ * v0.4 - fixes in unidirectional mode * v0.5 - add DEVICE_ID string support * v0.6 - never time out - * v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com) + * v0.7 - fixed bulk-IN read and poll (David Paschal) * v0.8 - add devfs support * v0.9 - fix unplug-while-open paths * v0.10- remove sleep_on, fix error on oom (oliver@neukum.org) + * v0.11 - add proto_bias option (Pete Zaitcev) + * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) */ /* @@ -55,16 +59,36 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.10" -#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap" +#define DRIVER_VERSION "v0.12" +#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal" #define DRIVER_DESC "USB Printer Device Class driver" #define USBLP_BUF_SIZE 8192 #define DEVICE_ID_SIZE 1024 -#define IOCNR_GET_DEVICE_ID 1 -#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) /* get device_id string */ +/* ioctls: */ #define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */ +#define IOCNR_GET_DEVICE_ID 1 +#define IOCNR_GET_PROTOCOLS 2 +#define IOCNR_SET_PROTOCOL 3 +#define IOCNR_HP_SET_CHANNEL 4 +#define IOCNR_GET_BUS_ADDRESS 5 +#define IOCNR_GET_VID_PID 6 +/* Get device_id string: */ +#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) +/* The following ioctls were added for http://hpoj.sourceforge.net: */ +/* Get two-int array: + * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), + * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */ +#define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len) +/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */ +#define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0) +/* Set channel number (HP Vendor-specific command): */ +#define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0) +/* Get two-int array: [0]=bus number, [1]=device address: */ +#define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len) +/* Get two-int array: [0]=vendor ID, [1]=product ID: */ +#define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len) /* * A DEVICE_ID string may include the printer's serial number. @@ -78,26 +102,40 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H * USB Printer Requests */ -#define USBLP_REQ_GET_ID 0x00 -#define USBLP_REQ_GET_STATUS 0x01 -#define USBLP_REQ_RESET 0x02 +#define USBLP_REQ_GET_ID 0x00 +#define USBLP_REQ_GET_STATUS 0x01 +#define USBLP_REQ_RESET 0x02 +#define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST 0x00 /* HP Vendor-specific */ #define USBLP_MINORS 16 #define USBLP_MINOR_BASE 0 #define USBLP_WRITE_TIMEOUT (5*HZ) /* 5 seconds */ +#define USBLP_FIRST_PROTOCOL 1 +#define USBLP_LAST_PROTOCOL 3 +#define USBLP_MAX_PROTOCOLS (USBLP_LAST_PROTOCOL+1) + struct usblp { struct usb_device *dev; /* USB device */ devfs_handle_t devfs; /* devfs device */ struct semaphore sem; /* locks this struct, especially "dev" */ + char *buf; /* writeurb->transfer_buffer */ struct urb *readurb, *writeurb; /* The urbs */ wait_queue_head_t wait; /* Zzzzz ... */ int readcount; /* Counter for reads */ int ifnum; /* Interface number */ + /* Alternate-setting numbers and endpoints for each protocol + * (7/1/{index=1,2,3}) that the device supports: */ + struct { + int alt_setting; + struct usb_endpoint_descriptor *epwrite; + struct usb_endpoint_descriptor *epread; + } protocol[USBLP_MAX_PROTOCOLS]; + int current_protocol; int minor; /* minor number of device */ int wcomplete; /* writing is completed */ - int rcomplete; /* reading is completed */ + int rcomplete; /* reading is completed */ unsigned int quirks; /* quirks flags */ unsigned char used; /* True if open */ unsigned char bidir; /* interface is bidirectional */ @@ -105,6 +143,35 @@ struct usblp { /* first 2 bytes are (big-endian) length */ }; +#ifdef DEBUG +static void usblp_dump(struct usblp *usblp) { + int p; + + dbg("usblp=0x%p", usblp); + dbg("dev=0x%p", usblp->dev); + dbg("devfs=0x%p", usblp->devfs); + dbg("buf=0x%p", usblp->buf); + dbg("readcount=%d", usblp->readcount); + dbg("ifnum=%d", usblp->ifnum); + for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { + dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting); + dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite); + dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread); + } + dbg("current_protocol=%d", usblp->current_protocol); + dbg("minor=%d", usblp->minor); + dbg("wcomplete=%d", usblp->wcomplete); + dbg("rcomplete=%d", usblp->rcomplete); + dbg("quirks=%d", usblp->quirks); + dbg("used=%d", usblp->used); + dbg("bidir=%d", usblp->bidir); + dbg("device_id_string=\"%s\"", + usblp->device_id_string ? + usblp->device_id_string + 2 : + (unsigned char *)"(null)"); +} +#endif + extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */ static struct usblp *usblp_table[USBLP_MINORS]; @@ -126,29 +193,45 @@ static struct quirk_printer_struct quirk_printers[] = { { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */ { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ + { 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */ { 0, 0 } }; +static int usblp_select_alts(struct usblp *usblp); +static int usblp_set_protocol(struct usblp *usblp, int protocol); +static int usblp_cache_device_id_string(struct usblp *usblp); + + /* * Functions for usblp control messages. */ -static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, int value, void *buf, int len) +static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len) { int retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, USB_TYPE_CLASS | dir | recip, value, usblp->ifnum, buf, len, HZ * 5); + request, type | dir | recip, value, usblp->ifnum, buf, len, USBLP_WRITE_TIMEOUT); dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d", request, !!dir, recip, value, len, retval); return retval < 0 ? retval : 0; } #define usblp_read_status(usblp, status)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) + usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) #define usblp_get_id(usblp, config, id, maxlen)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) + usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) #define usblp_reset(usblp)\ - usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) + usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) + +#define usblp_hp_channel_change_request(usblp, channel, buffer) \ + usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1) + +/* + * See the description for usblp_select_alts() below for the usage + * explanation. Look into your /proc/bus/usb/devices and dmesg in + * case of any trouble. + */ +static int proto_bias = -1; /* * URB callback. @@ -276,7 +359,7 @@ static void usblp_cleanup (struct usblp *usblp) { devfs_unregister (usblp->devfs); usblp_table [usblp->minor] = NULL; - info ("usblp%d: removed", usblp->minor); + info("usblp%d: removed", usblp->minor); kfree (usblp->writeurb->transfer_buffer); kfree (usblp->device_id_string); @@ -285,6 +368,13 @@ static void usblp_cleanup (struct usblp *usblp) kfree (usblp); } +static void usblp_unlink_urbs(struct usblp *usblp) +{ + usb_unlink_urb(usblp->writeurb); + if (usblp->bidir) + usb_unlink_urb(usblp->readurb); +} + static int usblp_release(struct inode *inode, struct file *file) { struct usblp *usblp = file->private_data; @@ -293,9 +383,7 @@ static int usblp_release(struct inode *inode, struct file *file) lock_kernel(); usblp->used = 0; if (usblp->dev) { - if (usblp->bidir) - usb_unlink_urb(usblp->readurb); - usb_unlink_urb(usblp->writeurb); + usblp_unlink_urbs(usblp); up(&usblp->sem); } else /* finish cleanup from disconnect */ usblp_cleanup (usblp); @@ -315,8 +403,9 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct usblp *usblp = file->private_data; - int length, err; - unsigned char status; + int length, err, i; + unsigned char status, newChannel; + int twoints[2]; int retval = 0; down (&usblp->sem); @@ -335,32 +424,128 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, goto done; } - err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); + length = usblp_cache_device_id_string(usblp); + if (length < 0) { + retval = length; + goto done; + } + if (length > _IOC_SIZE(cmd)) + length = _IOC_SIZE(cmd); /* truncate */ + + if (copy_to_user((unsigned char *) arg, + usblp->device_id_string, + (unsigned long) length)) { + retval = -EFAULT; + goto done; + } + + break; + + case IOCNR_GET_PROTOCOLS: + if (_IOC_DIR(cmd) != _IOC_READ || + _IOC_SIZE(cmd) < sizeof(twoints)) { + retval = -EINVAL; + goto done; + } + + twoints[0] = usblp->current_protocol; + twoints[1] = 0; + for (i = USBLP_FIRST_PROTOCOL; + i <= USBLP_LAST_PROTOCOL; i++) { + if (usblp->protocol[i].alt_setting >= 0) + twoints[1] |= (1<<i); + } + + if (copy_to_user((unsigned char *)arg, + (unsigned char *)twoints, + sizeof(twoints))) { + retval = -EFAULT; + goto done; + } + + break; + + case IOCNR_SET_PROTOCOL: + if (_IOC_DIR(cmd) != _IOC_WRITE) { + retval = -EINVAL; + goto done; + } + +#ifdef DEBUG + if (arg == -10) { + usblp_dump(usblp); + break; + } +#endif + + usblp_unlink_urbs(usblp); + retval = usblp_set_protocol(usblp, arg); + if (retval < 0) { + usblp_set_protocol(usblp, + usblp->current_protocol); + } + break; + + case IOCNR_HP_SET_CHANNEL: + if (_IOC_DIR(cmd) != _IOC_WRITE || + usblp->dev->descriptor.idVendor != 0x03F0 || + usblp->quirks & USBLP_QUIRK_BIDIR) { + retval = -EINVAL; + goto done; + } + + err = usblp_hp_channel_change_request(usblp, + arg, &newChannel); if (err < 0) { - dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string", + err("usblp%d: error = %d setting " + "HP channel", usblp->minor, err); - usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; retval = -EIO; goto done; } - length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ - if (length < DEVICE_ID_SIZE) - usblp->device_id_string[length] = '\0'; - else - usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0'; + dbg("usblp%d requested/got HP channel %ld/%d", + usblp->minor, arg, newChannel); + break; - dbg ("usblp%d Device ID string [%d/max %d]='%s'", - usblp->minor, length, _IOC_SIZE(cmd), &usblp->device_id_string[2]); + case IOCNR_GET_BUS_ADDRESS: + if (_IOC_DIR(cmd) != _IOC_READ || + _IOC_SIZE(cmd) < sizeof(twoints)) { + retval = -EINVAL; + goto done; + } - if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ + twoints[0] = usblp->dev->bus->busnum; + twoints[1] = usblp->dev->devnum; + if (copy_to_user((unsigned char *)arg, + (unsigned char *)twoints, + sizeof(twoints))) { + retval = -EFAULT; + goto done; + } - if (copy_to_user((unsigned char *) arg, - usblp->device_id_string, (unsigned long) length)) { + dbg("usblp%d is bus=%d, device=%d", + usblp->minor, twoints[0], twoints[1]); + break; + + case IOCNR_GET_VID_PID: + if (_IOC_DIR(cmd) != _IOC_READ || + _IOC_SIZE(cmd) < sizeof(twoints)) { + retval = -EINVAL; + goto done; + } + + twoints[0] = usblp->dev->descriptor.idVendor; + twoints[1] = usblp->dev->descriptor.idProduct; + if (copy_to_user((unsigned char *)arg, + (unsigned char *)twoints, + sizeof(twoints))) { retval = -EFAULT; goto done; } + dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X", + usblp->minor, twoints[0], twoints[1]); break; default: @@ -593,155 +778,268 @@ static struct file_operations usblp_fops = { static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *epread, *epwrite; - struct usblp *usblp; - int minor, i, bidir = 0, quirks; - int alts = dev->actconfig->interface[ifnum].act_altsetting; - int length, err; - char *buf; + struct usblp *usblp = 0; + int protocol; char name[6]; - /* If a bidirectional interface exists, use it. */ - for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) { - - interface = &dev->actconfig->interface[ifnum].altsetting[i]; - - if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 || - interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 || - (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2)) - continue; - - if (interface->bInterfaceProtocol > 1) { - bidir = 1; - alts = i; - break; - } - } - - interface = &dev->actconfig->interface[ifnum].altsetting[alts]; - if (usb_set_interface(dev, ifnum, alts)) - err("can't set desired altsetting %d on interface %d", alts, ifnum); - - epwrite = interface->endpoint + 0; - epread = bidir ? interface->endpoint + 1 : NULL; - - if ((epwrite->bEndpointAddress & 0x80) == 0x80) { - if (interface->bNumEndpoints == 1) - return NULL; - epwrite = interface->endpoint + 1; - epread = bidir ? interface->endpoint + 0 : NULL; - } - - if ((epwrite->bEndpointAddress & 0x80) == 0x80) - return NULL; - - if (bidir && (epread->bEndpointAddress & 0x80) != 0x80) - return NULL; - - for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++); - if (usblp_table[minor]) { - err("no more free usblp devices"); - return NULL; - } - + /* Malloc and start initializing usblp structure so we can use it + * directly. */ if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) { - err("out of memory"); - return NULL; + err("out of memory for usblp"); + goto abort; } memset(usblp, 0, sizeof(struct usblp)); - init_MUTEX (&usblp->sem); - - /* lookup quirks for this printer */ - quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct); - - if (bidir && (quirks & USBLP_QUIRK_BIDIR)) { - bidir = 0; - epread = NULL; - info ("Disabling reads from problem bidirectional printer on usblp%d", - minor); - } - usblp->dev = dev; + init_MUTEX (&usblp->sem); + init_waitqueue_head(&usblp->wait); usblp->ifnum = ifnum; - usblp->minor = minor; - usblp->bidir = bidir; - usblp->quirks = quirks; - init_waitqueue_head(&usblp->wait); + /* Look for a free usblp_table entry. */ + while (usblp_table[usblp->minor]) { + usblp->minor++; + if (usblp->minor >= USBLP_MINORS) { + err("no more free usblp devices"); + goto abort; + } + } usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL); if (!usblp->writeurb) { err("out of memory"); - kfree(usblp); - return NULL; + goto abort; } usblp->readurb = usb_alloc_urb(0, GFP_KERNEL); if (!usblp->readurb) { err("out of memory"); - usb_free_urb(usblp->writeurb); - kfree(usblp); - return NULL; + goto abort; } - if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) { - err("out of memory"); - usb_free_urb(usblp->writeurb); - usb_free_urb(usblp->readurb); - kfree(usblp); - return NULL; + /* Malloc device ID string buffer to the largest expected length, + * since we can re-query it on an ioctl and a dynamic string + * could change in length. */ + if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) { + err("out of memory for device_id_string"); + goto abort; } - if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) { - err("out of memory"); - usb_free_urb(usblp->writeurb); - usb_free_urb(usblp->readurb); - kfree(usblp); - kfree(buf); - return NULL; + /* Malloc write/read buffers in one chunk. We somewhat wastefully + * malloc both regardless of bidirectionality, because the + * alternate setting can be changed later via an ioctl. */ + if (!(usblp->buf = kmalloc(2 * USBLP_BUF_SIZE, GFP_KERNEL))) { + err("out of memory for buf"); + goto abort; } - FILL_BULK_URB(usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), - buf, 0, usblp_bulk_write, usblp); + /* Lookup quirks for this printer. */ + usblp->quirks = usblp_quirks( + dev->descriptor.idVendor, + dev->descriptor.idProduct); + + /* Analyze and pick initial alternate settings and endpoints. */ + protocol = usblp_select_alts(usblp); + if (protocol < 0) { + dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", + dev->descriptor.idVendor, + dev->descriptor.idProduct); + goto abort; + } - if (bidir) - FILL_BULK_URB(usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), - buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk_read, usblp); + /* Setup the selected alternate setting and endpoints. */ + if (usblp_set_protocol(usblp, protocol) < 0) + goto abort; - /* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */ - err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); - if (err >= 0) { - length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */ - if (length < DEVICE_ID_SIZE) - usblp->device_id_string[length] = '\0'; - else - usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0'; - dbg ("usblp%d Device ID string [%d]=%s", - minor, length, &usblp->device_id_string[2]); - } - else { - err ("usblp%d: error = %d reading IEEE-1284 Device ID string", - minor, err); - usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; - } + /* Retrieve and store the device ID string. */ + usblp_cache_device_id_string(usblp); #ifdef DEBUG usblp_check_status(usblp, 0); #endif - sprintf(name, "lp%d", minor); - - /* if we have devfs, create with perms=660 */ + /* If we have devfs, create with perms=660. */ + sprintf(name, "lp%d", usblp->minor); usblp->devfs = devfs_register(usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, - USBLP_MINOR_BASE + minor, + USBLP_MINOR_BASE + usblp->minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &usblp_fops, NULL); - info("usblp%d: USB %sdirectional printer dev %d if %d alt %d", - minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts); + info("usblp%d: USB %sdirectional printer dev %d " + "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X", + usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, ifnum, + usblp->protocol[usblp->current_protocol].alt_setting, + usblp->current_protocol, usblp->dev->descriptor.idVendor, + usblp->dev->descriptor.idProduct); - return usblp_table[minor] = usblp; + return usblp_table[usblp->minor] = usblp; + +abort: + if (usblp) { + usb_free_urb(usblp->writeurb); + usb_free_urb(usblp->readurb); + if (usblp->buf) kfree(usblp->buf); + if (usblp->device_id_string) kfree(usblp->device_id_string); + kfree(usblp); + } + return NULL; +} + +/* + * We are a "new" style driver with usb_device_id table, + * but our requirements are too intricate for simple match to handle. + * + * The "proto_bias" option may be used to specify the preferred protocol + * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3). If the device + * supports the preferred protocol, then we bind to it. + * + * The best interface for us is 7/1/2, because it is compatible + * with a stream of characters. If we find it, we bind to it. + * + * Note that the people from hpoj.sourceforge.net need to be able to + * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose. + * + * Failing 7/1/2, we look for 7/1/3, even though it's probably not + * stream-compatible, because this matches the behaviour of the old code. + * + * If nothing else, we bind to 7/1/1 - the unidirectional interface. + */ +static int usblp_select_alts(struct usblp *usblp) +{ + struct usb_interface *if_alt; + struct usb_interface_descriptor *ifd; + struct usb_endpoint_descriptor *epd, *epwrite, *epread; + int p, i, e; + + if_alt = &usblp->dev->actconfig->interface[usblp->ifnum]; + + for (p = 0; p < USBLP_MAX_PROTOCOLS; p++) + usblp->protocol[p].alt_setting = -1; + + /* Find out what we have. */ + for (i = 0; i < if_alt->num_altsetting; i++) { + ifd = &if_alt->altsetting[i]; + + if (ifd->bInterfaceClass != 7 || ifd->bInterfaceSubClass != 1) + continue; + + if (ifd->bInterfaceProtocol < USBLP_FIRST_PROTOCOL || + ifd->bInterfaceProtocol > USBLP_LAST_PROTOCOL) + continue; + + /* Look for bulk OUT and IN endpoints. */ + epwrite = epread = 0; + for (e = 0; e < ifd->bNumEndpoints; e++) { + epd = &ifd->endpoint[e]; + + if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!= + USB_ENDPOINT_XFER_BULK) + continue; + + if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) { + if (!epwrite) epwrite=epd; + + } else { + if (!epread) epread=epd; + } + } + + /* Ignore buggy hardware without the right endpoints. */ + if (!epwrite || (ifd->bInterfaceProtocol > 1 && !epread)) + continue; + + /* Turn off reads for 7/1/1 (unidirectional) interfaces + * and buggy bidirectional printers. */ + if (ifd->bInterfaceProtocol == 1) { + epread = NULL; + } else if (usblp->quirks & USBLP_QUIRK_BIDIR) { + info("Disabling reads from problem bidirectional " + "printer on usblp%d", usblp->minor); + epread = NULL; + } + + usblp->protocol[ifd->bInterfaceProtocol].alt_setting = i; + usblp->protocol[ifd->bInterfaceProtocol].epwrite = epwrite; + usblp->protocol[ifd->bInterfaceProtocol].epread = epread; + } + + /* If our requested protocol is supported, then use it. */ + if (proto_bias >= USBLP_FIRST_PROTOCOL && + proto_bias <= USBLP_LAST_PROTOCOL && + usblp->protocol[proto_bias].alt_setting != -1) + return proto_bias; + + /* Ordering is important here. */ + if (usblp->protocol[2].alt_setting != -1) return 2; + if (usblp->protocol[1].alt_setting != -1) return 1; + if (usblp->protocol[3].alt_setting != -1) return 3; + + /* If nothing is available, then don't bind to this device. */ + return -1; +} + +static int usblp_set_protocol(struct usblp *usblp, int protocol) +{ + int r, alts; + + if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) + return -EINVAL; + + alts = usblp->protocol[protocol].alt_setting; + if (alts < 0) return -EINVAL; + r = usb_set_interface(usblp->dev, usblp->ifnum, alts); + if (r < 0) { + err("can't set desired altsetting %d on interface %d", + alts, usblp->ifnum); + return r; + } + + FILL_BULK_URB(usblp->writeurb, usblp->dev, + usb_sndbulkpipe(usblp->dev, + usblp->protocol[protocol].epwrite->bEndpointAddress), + usblp->buf, 0, + usblp_bulk_write, usblp); + + usblp->bidir = (usblp->protocol[protocol].epread != 0); + if (usblp->bidir) + FILL_BULK_URB(usblp->readurb, usblp->dev, + usb_rcvbulkpipe(usblp->dev, + usblp->protocol[protocol].epread->bEndpointAddress), + usblp->buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, + usblp_bulk_read, usblp); + + usblp->current_protocol = protocol; + dbg("usblp%d set protocol %d", usblp->minor, protocol); + return 0; +} + +/* Retrieves and caches device ID string. + * Returns length, including length bytes but not null terminator. + * On error, returns a negative errno value. */ +static int usblp_cache_device_id_string(struct usblp *usblp) +{ + int err, length; + + err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1); + if (err < 0) { + dbg("usblp%d: error = %d reading IEEE-1284 Device ID string", + usblp->minor, err); + usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; + return -EIO; + } + + /* First two bytes are length in big-endian. + * They count themselves, and we copy them into + * the user's buffer. */ + length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; + if (length < 2) + length = 2; + else if (length >= DEVICE_ID_SIZE) + length = DEVICE_ID_SIZE - 1; + usblp->device_id_string[length] = '\0'; + + dbg("usblp%d Device ID string [len=%d]=\"%s\"", + usblp->minor, length, &usblp->device_id_string[2]); + + return length; } static void usblp_disconnect(struct usb_device *dev, void *ptr) @@ -757,9 +1055,7 @@ static void usblp_disconnect(struct usb_device *dev, void *ptr) lock_kernel(); usblp->dev = NULL; - usb_unlink_urb(usblp->writeurb); - if (usblp->bidir) - usb_unlink_urb(usblp->readurb); + usblp_unlink_urbs(usblp); if (!usblp->used) usblp_cleanup (usblp); @@ -794,7 +1090,7 @@ static int __init usblp_init(void) { if (usb_register(&usblp_driver)) return -1; - info(DRIVER_VERSION ":" DRIVER_DESC); + info(DRIVER_VERSION ": " DRIVER_DESC); return 0; } @@ -808,5 +1104,6 @@ module_exit(usblp_exit); MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_PARM(proto_bias, "i"); +MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index f185987c6541..812726b110fa 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -262,7 +262,7 @@ static int cyberjack_write (struct usb_serial_port *port, int from_user, const u port); /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); /* Throw away data. No better idea what to do with it. */ @@ -331,7 +331,7 @@ static void cyberjack_read_int_callback( struct urb *urb ) if( !old_rdtodo ) { port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if( result ) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); dbg(__FUNCTION__ " - usb_submit_urb(read urb)"); @@ -387,7 +387,7 @@ static void cyberjack_read_bulk_callback (struct urb *urb) /* Continue to read if we have still urbs to do. */ if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) { port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); dbg(__FUNCTION__ " - usb_submit_urb(read urb)"); @@ -440,7 +440,7 @@ static void cyberjack_write_bulk_callback (struct urb *urb) port); /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); /* Throw away data. No better idea what to do with it. */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 621af4d63ebc..a03c9b4a9a1d 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -676,7 +676,7 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, co oob_port->write_urb->transfer_buffer_length = len; oob_port->write_urb->dev = port->serial->dev; - if( (ret=usb_submit_urb(oob_port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0 ) { oob_priv->dp_write_urb_in_use = 1; count -= len; buf += len; @@ -764,7 +764,7 @@ count ); } port->write_urb->dev = port->serial->dev; - if( (ret=usb_submit_urb(port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) { priv->dp_write_urb_in_use = 1; priv->dp_out_buf_len = 0; count -= len; @@ -841,7 +841,7 @@ port_priv->dp_port_num, modem_signals ); oob_port->write_urb->transfer_buffer_length = 8; oob_port->write_urb->dev = port->serial->dev; - if( (ret=usb_submit_urb(oob_port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0 ) { oob_priv->dp_write_urb_in_use = 1; port_priv->dp_modem_signals = (port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS)) @@ -962,7 +962,7 @@ dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num ); /* restart read chain */ if( priv->dp_throttle_restart ) { port->read_urb->dev = port->serial->dev; - ret = usb_submit_urb( port->read_urb, GFP_KERNEL ); + ret = usb_submit_urb( port->read_urb, GFP_ATOMIC ); } /* turn throttle off */ @@ -1323,7 +1323,7 @@ priv->dp_port_num, count, from_user, in_interrupt() ); /* copy in new data */ memcpy( data, from_user ? user_buf : buf, new_len ); - if( (ret=usb_submit_urb(port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) { priv->dp_write_urb_in_use = 1; ret = new_len; priv->dp_out_buf_len = 0; @@ -1399,7 +1399,7 @@ dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status ); memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf, priv->dp_out_buf_len ); - if( (ret=usb_submit_urb(port->write_urb, GFP_KERNEL)) == 0 ) { + if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) { priv->dp_write_urb_in_use = 1; priv->dp_out_buf_len = 0; } @@ -1837,7 +1837,7 @@ dbg( "digi_read_bulk_callback: TOP" ); /* continue read */ urb->dev = port->serial->dev; - if( (ret=usb_submit_urb(urb, GFP_KERNEL)) != 0 ) { + if( (ret=usb_submit_urb(urb, GFP_ATOMIC)) != 0 ) { err( __FUNCTION__ ": failed resubmitting urb, ret=%d, port=%d", ret, priv->dp_port_num ); } diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 3a636d7a4740..fa390d5c32cc 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -256,7 +256,7 @@ static int empeg_write (struct usb_serial_port *port, int from_user, const unsig } if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); if (urb->transfer_buffer == NULL) { err(__FUNCTION__" no more kernel memory..."); goto exit; @@ -288,7 +288,7 @@ static int empeg_write (struct usb_serial_port *port, int from_user, const unsig urb->transfer_flags |= USB_QUEUE_BULK; /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_KERNEL); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); bytes_sent = status; @@ -441,7 +441,7 @@ static void empeg_read_bulk_callback (struct urb *urb) port->read_urb->transfer_flags |= USB_QUEUE_BULK; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); @@ -466,7 +466,7 @@ static void empeg_unthrottle (struct usb_serial_port *port) port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 911d3ac53f94..fc07f8f67835 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -469,7 +469,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, port->write_urb->transfer_buffer, count, ftdi_sio_write_bulk_callback, port); - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); return 0; @@ -631,7 +631,7 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ftdi_sio_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 60194ede19d8..393fbafd21e2 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -790,7 +790,7 @@ static void edge_interrupt_callback (struct urb *urb) /* we have pending bytes on the bulk in pipe, send a request */ edge_serial->read_urb->dev = edge_serial->serial->dev; - result = usb_submit_urb(edge_serial->read_urb, GFP_KERNEL); + result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (result) { dbg(__FUNCTION__" - usb_submit_urb(read bulk) failed with result = %d", result); } @@ -867,7 +867,7 @@ static void edge_bulk_in_callback (struct urb *urb) /* there is, so resubmit our urb */ edge_serial->read_urb->dev = edge_serial->serial->dev; - status = usb_submit_urb(edge_serial->read_urb, GFP_KERNEL); + status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); if (status) { err(__FUNCTION__" - usb_submit_urb(read bulk) failed, status = %d", status); } @@ -1435,7 +1435,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge /* build the data header for the buffer and port that we are about to send out */ count = fifo->count; - buffer = kmalloc (count+2, GFP_KERNEL); + buffer = kmalloc (count+2, GFP_ATOMIC); if (buffer == NULL) { err(__FUNCTION__" - no more kernel memory..."); edge_port->write_in_progress = FALSE; @@ -1474,7 +1474,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge urb->transfer_flags |= USB_QUEUE_BULK; urb->dev = edge_serial->serial->dev; - status = usb_submit_urb(urb, GFP_KERNEL); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { /* something went wrong */ dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed"); @@ -2431,7 +2431,7 @@ static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u dbg(__FUNCTION__" - %d, %d", command, param); - buffer = kmalloc (10, GFP_KERNEL); + buffer = kmalloc (10, GFP_ATOMIC); if (!buffer) { err(__FUNCTION__" - kmalloc(%d) failed.\n", 10); return -ENOMEM; @@ -2467,7 +2467,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer usb_serial_debug_data (__FILE__, __FUNCTION__, length, buffer); /* Allocate our next urb */ - urb = usb_alloc_urb (0, GFP_KERNEL); + urb = usb_alloc_urb (0, GFP_ATOMIC); if (!urb) return -ENOMEM; @@ -2482,7 +2482,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer urb->transfer_flags |= USB_QUEUE_BULK; edge_port->commandPending = TRUE; - status = usb_submit_urb(urb, GFP_KERNEL); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { /* something went wrong */ @@ -2532,7 +2532,7 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa } // Alloc memory for the string of commands. - cmdBuffer = kmalloc (0x100, GFP_KERNEL); + cmdBuffer = kmalloc (0x100, GFP_ATOMIC); if (!cmdBuffer) { err(__FUNCTION__" - kmalloc(%d) failed.\n", 0x100); return -ENOMEM; @@ -2618,7 +2618,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r dbg (__FUNCTION__" - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", regValue); // Alloc memory for the string of commands. - cmdBuffer = kmalloc (0x10, GFP_KERNEL); + cmdBuffer = kmalloc (0x10, GFP_ATOMIC); if (cmdBuffer == NULL ) { return -ENOMEM; } diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c839920d236a..c3e9c8791fa9 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -297,7 +297,7 @@ static void ipaq_read_bulk_callback(struct urb *urb) usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ipaq_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); return; @@ -412,7 +412,7 @@ static int ipaq_write_flush(struct usb_serial_port *port) usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback, port); - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); } diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index f44ae514529a..5a8f68918b67 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -405,7 +405,7 @@ static int ir_write (struct usb_serial_port *port, int from_user, const unsigned = USB_QUEUE_BULK | USB_ZERO_PACKET; - result = usb_submit_urb (port->write_urb, GFP_KERNEL); + result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) err("%s - failed submitting write urb, error %d", __FUNCTION__, result); else @@ -515,7 +515,7 @@ static void ir_read_bulk_callback (struct urb *urb) port->read_urb->transfer_flags = USB_QUEUE_BULK; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err("%s - failed resubmitting read urb, error %d", diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index d8d8a2e83bb2..2879204149e1 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -378,7 +378,7 @@ static int keyspan_write(struct usb_serial_port *port, int from_user, this_urb->transfer_flags &= ~USB_ASYNC_UNLINK; this_urb->dev = port->serial->dev; - if ((err = usb_submit_urb(this_urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(this_urb, GFP_ATOMIC)) != 0) { dbg("usb_submit_urb(write bulk) failed (%d)\n", err); } p_priv->tx_start_time[flip] = jiffies; @@ -436,7 +436,7 @@ static void usa26_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ urb->dev = port->serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } return; @@ -535,7 +535,7 @@ static void usa26_instat_callback(struct urb *urb) exit: /* Resubmit urb so we continue receiving */ urb->dev = serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } } @@ -586,7 +586,7 @@ static void usa28_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ urb->dev = port->serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } @@ -671,7 +671,7 @@ static void usa28_instat_callback(struct urb *urb) exit: /* Resubmit urb so we continue receiving */ urb->dev = serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } } @@ -764,7 +764,7 @@ exit: /* Resubmit urb so we continue receiving */ urb->dev = serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } } @@ -819,7 +819,7 @@ static void usa49_indat_callback(struct urb *urb) /* Resubmit urb so we continue receiving */ urb->dev = port->serial->dev; - if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) { + if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { dbg(__FUNCTION__ "resubmit read urb failed. (%d)\n", err); } } diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index ae37c1ff9b86..54b09b26e43c 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -292,7 +292,7 @@ static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port) /* just restart the receive interrupt URB */ dbg("keyspan_pda_rx_unthrottle port %d", port->number); port->interrupt_in_urb->dev = port->serial->dev; - if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) + if (usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC)) dbg(" usb_submit_urb(read urb) failed"); return; } @@ -584,7 +584,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, priv->tx_room -= count; port->write_urb->dev = port->serial->dev; - rc = usb_submit_urb(port->write_urb, GFP_KERNEL); + rc = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (rc) { dbg(" usb_submit_urb(write bulk) failed"); goto exit; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 3aa9c40e2c61..5b0e1b944dcb 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -519,7 +519,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, } if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); if (urb->transfer_buffer == NULL) { err(__FUNCTION__ " - no more kernel memory..."); goto exit; @@ -555,7 +555,7 @@ static int klsi_105_write (struct usb_serial_port *port, int from_user, /* send the data out the bulk port */ - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); @@ -721,7 +721,7 @@ static void klsi_105_read_bulk_callback (struct urb *urb) port->read_urb->transfer_buffer_length, klsi_105_read_bulk_callback, port); - rc = usb_submit_urb(port->read_urb, GFP_KERNEL); + rc = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (rc) err(__FUNCTION__ " - failed resubmitting read urb, error %d", rc); @@ -1019,7 +1019,7 @@ static void klsi_105_unthrottle (struct usb_serial_port *port) dbg(__FUNCTION__ " - port %d", port->number); port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 1151d0d2170a..125c4a647ab3 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -470,7 +470,7 @@ static int mct_u232_write (struct usb_serial_port *port, int from_user, port); /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { err(__FUNCTION__ " - failed submitting write urb, error %d", result); diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 2eb34c553790..457984644e9b 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -265,7 +265,7 @@ static void omninet_read_bulk_callback (struct urb *urb) usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), urb->transfer_buffer, urb->transfer_buffer_length, omninet_read_bulk_callback, port); - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); @@ -316,7 +316,7 @@ static int omninet_write (struct usb_serial_port *port, int from_user, const uns wport->write_urb->transfer_buffer_length = 64; wport->write_urb->dev = serial->dev; - result = usb_submit_urb(wport->write_urb, GFP_KERNEL); + result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting write urb, error %d", result); else diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 57dedd00441c..23adb9024f46 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -195,7 +195,7 @@ static int pl2303_write (struct usb_serial_port *port, int from_user, const uns port->write_urb->transfer_buffer_length = count; port->write_urb->dev = port->serial->dev; - result = usb_submit_urb (port->write_urb, GFP_KERNEL); + result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting write urb, error %d", result); else @@ -643,7 +643,7 @@ static void pl2303_read_bulk_callback (struct urb *urb) dbg (__FUNCTION__ " - caught -EPROTO, resubmitting the urb"); urb->status = 0; urb->dev = serial->dev; - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); return; @@ -668,7 +668,7 @@ static void pl2303_read_bulk_callback (struct urb *urb) /* Schedule the next read _if_ we are still open */ if (port->open_count) { urb->dev = serial->dev; - result = usb_submit_urb(urb, GFP_KERNEL); + result = usb_submit_urb(urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } @@ -697,7 +697,7 @@ static void pl2303_write_bulk_callback (struct urb *urb) dbg (__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); port->write_urb->transfer_buffer_length = 1; port->write_urb->dev = port->serial->dev; - result = usb_submit_urb (port->write_urb, GFP_KERNEL); + result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting write urb, error %d", result); diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c index 4746b8107f45..6271ade640d6 100644 --- a/drivers/usb/serial/usbserial.c +++ b/drivers/usb/serial/usbserial.c @@ -899,7 +899,7 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns generic_write_bulk_callback), port); /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_KERNEL); + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting write urb, error %d", result); else @@ -989,7 +989,7 @@ static void generic_read_bulk_callback (struct urb *urb) ((serial->type->read_bulk_callback) ? serial->type->read_bulk_callback : generic_read_bulk_callback), port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 2ac4489b92d8..29415d2e2fb1 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -344,13 +344,13 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig dbg(__FUNCTION__ " - port %d", port->number); - buffer = kmalloc (count, GFP_KERNEL); + buffer = kmalloc (count, GFP_ATOMIC); if (!buffer) { err ("out of memory"); return -ENOMEM; } - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { err ("no more free urbs"); kfree (buffer); @@ -377,7 +377,7 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig urb->transfer_flags |= USB_QUEUE_BULK; /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_KERNEL); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); count = status; @@ -491,7 +491,7 @@ static void visor_read_bulk_callback (struct urb *urb) port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, visor_read_bulk_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result); return; @@ -512,7 +512,7 @@ static void visor_unthrottle (struct usb_serial_port *port) dbg(__FUNCTION__ " - port %d", port->number); port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting read urb, error %d", result); } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 4485b3d26936..3a1dcf663a3a 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -240,7 +240,7 @@ static void command_port_read_callback (struct urb *urb) usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, command_port_read_callback, port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) dbg(__FUNCTION__ " - failed resubmitting read urb, error %d", result); } diff --git a/fs/filesystems.c b/fs/filesystems.c index 76eda773d051..9d924215e12c 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -6,7 +6,226 @@ * table of configured filesystems */ +#include <linux/config.h> +#include <linux/slab.h> +#include <linux/kmod.h> +#define __NO_VERSION__ +#include <linux/module.h> +#include <asm/uaccess.h> + +/* + * Handling of filesystem drivers list. + * Rules: + * Inclusion to/removals from/scanning of list are protected by spinlock. + * During the unload module must call unregister_filesystem(). + * We can access the fields of list element if: + * 1) spinlock is held or + * 2) we hold the reference to the module. + * The latter can be guaranteed by call of try_inc_mod_count(); if it + * returned 0 we must skip the element, otherwise we got the reference. + * Once the reference is obtained we can drop the spinlock. + */ + +static struct file_system_type *file_systems; +static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED; + +/* WARNING: This can be used only if we _already_ own a reference */ +void get_filesystem(struct file_system_type *fs) +{ + if (fs->owner) + __MOD_INC_USE_COUNT(fs->owner); +} + +void put_filesystem(struct file_system_type *fs) +{ + if (fs->owner) + __MOD_DEC_USE_COUNT(fs->owner); +} + +static struct file_system_type **find_filesystem(const char *name) +{ + struct file_system_type **p; + for (p=&file_systems; *p; p=&(*p)->next) + if (strcmp((*p)->name,name) == 0) + break; + return p; +} + +/** + * register_filesystem - register a new filesystem + * @fs: the file system structure + * + * Adds the file system passed to the list of file systems the kernel + * is aware of for mount and other syscalls. Returns 0 on success, + * or a negative errno code on an error. + * + * The &struct file_system_type that is passed is linked into the kernel + * structures and must not be freed until the file system has been + * unregistered. + */ + +int register_filesystem(struct file_system_type * fs) +{ + int res = 0; + struct file_system_type ** p; + + if (!fs) + return -EINVAL; + if (fs->next) + return -EBUSY; + INIT_LIST_HEAD(&fs->fs_supers); + write_lock(&file_systems_lock); + p = find_filesystem(fs->name); + if (*p) + res = -EBUSY; + else + *p = fs; + write_unlock(&file_systems_lock); + return res; +} + +/** + * unregister_filesystem - unregister a file system + * @fs: filesystem to unregister + * + * Remove a file system that was previously successfully registered + * with the kernel. An error is returned if the file system is not found. + * Zero is returned on a success. + * + * Once this function has returned the &struct file_system_type structure + * may be freed or reused. + */ + +int unregister_filesystem(struct file_system_type * fs) +{ + struct file_system_type ** tmp; + + write_lock(&file_systems_lock); + tmp = &file_systems; + while (*tmp) { + if (fs == *tmp) { + *tmp = fs->next; + fs->next = NULL; + write_unlock(&file_systems_lock); + return 0; + } + tmp = &(*tmp)->next; + } + write_unlock(&file_systems_lock); + return -EINVAL; +} + +static int fs_index(const char * __name) +{ + struct file_system_type * tmp; + char * name; + int err, index; + + name = getname(__name); + err = PTR_ERR(name); + if (IS_ERR(name)) + return err; + + err = -EINVAL; + read_lock(&file_systems_lock); + for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) { + if (strcmp(tmp->name,name) == 0) { + err = index; + break; + } + } + read_unlock(&file_systems_lock); + putname(name); + return err; +} + +static int fs_name(unsigned int index, char * buf) +{ + struct file_system_type * tmp; + int len, res; + + read_lock(&file_systems_lock); + for (tmp = file_systems; tmp; tmp = tmp->next, index--) + if (index <= 0 && try_inc_mod_count(tmp->owner)) + break; + read_unlock(&file_systems_lock); + if (!tmp) + return -EINVAL; + + /* OK, we got the reference, so we can safely block */ + len = strlen(tmp->name) + 1; + res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0; + put_filesystem(tmp); + return res; +} + +static int fs_maxindex(void) +{ + struct file_system_type * tmp; + int index; + + read_lock(&file_systems_lock); + for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++) + ; + read_unlock(&file_systems_lock); + return index; +} + /* - * Code will move here from fs/super.c and yes, it will be fs type handling - * stuff. + * Whee.. Weird sysv syscall. */ +asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2) +{ + int retval = -EINVAL; + + switch (option) { + case 1: + retval = fs_index((const char *) arg1); + break; + + case 2: + retval = fs_name(arg1, (char *) arg2); + break; + + case 3: + retval = fs_maxindex(); + break; + } + return retval; +} + +int get_filesystem_list(char * buf) +{ + int len = 0; + struct file_system_type * tmp; + + read_lock(&file_systems_lock); + tmp = file_systems; + while (tmp && len < PAGE_SIZE - 80) { + len += sprintf(buf+len, "%s\t%s\n", + (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", + tmp->name); + tmp = tmp->next; + } + read_unlock(&file_systems_lock); + return len; +} + +struct file_system_type *get_fs_type(const char *name) +{ + struct file_system_type *fs; + + read_lock(&file_systems_lock); + fs = *(find_filesystem(name)); + if (fs && !try_inc_mod_count(fs->owner)) + fs = NULL; + read_unlock(&file_systems_lock); + if (!fs && (request_module(name) == 0)) { + read_lock(&file_systems_lock); + fs = *(find_filesystem(name)); + if (fs && !try_inc_mod_count(fs->owner)) + fs = NULL; + read_unlock(&file_systems_lock); + } + return fs; +} diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 583ade0421c0..bef27095249e 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c @@ -110,14 +110,13 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, struct buffer_head *bh = NULL; int len; int map; - int high_sierra; int first_de = 1; char *p = NULL; /* Quiet GCC */ struct iso_directory_record *de; + struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb); offset = filp->f_pos & (bufsize - 1); block = filp->f_pos >> bufbits; - high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; while (filp->f_pos < inode->i_size) { int de_len; @@ -166,7 +165,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, de = tmpde; } - if (de->flags[-high_sierra] & 0x80) { + if (de->flags[-sbi->s_high_sierra] & 0x80) { first_de = 0; filp->f_pos += de_len; continue; @@ -194,16 +193,16 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, /* Handle everything else. Do name translation if there is no Rock Ridge NM field. */ - if (inode->i_sb->u.isofs_sb.s_unhide == 'n') { + if (sbi->s_unhide == 'n') { /* Do not report hidden or associated files */ - if (de->flags[-high_sierra] & 5) { + if (de->flags[-sbi->s_high_sierra] & 5) { filp->f_pos += de_len; continue; } } map = 1; - if (inode->i_sb->u.isofs_sb.s_rock) { + if (sbi->s_rock) { len = get_rock_ridge_filename(de, tmpname, inode); if (len != 0) { /* may be -1 */ p = tmpname; @@ -212,16 +211,16 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, } if (map) { #ifdef CONFIG_JOLIET - if (inode->i_sb->u.isofs_sb.s_joliet_level) { + if (sbi->s_joliet_level) { len = get_joliet_filename(de, tmpname, inode); p = tmpname; } else #endif - if (inode->i_sb->u.isofs_sb.s_mapping == 'a') { + if (sbi->s_mapping == 'a') { len = get_acorn_filename(de, tmpname, inode); p = tmpname; } else - if (inode->i_sb->u.isofs_sb.s_mapping == 'n') { + if (sbi->s_mapping == 'n') { len = isofs_name_translate(de, tmpname, inode); p = tmpname; } else { diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index d1bec1eae0a0..31174ae2bede 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -60,10 +60,11 @@ static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qst static void isofs_put_super(struct super_block *sb) { + struct isofs_sb_info *sbi = ISOFS_SB(sb); #ifdef CONFIG_JOLIET - if (sb->u.isofs_sb.s_nls_iocharset) { - unload_nls(sb->u.isofs_sb.s_nls_iocharset); - sb->u.isofs_sb.s_nls_iocharset = NULL; + if (sbi->s_nls_iocharset) { + unload_nls(sbi->s_nls_iocharset); + sbi->s_nls_iocharset = NULL; } #endif @@ -72,6 +73,8 @@ static void isofs_put_super(struct super_block *sb) check_malloc, check_bread); #endif + kfree(sbi); + sb->u.generic_sbp = NULL; return; } @@ -518,7 +521,6 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) struct iso_supplementary_descriptor *sec = NULL; struct iso_directory_record * rootp; int joliet_level = 0; - int high_sierra; int iso_blknum, block; int orig_zonesize; int table; @@ -526,9 +528,16 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) unsigned long first_data_zone; struct inode * inode; struct iso9660_options opt; + struct isofs_sb_info * sbi; + + sbi = kmalloc(sizeof(struct isofs_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; + s->u.generic_sbp = sbi; + memset(sbi, 0, sizeof(struct isofs_sb_info)); if (!parse_options((char *) data, &opt)) - goto out_unlock; + goto out_freesbi; #if 0 printk("map = %c\n", opt.map); @@ -554,7 +563,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) */ opt.blocksize = sb_min_blocksize(s, opt.blocksize); - s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */ + sbi->s_high_sierra = 0; /* default is iso9660 */ vol_desc_start = (opt.sbsector != -1) ? opt.sbsector : isofs_get_last_session(s,opt.session); @@ -614,8 +623,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) if (isonum_711 (hdp->type) != ISO_VD_PRIMARY) goto out_freebh; - s->u.isofs_sb.s_high_sierra = 1; - high_sierra = 1; + sbi->s_high_sierra = 1; opt.rock = 'n'; h_pri = (struct hs_primary_descriptor *)vdp; goto root_found; @@ -646,29 +654,29 @@ root_found: pri = (struct iso_primary_descriptor *) sec; } - if(high_sierra){ + if(sbi->s_high_sierra){ rootp = (struct iso_directory_record *) h_pri->root_directory_record; #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (h_pri->volume_set_size) != 1) goto out_no_support; #endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ - s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size); - s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size); - s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size); + sbi->s_nzones = isonum_733 (h_pri->volume_space_size); + sbi->s_log_zone_size = isonum_723 (h_pri->logical_block_size); + sbi->s_max_size = isonum_733(h_pri->volume_space_size); } else { rootp = (struct iso_directory_record *) pri->root_directory_record; #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (pri->volume_set_size) != 1) goto out_no_support; #endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ - s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size); - s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size); - s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size); + sbi->s_nzones = isonum_733 (pri->volume_space_size); + sbi->s_log_zone_size = isonum_723 (pri->logical_block_size); + sbi->s_max_size = isonum_733(pri->volume_space_size); } - s->u.isofs_sb.s_ninodes = 0; /* No way to figure this out easily */ + sbi->s_ninodes = 0; /* No way to figure this out easily */ - orig_zonesize = s -> u.isofs_sb.s_log_zone_size; + orig_zonesize = sbi->s_log_zone_size; /* * If the zone size is smaller than the hardware sector size, * this is a fatal error. This would occur if the disc drive @@ -680,10 +688,10 @@ root_found: goto out_bad_size; /* RDE: convert log zone size to bit shift */ - switch (s -> u.isofs_sb.s_log_zone_size) - { case 512: s -> u.isofs_sb.s_log_zone_size = 9; break; - case 1024: s -> u.isofs_sb.s_log_zone_size = 10; break; - case 2048: s -> u.isofs_sb.s_log_zone_size = 11; break; + switch (sbi->s_log_zone_size) + { case 512: sbi->s_log_zone_size = 9; break; + case 1024: sbi->s_log_zone_size = 10; break; + case 2048: sbi->s_log_zone_size = 11; break; default: goto out_bad_zone_size; @@ -705,16 +713,16 @@ root_found: first_data_zone = ((isonum_733 (rootp->extent) + isonum_711 (rootp->ext_attr_length)) - << s -> u.isofs_sb.s_log_zone_size); - s->u.isofs_sb.s_firstdatazone = first_data_zone; + << sbi->s_log_zone_size); + sbi->s_firstdatazone = first_data_zone; #ifndef BEQUIET printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n", - s->u.isofs_sb.s_max_size, - 1UL << s->u.isofs_sb.s_log_zone_size); + sbi->s_max_size, + 1UL << sbi->s_log_zone_size); printk(KERN_DEBUG "First datazone:%ld Root inode number:%ld\n", - s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size, - s->u.isofs_sb.s_firstdatazone); - if(high_sierra) + sbi->s_firstdatazone >> sbi->s_log_zone_size, + sbi->s_firstdatazone); + if(sbi->s_high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n"); #endif @@ -732,7 +740,7 @@ root_found: pri->root_directory_record; first_data_zone = ((isonum_733 (rootp->extent) + isonum_711 (rootp->ext_attr_length)) - << s -> u.isofs_sb.s_log_zone_size); + << sbi->s_log_zone_size); } /* @@ -761,43 +769,43 @@ root_found: */ sb_set_blocksize(s, orig_zonesize); - s->u.isofs_sb.s_nls_iocharset = NULL; + sbi->s_nls_iocharset = NULL; #ifdef CONFIG_JOLIET if (joliet_level && opt.utf8 == 0) { char * p = opt.iocharset ? opt.iocharset : "iso8859-1"; - s->u.isofs_sb.s_nls_iocharset = load_nls(p); - if (! s->u.isofs_sb.s_nls_iocharset) { + sbi->s_nls_iocharset = load_nls(p); + if (! sbi->s_nls_iocharset) { /* Fail only if explicit charset specified */ if (opt.iocharset) - goto out_unlock; - s->u.isofs_sb.s_nls_iocharset = load_nls_default(); + goto out_freesbi; + sbi->s_nls_iocharset = load_nls_default(); } } #endif s->s_op = &isofs_sops; - s->u.isofs_sb.s_mapping = opt.map; - s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 2 : 0); - s->u.isofs_sb.s_rock_offset = -1; /* initial offset, will guess until SP is found*/ - s->u.isofs_sb.s_cruft = opt.cruft; - s->u.isofs_sb.s_unhide = opt.unhide; - s->u.isofs_sb.s_uid = opt.uid; - s->u.isofs_sb.s_gid = opt.gid; - s->u.isofs_sb.s_utf8 = opt.utf8; - s->u.isofs_sb.s_nocompress = opt.nocompress; + sbi->s_mapping = opt.map; + sbi->s_rock = (opt.rock == 'y' ? 2 : 0); + sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ + sbi->s_cruft = opt.cruft; + sbi->s_unhide = opt.unhide; + sbi->s_uid = opt.uid; + sbi->s_gid = opt.gid; + sbi->s_utf8 = opt.utf8; + sbi->s_nocompress = opt.nocompress; /* * It would be incredibly stupid to allow people to mark every file * on the disk as suid, so we merely allow them to set the default * permissions. */ - s->u.isofs_sb.s_mode = opt.mode & 0777; + sbi->s_mode = opt.mode & 0777; /* * Read the root inode, which _may_ result in changing * the s_rock flag. Once we have the final s_rock value, * we then decide whether to use the Joliet descriptor. */ - inode = iget(s, s->u.isofs_sb.s_firstdatazone); + inode = iget(s, sbi->s_firstdatazone); /* * If this disk has both Rock Ridge and Joliet on it, then we @@ -807,16 +815,16 @@ root_found: * CD with Unicode names. Until someone sees such a beast, it * will not be supported. */ - if (s->u.isofs_sb.s_rock == 1) { + if (sbi->s_rock == 1) { joliet_level = 0; } else if (joliet_level) { - s->u.isofs_sb.s_rock = 0; - if (s->u.isofs_sb.s_firstdatazone != first_data_zone) { - s->u.isofs_sb.s_firstdatazone = first_data_zone; + sbi->s_rock = 0; + if (sbi->s_firstdatazone != first_data_zone) { + sbi->s_firstdatazone = first_data_zone; printk(KERN_DEBUG "ISOFS: changing to secondary root\n"); iput(inode); - inode = iget(s, s->u.isofs_sb.s_firstdatazone); + inode = iget(s, sbi->s_firstdatazone); } } @@ -825,7 +833,7 @@ root_found: if (joliet_level) opt.check = 'r'; else opt.check = 's'; } - s->u.isofs_sb.s_joliet_level = joliet_level; + sbi->s_joliet_level = joliet_level; /* check the root inode */ if (!inode) @@ -855,18 +863,18 @@ out_no_root: out_iput: iput(inode); #ifdef CONFIG_JOLIET - if (s->u.isofs_sb.s_nls_iocharset) - unload_nls(s->u.isofs_sb.s_nls_iocharset); + if (sbi->s_nls_iocharset) + unload_nls(sbi->s_nls_iocharset); #endif - goto out_unlock; + goto out_freesbi; out_no_read: printk(KERN_WARNING "isofs_fill_super: " "bread failed, dev=%s, iso_blknum=%d, block=%d\n", s->s_id, iso_blknum, block); - goto out_unlock; + goto out_freesbi; out_bad_zone_size: printk(KERN_WARNING "Bad logical zone size %ld\n", - s->u.isofs_sb.s_log_zone_size); + sbi->s_log_zone_size); goto out_freebh; out_bad_size: printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n", @@ -883,7 +891,9 @@ out_unknown_format: out_freebh: brelse(bh); -out_unlock: +out_freesbi: + kfree(sbi); + s->u.generic_sbp = NULL; return -EINVAL; } @@ -891,11 +901,11 @@ static int isofs_statfs (struct super_block *sb, struct statfs *buf) { buf->f_type = ISOFS_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; - buf->f_blocks = (sb->u.isofs_sb.s_nzones - << (sb->u.isofs_sb.s_log_zone_size - sb->s_blocksize_bits)); + buf->f_blocks = (ISOFS_SB(sb)->s_nzones + << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits)); buf->f_bfree = 0; buf->f_bavail = 0; - buf->f_files = sb->u.isofs_sb.s_ninodes; + buf->f_files = ISOFS_SB(sb)->s_ninodes; buf->f_ffree = 0; buf->f_namelen = NAME_MAX; return 0; @@ -1058,7 +1068,7 @@ static int isofs_read_level3_size(struct inode * inode) { unsigned long f_pos = inode->i_ino; unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); - int high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; + int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra; struct buffer_head * bh = NULL; unsigned long block, offset; int i = 0; @@ -1157,9 +1167,10 @@ out_toomany: static void isofs_read_inode(struct inode * inode) { struct super_block *sb = inode->i_sb; + struct isofs_sb_info *sbi = ISOFS_SB(sb); unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); int block = inode->i_ino >> ISOFS_BUFFER_BITS(inode); - int high_sierra = sb->u.isofs_sb.s_high_sierra; + int high_sierra = sbi->s_high_sierra; struct buffer_head * bh = NULL; struct iso_directory_record * de; struct iso_directory_record * tmpde = NULL; @@ -1205,7 +1216,7 @@ static void isofs_read_inode(struct inode * inode) do it the hard way. */ } else { /* Everybody gets to read the file. */ - inode->i_mode = inode->i_sb->u.isofs_sb.s_mode; + inode->i_mode = sbi->s_mode; inode->i_nlink = 1; inode->i_mode |= S_IFREG; /* If there are no periods in the name, @@ -1217,8 +1228,8 @@ static void isofs_read_inode(struct inode * inode) if(i == de->name_len[0] || de->name[i] == ';') inode->i_mode |= S_IXUGO; /* execute permission */ } - inode->i_uid = inode->i_sb->u.isofs_sb.s_uid; - inode->i_gid = inode->i_sb->u.isofs_sb.s_gid; + inode->i_uid = sbi->s_uid; + inode->i_gid = sbi->s_gid; inode->i_blocks = inode->i_blksize = 0; ei->i_format_parm[0] = 0; @@ -1241,10 +1252,10 @@ static void isofs_read_inode(struct inode * inode) * legal. Do not prevent to use DVD's schilling@fokus.gmd.de */ if ((inode->i_size < 0 || inode->i_size > 0x7FFFFFFE) && - inode->i_sb->u.isofs_sb.s_cruft == 'n') { + sbi->s_cruft == 'n') { printk(KERN_WARNING "Warning: defective CD-ROM. " "Enabling \"cruft\" mount option.\n"); - inode->i_sb->u.isofs_sb.s_cruft = 'y'; + sbi->s_cruft = 'y'; } /* @@ -1254,7 +1265,7 @@ static void isofs_read_inode(struct inode * inode) * on the CDROM. */ - if (inode->i_sb->u.isofs_sb.s_cruft == 'y' && + if (sbi->s_cruft == 'y' && inode->i_size & 0xff000000) { inode->i_size &= 0x00ffffff; } @@ -1298,8 +1309,8 @@ static void isofs_read_inode(struct inode * inode) if (!high_sierra) { parse_rock_ridge_inode(de, inode); /* if we want uid/gid set, override the rock ridge setting */ - test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid); - test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid); + test_and_set_uid(&inode->i_uid, sbi->s_uid); + test_and_set_gid(&inode->i_gid, sbi->s_gid); } /* get the volume sequence number */ @@ -1311,17 +1322,17 @@ static void isofs_read_inode(struct inode * inode) * of which is limiting the file size to 16Mb. Thus we silently allow * volume numbers of 0 to go through without complaining. */ - if (inode->i_sb->u.isofs_sb.s_cruft == 'n' && + if (sbi->s_cruft == 'n' && (volume_seq_no != 0) && (volume_seq_no != 1)) { printk(KERN_WARNING "Warning: defective CD-ROM " "(volume sequence number %d). " "Enabling \"cruft\" mount option.\n", volume_seq_no); - inode->i_sb->u.isofs_sb.s_cruft = 'y'; + sbi->s_cruft = 'y'; } /* Install the inode operations vector */ #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS - if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && + if (sbi->s_cruft != 'y' && (volume_seq_no != 0) && (volume_seq_no != 1)) { printk(KERN_WARNING "Multi-volume CD somehow got mounted.\n"); } else diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c index 15d2370bda3f..86c50e22fc87 100644 --- a/fs/isofs/joliet.c +++ b/fs/isofs/joliet.c @@ -77,8 +77,8 @@ get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, st struct nls_table *nls; unsigned char len = 0; - utf8 = inode->i_sb->u.isofs_sb.s_utf8; - nls = inode->i_sb->u.isofs_sb.s_nls_iocharset; + utf8 = ISOFS_SB(inode->i_sb)->s_utf8; + nls = ISOFS_SB(inode->i_sb)->s_nls_iocharset; if (utf8) { len = wcsntombs_be(outname, de->name, diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 485bb7023fe2..cbdf44b0164e 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -65,6 +65,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned char bufbits = ISOFS_BUFFER_BITS(dir); unsigned int block, f_pos, offset; struct buffer_head * bh = NULL; + struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb); if (!ISOFS_I(dir)->i_first_extent) return 0; @@ -120,19 +121,19 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, dlen = de->name_len[0]; dpnt = de->name; - if (dir->i_sb->u.isofs_sb.s_rock && + if (sbi->s_rock && ((i = get_rock_ridge_filename(de, tmpname, dir)))) { dlen = i; /* possibly -1 */ dpnt = tmpname; #ifdef CONFIG_JOLIET - } else if (dir->i_sb->u.isofs_sb.s_joliet_level) { + } else if (sbi->s_joliet_level) { dlen = get_joliet_filename(de, tmpname, dir); dpnt = tmpname; #endif - } else if (dir->i_sb->u.isofs_sb.s_mapping == 'a') { + } else if (sbi->s_mapping == 'a') { dlen = get_acorn_filename(de, tmpname, dir); dpnt = tmpname; - } else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') { + } else if (sbi->s_mapping == 'n') { dlen = isofs_name_translate(de, tmpname, dir); dpnt = tmpname; } @@ -142,8 +143,8 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, */ match = 0; if (dlen > 0 && - (!(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5) - || dir->i_sb->u.isofs_sb.s_unhide == 'y')) + (!(de->flags[-sbi->s_high_sierra] & 5) + || sbi->s_unhide == 'y')) { match = (isofs_cmp(dentry,dpnt,dlen) == 0); } diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 5065d2fdccc6..17b2bb5e6908 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -32,7 +32,7 @@ #define CHECK_SP(FAIL) \ if(rr->u.SP.magic[0] != 0xbe) FAIL; \ if(rr->u.SP.magic[1] != 0xef) FAIL; \ - inode->i_sb->u.isofs_sb.s_rock_offset=rr->u.SP.skip; + ISOFS_SB(inode->i_sb)->s_rock_offset=rr->u.SP.skip; /* We define a series of macros because each function must do exactly the same thing in certain places. We use the macros to ensure that everything is done correctly */ @@ -51,10 +51,10 @@ if(LEN & 1) LEN++; \ CHR = ((unsigned char *) DE) + LEN; \ LEN = *((unsigned char *) DE) - LEN; \ - if (inode->i_sb->u.isofs_sb.s_rock_offset!=-1) \ + if (ISOFS_SB(inode->i_sb)->s_rock_offset!=-1) \ { \ - LEN-=inode->i_sb->u.isofs_sb.s_rock_offset; \ - CHR+=inode->i_sb->u.isofs_sb.s_rock_offset; \ + LEN-=ISOFS_SB(inode->i_sb)->s_rock_offset; \ + CHR+=ISOFS_SB(inode->i_sb)->s_rock_offset; \ if (LEN<0) LEN=0; \ } \ } @@ -102,7 +102,7 @@ int find_rock_ridge_relocation(struct iso_directory_record * de, /* Return value if we do not find appropriate record. */ retval = isonum_733 (de->extent); - if (!inode->i_sb->u.isofs_sb.s_rock) return retval; + if (!ISOFS_SB(inode->i_sb)->s_rock) return retval; SETUP_ROCK_RIDGE(de, chr, len); repeat: @@ -162,7 +162,7 @@ int get_rock_ridge_filename(struct iso_directory_record * de, CONTINUE_DECLS; int retnamlen = 0, truncate=0; - if (!inode->i_sb->u.isofs_sb.s_rock) return 0; + if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; *retname = 0; SETUP_ROCK_RIDGE(de, chr, len); @@ -234,7 +234,7 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de, int symlink_len = 0; CONTINUE_DECLS; - if (!inode->i_sb->u.isofs_sb.s_rock) return 0; + if (!ISOFS_SB(inode->i_sb)->s_rock) return 0; SETUP_ROCK_RIDGE(de, chr, len); if (regard_xa) @@ -272,7 +272,7 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de, CHECK_CE; break; case SIG('E','R'): - inode->i_sb->u.isofs_sb.s_rock = 1; + ISOFS_SB(inode->i_sb)->s_rock = 1; printk(KERN_DEBUG "ISO 9660 Extensions: "); { int p; for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]); @@ -368,7 +368,7 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de, ISOFS_I(inode)->i_first_extent = isonum_733(rr->u.CL.location); reloc = iget(inode->i_sb, (ISOFS_I(inode)->i_first_extent << - inode -> i_sb -> u.isofs_sb.s_log_zone_size)); + ISOFS_SB(inode->i_sb)->s_log_zone_size)); if (!reloc) goto out; inode->i_mode = reloc->i_mode; @@ -385,7 +385,7 @@ int parse_rock_ridge_inode_internal(struct iso_directory_record * de, break; #ifdef CONFIG_ZISOFS case SIG('Z','F'): - if ( !inode->i_sb->u.isofs_sb.s_nocompress ) { + if ( !ISOFS_SB(inode->i_sb)->s_nocompress ) { int algo; algo = isonum_721(rr->u.ZF.algorithm); if ( algo == SIG('p','z') ) { @@ -478,8 +478,8 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, int result=parse_rock_ridge_inode_internal(de,inode,0); /* if rockridge flag was reset and we didn't look for attributes * behind eventual XA attributes, have a look there */ - if ((inode->i_sb->u.isofs_sb.s_rock_offset==-1) - &&(inode->i_sb->u.isofs_sb.s_rock==2)) + if ((ISOFS_SB(inode->i_sb)->s_rock_offset==-1) + &&(ISOFS_SB(inode->i_sb)->s_rock==2)) { result=parse_rock_ridge_inode_internal(de,inode,14); }; @@ -506,7 +506,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) unsigned char *chr; struct rock_ridge *rr; - if (!inode->i_sb->u.isofs_sb.s_rock) + if (!ISOFS_SB(inode->i_sb)->s_rock) panic ("Cannot have symlink with high sierra variant of iso filesystem\n"); block = inode->i_ino >> bufbits; diff --git a/fs/super.c b/fs/super.c index 66a6274d1b71..1a2d66737e08 100644 --- a/fs/super.c +++ b/fs/super.c @@ -25,235 +25,16 @@ #include <linux/locks.h> #include <linux/smp_lock.h> #include <linux/devfs_fs_kernel.h> -#include <linux/major.h> #include <linux/acct.h> - #include <asm/uaccess.h> -#include <linux/kmod.h> -#define __NO_VERSION__ -#include <linux/module.h> +void get_filesystem(struct file_system_type *fs); +void put_filesystem(struct file_system_type *fs); +struct file_system_type *get_fs_type(const char *name); LIST_HEAD(super_blocks); spinlock_t sb_lock = SPIN_LOCK_UNLOCKED; -/* - * Handling of filesystem drivers list. - * Rules: - * Inclusion to/removals from/scanning of list are protected by spinlock. - * During the unload module must call unregister_filesystem(). - * We can access the fields of list element if: - * 1) spinlock is held or - * 2) we hold the reference to the module. - * The latter can be guaranteed by call of try_inc_mod_count(); if it - * returned 0 we must skip the element, otherwise we got the reference. - * Once the reference is obtained we can drop the spinlock. - */ - -static struct file_system_type *file_systems; -static rwlock_t file_systems_lock = RW_LOCK_UNLOCKED; - -/* WARNING: This can be used only if we _already_ own a reference */ -static void get_filesystem(struct file_system_type *fs) -{ - if (fs->owner) - __MOD_INC_USE_COUNT(fs->owner); -} - -static void put_filesystem(struct file_system_type *fs) -{ - if (fs->owner) - __MOD_DEC_USE_COUNT(fs->owner); -} - -static struct file_system_type **find_filesystem(const char *name) -{ - struct file_system_type **p; - for (p=&file_systems; *p; p=&(*p)->next) - if (strcmp((*p)->name,name) == 0) - break; - return p; -} - -/** - * register_filesystem - register a new filesystem - * @fs: the file system structure - * - * Adds the file system passed to the list of file systems the kernel - * is aware of for mount and other syscalls. Returns 0 on success, - * or a negative errno code on an error. - * - * The &struct file_system_type that is passed is linked into the kernel - * structures and must not be freed until the file system has been - * unregistered. - */ - -int register_filesystem(struct file_system_type * fs) -{ - int res = 0; - struct file_system_type ** p; - - if (!fs) - return -EINVAL; - if (fs->next) - return -EBUSY; - INIT_LIST_HEAD(&fs->fs_supers); - write_lock(&file_systems_lock); - p = find_filesystem(fs->name); - if (*p) - res = -EBUSY; - else - *p = fs; - write_unlock(&file_systems_lock); - return res; -} - -/** - * unregister_filesystem - unregister a file system - * @fs: filesystem to unregister - * - * Remove a file system that was previously successfully registered - * with the kernel. An error is returned if the file system is not found. - * Zero is returned on a success. - * - * Once this function has returned the &struct file_system_type structure - * may be freed or reused. - */ - -int unregister_filesystem(struct file_system_type * fs) -{ - struct file_system_type ** tmp; - - write_lock(&file_systems_lock); - tmp = &file_systems; - while (*tmp) { - if (fs == *tmp) { - *tmp = fs->next; - fs->next = NULL; - write_unlock(&file_systems_lock); - return 0; - } - tmp = &(*tmp)->next; - } - write_unlock(&file_systems_lock); - return -EINVAL; -} - -static int fs_index(const char * __name) -{ - struct file_system_type * tmp; - char * name; - int err, index; - - name = getname(__name); - err = PTR_ERR(name); - if (IS_ERR(name)) - return err; - - err = -EINVAL; - read_lock(&file_systems_lock); - for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) { - if (strcmp(tmp->name,name) == 0) { - err = index; - break; - } - } - read_unlock(&file_systems_lock); - putname(name); - return err; -} - -static int fs_name(unsigned int index, char * buf) -{ - struct file_system_type * tmp; - int len, res; - - read_lock(&file_systems_lock); - for (tmp = file_systems; tmp; tmp = tmp->next, index--) - if (index <= 0 && try_inc_mod_count(tmp->owner)) - break; - read_unlock(&file_systems_lock); - if (!tmp) - return -EINVAL; - - /* OK, we got the reference, so we can safely block */ - len = strlen(tmp->name) + 1; - res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0; - put_filesystem(tmp); - return res; -} - -static int fs_maxindex(void) -{ - struct file_system_type * tmp; - int index; - - read_lock(&file_systems_lock); - for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++) - ; - read_unlock(&file_systems_lock); - return index; -} - -/* - * Whee.. Weird sysv syscall. - */ -asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2) -{ - int retval = -EINVAL; - - switch (option) { - case 1: - retval = fs_index((const char *) arg1); - break; - - case 2: - retval = fs_name(arg1, (char *) arg2); - break; - - case 3: - retval = fs_maxindex(); - break; - } - return retval; -} - -int get_filesystem_list(char * buf) -{ - int len = 0; - struct file_system_type * tmp; - - read_lock(&file_systems_lock); - tmp = file_systems; - while (tmp && len < PAGE_SIZE - 80) { - len += sprintf(buf+len, "%s\t%s\n", - (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", - tmp->name); - tmp = tmp->next; - } - read_unlock(&file_systems_lock); - return len; -} - -struct file_system_type *get_fs_type(const char *name) -{ - struct file_system_type *fs; - - read_lock(&file_systems_lock); - fs = *(find_filesystem(name)); - if (fs && !try_inc_mod_count(fs->owner)) - fs = NULL; - read_unlock(&file_systems_lock); - if (!fs && (request_module(name) == 0)) { - read_lock(&file_systems_lock); - fs = *(find_filesystem(name)); - if (fs && !try_inc_mod_count(fs->owner)) - fs = NULL; - read_unlock(&file_systems_lock); - } - return fs; -} - /** * alloc_super - create new superblock * diff --git a/fs/udf/super.c b/fs/udf/super.c index 0e668a01a592..2edd4015fb61 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1413,12 +1413,17 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) struct inode *inode=NULL; struct udf_options uopt; lb_addr rootdir, fileset; + struct udf_sb_info *sbi; uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); uopt.uid = -1; uopt.gid = -1; uopt.umask = 0; + sbi = kmalloc(sizeof(struct udf_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; + sb->u.generic_sbp = sbi; memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info)); #if UDFFS_RW != 1 @@ -1607,6 +1612,8 @@ error_out: udf_close_lvid(sb); udf_release_data(UDF_SB_LVIDBH(sb)); UDF_SB_FREE(sb); + kfree(sbi); + sb->u.generic_sbp = NULL; return -EINVAL; } @@ -1697,6 +1704,8 @@ udf_put_super(struct super_block *sb) udf_close_lvid(sb); udf_release_data(UDF_SB_LVIDBH(sb)); UDF_SB_FREE(sb); + kfree(sb->u.generic_sbp); + sb->u.generic_sbp = NULL; } /* diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 0dde99415c97..2b264e1cf49a 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -30,6 +30,11 @@ #define UDF_PART_FLAG_REWRITABLE 0x0040 #define UDF_PART_FLAG_OVERWRITABLE 0x0080 +static inline struct udf_sb_info *UDF_SB(struct super_block *sb) +{ + return sb->u.generic_sbp; +} + #define UDF_SB_FREE(X)\ {\ if (UDF_SB(X))\ @@ -39,7 +44,6 @@ UDF_SB_PARTMAPS(X) = NULL;\ }\ } -#define UDF_SB(X) (&((X)->u.udf_sb)) #define UDF_SB_ALLOC_PARTMAPS(X,Y)\ {\ diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 836aef50cded..1b4d5a5d1401 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -8,6 +8,8 @@ #include <linux/fs.h> #include <linux/config.h> #include <linux/types.h> +#include <linux/udf_fs_i.h> +#include <linux/udf_fs_sb.h> #ifndef LINUX_VERSION_CODE #include <linux/version.h> @@ -15,8 +17,6 @@ #if !defined(CONFIG_UDF_FS) && !defined(CONFIG_UDF_FS_MODULE) #define CONFIG_UDF_FS_MODULE -#include <linux/udf_fs_i.h> -#include <linux/udf_fs_sb.h> #endif #include "udfend.h" diff --git a/include/asm-ppc/siginfo.h b/include/asm-ppc/siginfo.h index 684ad91eb8d7..597b234d1b44 100644 --- a/include/asm-ppc/siginfo.h +++ b/include/asm-ppc/siginfo.h @@ -99,7 +99,6 @@ typedef struct siginfo { /* * si_code values - * Digital reserves positive values for kernel-generated signals. */ #define SI_USER 0 /* sent by kill, sigsend, raise */ #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ @@ -109,6 +108,7 @@ typedef struct siginfo { #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_TKILL -6 /* sent by tkill system call */ +#define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) diff --git a/include/asm-ppc/thread_info.h b/include/asm-ppc/thread_info.h index 0ea0afd7e48e..b98527161019 100644 --- a/include/asm-ppc/thread_info.h +++ b/include/asm-ppc/thread_info.h @@ -18,10 +18,11 @@ * If you change this, change the TI_* offsets below to match. */ struct thread_info { - struct task_struct *task; /* main task structure */ - struct exec_domain *exec_domain; /* execution domain */ - unsigned long flags; /* low level flags */ - int cpu; /* cpu we're on */ + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + int cpu; /* cpu we're on */ + int preempt_count; /* not used at present */ }; /* diff --git a/include/linux/fs.h b/include/linux/fs.h index d05052fa4461..1600f74d5410 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -648,7 +648,6 @@ struct quota_mount_options #include <linux/ext3_fs_sb.h> #include <linux/hpfs_fs_sb.h> #include <linux/ntfs_fs_sb.h> -#include <linux/iso_fs_sb.h> #include <linux/sysv_fs_sb.h> #include <linux/affs_fs_sb.h> #include <linux/ufs_fs_sb.h> @@ -657,7 +656,6 @@ struct quota_mount_options #include <linux/adfs_fs_sb.h> #include <linux/reiserfs_fs_sb.h> #include <linux/bfs_fs_sb.h> -#include <linux/udf_fs_sb.h> extern struct list_head super_blocks; extern spinlock_t sb_lock; @@ -696,7 +694,6 @@ struct super_block { struct ext3_sb_info ext3_sb; struct hpfs_sb_info hpfs_sb; struct ntfs_sb_info ntfs_sb; - struct isofs_sb_info isofs_sb; struct sysv_sb_info sysv_sb; struct affs_sb_info affs_sb; struct ufs_sb_info ufs_sb; @@ -706,7 +703,6 @@ struct super_block { struct adfs_sb_info adfs_sb; struct reiserfs_sb_info reiserfs_sb; struct bfs_sb_info bfs_sb; - struct udf_sb_info udf_sb; void *generic_sbp; } u; /* diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h index cffc0323325d..4f57c1174598 100644 --- a/include/linux/hiddev.h +++ b/include/linux/hiddev.h @@ -119,6 +119,7 @@ struct hiddev_usage_ref { __s32 value; }; +#define HID_FIELD_INDEX_NONE 0xffffffff /* * Protocol version. @@ -143,6 +144,15 @@ struct hiddev_usage_ref { #define HIDIOCGUSAGE _IOWR('H', 0x0B, struct hiddev_usage_ref) #define HIDIOCSUSAGE _IOW('H', 0x0C, struct hiddev_usage_ref) #define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref) +#define HIDIOCGFLAG _IOR('H', 0x0E, int) +#define HIDIOCSFLAG _IOW('H', 0x0F, int) + +/* + * Flags to be used in HIDIOCSFLAG + */ +#define HIDDEV_FLAG_UREF 0x1 +#define HIDDEV_FLAG_REPORT 0x2 +#define HIDDEV_FLAGS 0x3 /* To traverse the input report descriptor info for a HID device, perform the * following: @@ -179,7 +189,7 @@ struct hiddev_usage_ref { #ifdef CONFIG_USB_HIDDEV int hiddev_connect(struct hid_device *); void hiddev_disconnect(struct hid_device *); -void hiddev_hid_event(struct hid_device *, unsigned int usage, int value); +void hiddev_hid_event(struct hid_device *, struct hiddev_usage_ref *ref); int __init hiddev_init(void); void __exit hiddev_exit(void); #else diff --git a/include/linux/if_wanpipe.h b/include/linux/if_wanpipe.h index 544d818d9f73..c4cd29a162fe 100644 --- a/include/linux/if_wanpipe.h +++ b/include/linux/if_wanpipe.h @@ -122,6 +122,7 @@ struct wanpipe_opt unsigned poll_cnt; unsigned char force; /* Used to force sock release */ atomic_t packet_sent; + unsigned short num; }; #define wp_sk(__sk) ((struct wanpipe_opt *)(__sk)->protinfo) diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h index b235c3ea9f23..3520e22a2af8 100644 --- a/include/linux/iso_fs.h +++ b/include/linux/iso_fs.h @@ -160,7 +160,6 @@ struct iso_directory_record { #define ISOFS_BUFFER_SIZE(INODE) ((INODE)->i_sb->s_blocksize) #define ISOFS_BUFFER_BITS(INODE) ((INODE)->i_sb->s_blocksize_bits) -#define ISOFS_ZONE_BITS(INODE) ((INODE)->i_sb->u.isofs_sb.s_log_zone_size) #define ISOFS_SUPER_MAGIC 0x9660 @@ -171,6 +170,12 @@ struct iso_directory_record { #include <asm/byteorder.h> #include <asm/unaligned.h> #include <linux/iso_fs_i.h> +#include <linux/iso_fs_sb.h> + +static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb) +{ + return sb->u.generic_sbp; +} static inline struct iso_inode_info *ISOFS_I(struct inode *inode) { diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index 5fa94340daf9..b93dd0167679 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -38,7 +38,7 @@ MODULE_LICENSE("GPL"); static int kill_proto(const struct ip_conntrack *i, void *data) { - return (i->tuplehash[IP_CT_DIR_ORIGINAL].dst.protonum == + return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == *((u_int8_t *) data)); } diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c index 88a4e1356ed3..0a9f62073788 100644 --- a/net/wanrouter/af_wanpipe.c +++ b/net/wanrouter/af_wanpipe.c @@ -19,6 +19,7 @@ * Alan Cox. * X25 socket Author: Jonathan Naylor. * ============================================================================ +* Mar 15, 2002 Arnaldo C. Melo o Use wp_sk()->num, as it isnt anymore in sock * Apr 25, 2000 Nenad Corbic o Added the ability to send zero length packets. * Mar 13, 2000 Nenad Corbic o Added a tx buffer check via ioctl call. * Mar 06, 2000 Nenad Corbic o Fixed the corrupt sock lcn problem. @@ -164,11 +165,11 @@ static void dbg_kfree(void * v, int line) { /* List of all wanpipe sockets. */ -struct sock * wanpipe_sklist = NULL; +struct sock* wanpipe_sklist; static rwlock_t wanpipe_sklist_lock = RW_LOCK_UNLOCKED; atomic_t wanpipe_socks_nr; -static unsigned long wanpipe_tx_critical=0; +static unsigned long wanpipe_tx_critical; #if 0 /* Private wanpipe socket structures. */ @@ -187,9 +188,9 @@ struct wanpipe_opt }; #endif -static int sk_count=0; +static int sk_count; extern struct proto_ops wanpipe_ops; -static unsigned long find_free_critical=0; +static unsigned long find_free_critical; static void wanpipe_unlink_driver (struct sock *); static void wanpipe_link_driver (netdevice_t *,struct sock *sk); @@ -400,9 +401,9 @@ static int wanpipe_listen_rcv (struct sk_buff *skb, struct sock *sk) card->u.x.svc_to_dev_map[(chan->lcn%MAX_X25_LCN)] = dev; newsk->zapped=0; - newsk->num = htons(X25_PROT); + newwp->num = htons(X25_PROT); - if (wanpipe_do_bind(newsk,dev,newsk->num)){ + if (wanpipe_do_bind(newsk, dev, newwp->num)) { wanpipe_kill_sock_irq (newsk); release_device(dev); return -EINVAL; @@ -470,7 +471,7 @@ static struct sock *wanpipe_make_new(struct sock *osk) sk->socket = osk->socket; sk->priority = osk->priority; sk->protocol = osk->protocol; - sk->num = osk->num; + wp_sk(sk)->num = wp_sk(osk)->num; sk->rcvbuf = osk->rcvbuf; sk->sndbuf = osk->sndbuf; sk->debug = osk->debug; @@ -566,9 +567,11 @@ static int wanpipe_sendmsg(struct socket *sock, struct msghdr *msg, int len, if (len < sizeof(x25api_hdr_t)) return -EINVAL; + wp = wp_sk(sk); + if (saddr == NULL) { ifindex = sk->bound_dev_if; - proto = sk->num; + proto = wp->num; addr = NULL; }else{ @@ -648,7 +651,6 @@ static int wanpipe_sendmsg(struct socket *sock, struct msghdr *msg, int len, } skb_queue_tail(&sk->write_queue,skb); - wp = wp_sk(sk); atomic_inc(&wp->packet_sent); if (!(test_and_set_bit(0, &wp->timer))){ @@ -998,7 +1000,8 @@ static int wanpipe_release(struct socket *sock, struct socket *peersock) * Unhook packet receive handler. */ - if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED && sk->zapped){ + if (wp->num == htons(X25_PROT) && + sk->state != WANSOCK_DISCONNECTED && sk->zapped) { netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); wanpipe_common_t *chan; if (dev){ @@ -1206,7 +1209,8 @@ static void wanpipe_kill_sock_timer (unsigned long data) write_unlock(&wanpipe_sklist_lock); - if (sk->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED){ + if (wp_sk(sk)->num == htons(X25_PROT) && + sk->state != WANSOCK_DISCONNECTED){ netdevice_t *dev = dev_get_by_index(sk->bound_dev_if); wanpipe_common_t *chan; if (dev){ @@ -1352,6 +1356,7 @@ static void wanpipe_kill_sock_irq (struct sock *sk) static int wanpipe_do_bind(struct sock *sk, netdevice_t *dev, int protocol) { + wanpipe_opt *wp = wp_sk(sk); wanpipe_common_t *chan=NULL; int err=0; @@ -1360,7 +1365,7 @@ static int wanpipe_do_bind(struct sock *sk, netdevice_t *dev, int protocol) goto bind_unlock_exit; } - sk->num = protocol; + wp->num = protocol; if (protocol == 0){ release_device(dev); @@ -1373,7 +1378,7 @@ static int wanpipe_do_bind(struct sock *sk, netdevice_t *dev, int protocol) chan=dev->priv; sk->state = chan->state; - if (sk->num == htons(X25_PROT) && + if (wp->num == htons(X25_PROT) && sk->state != WANSOCK_DISCONNECTED && sk->state != WANSOCK_CONNECTING){ DBG_PRINTK(KERN_INFO @@ -1388,7 +1393,7 @@ static int wanpipe_do_bind(struct sock *sk, netdevice_t *dev, int protocol) sk->bound_dev_if = dev->ifindex; /* X25 Specific option */ - if (sk->num == htons(X25_PROT)) + if (wp->num == htons(X25_PROT)) wp_sk(sk)->svc = chan->svc; } else { @@ -1421,6 +1426,7 @@ static int wanpipe_bind(struct socket *sock, struct sockaddr *uaddr, int addr_le { struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; struct sock *sk=sock->sk; + wanpipe_opt *wp = wp_sk(sk); netdevice_t *dev = NULL; sdla_t *card=NULL; char name[15]; @@ -1462,7 +1468,7 @@ static int wanpipe_bind(struct socket *sock, struct sockaddr *uaddr, int addr_le return err; if (sll->sll_protocol) - sk->num = sll->sll_protocol; + wp->num = sll->sll_protocol; sk->state = WANSOCK_BIND_LISTEN; return 0; @@ -1509,7 +1515,7 @@ static int wanpipe_bind(struct socket *sock, struct sockaddr *uaddr, int addr_le return -EINVAL; } - return wanpipe_do_bind(sk, dev, sll->sll_protocol ? : sk->num); + return wanpipe_do_bind(sk, dev, sll->sll_protocol ? : wp->num); } /*============================================================ @@ -1613,7 +1619,7 @@ static int wanpipe_create(struct socket *sock, int protocol) sk->zapped=0; sk->family = PF_WANPIPE; - sk->num = protocol; + wp_sk(sk)->num = protocol; sk->state = WANSOCK_DISCONNECTED; sk->ack_backlog = 0; sk->bound_dev_if=0; @@ -1774,7 +1780,7 @@ static int wanpipe_getname(struct socket *sock, struct sockaddr *uaddr, sll->sll_family = AF_WANPIPE; sll->sll_ifindex = sk->bound_dev_if; - sll->sll_protocol = sk->num; + sll->sll_protocol = wp_sk(sk)->num; dev = dev_get_by_index(sk->bound_dev_if); if (dev) { sll->sll_hatype = dev->type; @@ -1836,7 +1842,8 @@ static int wanpipe_notifier(struct notifier_block *this, unsigned long msg, void } break; case NETDEV_UP: - if (dev->ifindex == sk->bound_dev_if && sk->num && !sk->zapped) { + if (dev->ifindex == sk->bound_dev_if && + po->num && !sk->zapped) { printk(KERN_INFO "wansock: Registering Device: %s\n", dev->name); wanpipe_link_driver(dev,sk); @@ -2242,7 +2249,7 @@ unsigned int wanpipe_poll(struct file * file, struct socket *sock, poll_table *w * where multiple packets can be pending in the socket * transmit queue */ - if (sk->num == htons(X25_PROT)){ + if (wp_sk(sk)->num == htons(X25_PROT)) { if (atomic_read(&wp_sk(sk)->packet_sent)) return mask; } @@ -2274,7 +2281,7 @@ static int wanpipe_listen(struct socket *sock, int backlog) /* This is x25 specific area if protocol doesn't * match, return error */ - if (sk->num != htons(X25_PROT)) + if (wp_sk(sk)->num != htons(X25_PROT)) return -EINVAL; if (sk->state == WANSOCK_BIND_LISTEN) { @@ -2352,7 +2359,7 @@ static int wanpipe_exec_cmd(struct sock *sk, int cmd, unsigned int flags) /* This is x25 specific area if protocol doesn't * match, return error */ - if (sk->num != htons(X25_PROT)) + if (wp->num != htons(X25_PROT)) return -EINVAL; @@ -2535,7 +2542,7 @@ static int wanpipe_accept(struct socket *sock, struct socket *newsock, int flags if (sk->state != WANSOCK_LISTEN) return -EINVAL; - if (sk->num != htons(X25_PROT)) + if (wp_sk(sk)->num != htons(X25_PROT)) return -EINVAL; add_wait_queue(sk->sleep,&wait); @@ -2628,7 +2635,7 @@ static int wanpipe_connect(struct socket *sock, struct sockaddr *uaddr, int addr netdevice_t *dev; int err; - if (sk->num != htons(X25_PROT)) + if (wp_sk(sk)->num != htons(X25_PROT)) return -EINVAL; if (sk->state == WANSOCK_CONNECTED) |
